/trunk/last_weekday_date.phps |
---|
File deleted |
/trunk/gmp_supplement.inc.phps |
---|
File deleted |
/trunk/vtor_get_contents.inc.phps |
---|
File deleted |
/trunk/htmlentities_compat.inc.php |
---|
File deleted |
/trunk/decode_jwt_token.inc.phps |
---|
File deleted |
/trunk/color_utils.inc.php |
---|
File deleted |
/trunk/ipv4_functions.inc.phps |
---|
File deleted |
/trunk/ipv6_functions.inc.phps |
---|
File deleted |
/trunk/x_509_utils.inc.phps |
---|
File deleted |
/trunk/easterdates.phps |
---|
File deleted |
\ No newline at end of file |
/trunk/VtsBrowserDownload.class.php |
---|
File deleted |
/trunk/oid_utils.inc.phps |
---|
File deleted |
/trunk/ipresolution.inc.phps |
---|
File deleted |
/trunk/SecureMailer.class.phps |
---|
File deleted |
/trunk/googlecache.inc.phps |
---|
File deleted |
/trunk/anti_xss.php |
---|
File deleted |
/trunk/ip_functions.inc.phps |
---|
File deleted |
/trunk/marschallHash.phps |
---|
File deleted |
/trunk/cookie_test.phps |
---|
File deleted |
\ No newline at end of file |
/trunk/functions_diff.inc.phps |
---|
File deleted |
/trunk/simplexml_supplement.inc.phps |
---|
File deleted |
/trunk/grep_funcs.inc.phps |
---|
File deleted |
/trunk/xml_utils.inc.phps |
---|
File deleted |
/trunk/SecureMailer.class.php |
---|
0,0 → 1,133 |
<?php |
/* |
* Secure Mailer PHP Class |
* Copyright 2009-2013 Daniel Marschall, ViaThinkSoft |
* QB_SECURE_MAIL_PARAM (C) Erich Kachel |
* Version 2013-04-14 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
// TODO: getHeaders() as single string , attachments , remove headers etc, headers as array in/out, do you also need addRawHeader()? |
class SecureMailer { |
private $headers = ''; |
// TODO: This should rather be private, but it won't work |
const endl = "\n"; // GMX doesn't like CRLF! wtf?! (tested in Postfix in Linux) |
private function QB_SECURE_MAIL_PARAM($param_ = '', $level_ = 2) { |
// Prevents eMail header injections |
// Source: http://www.erich-kachel.de/?p=26 (modified) |
/* replace until done */ |
$filtered = null; |
while (is_null($filtered) || ($param_ != $filtered)) { |
if (!is_null($filtered)) { |
$param_ = $filtered; |
} |
$filtered = preg_replace("/(Content-Transfer-Encoding:|MIME-Version:|content-type:|Subject:|to:|cc:|bcc:|from:|reply-to:)/ims", '', $param_); |
} |
unset($filtered); |
if ($level_ >= 2) { |
/* replace until done */ |
while (!isset($filtered) || ($param_ != $filtered)) { |
if (isset($filtered)) { |
$param_ = $filtered; |
} |
$filtered = preg_replace("/(%0A|\\\\r|%0D|\\\\n|%00|\\\\0|%09|\\\\t|%01|%02|%03|%04|%05|%06|%07|%08|%09|%0B|%0C|%0E|%0F|%10|%11|%12|%13)/ims", '', $param_); |
} |
} |
return $param_; |
} |
private function getHeaders() { |
return $this->headers; |
} |
private static function mail_base64_encode($text) { |
// Why 72? Seen here: http://linux.dsplabs.com.au/munpack-mime-base64-multi-part-attachment-php-perl-decode-email-pdf-p82/ |
return wordwrap(base64_encode($text), 72, self::endl, true); |
} |
private function headerLine($name, $value) { |
// Change 2011-02-09 |
// LF is OK! CRLF does lead to CR+CRLF on some systems! |
// http://bugs.php.net/bug.php?id=15841 |
// The mail() function is not talking to an SMTP server, so RFC2822 does not apply here. mail() is talking to a command line program on the local system, and it is reasonable to expect that program to require system-native line breaks. |
return $this->QB_SECURE_MAIL_PARAM($name).': '.$this->QB_SECURE_MAIL_PARAM($value)."\n"; |
} |
public function addHeader($name, $value) { |
$this->headers .= $this->headerLine($name, $value); |
} |
public static function utf8Subject($subject) { |
return '=?UTF-8?B?'.base64_encode(utf8_encode($subject)).'?='; |
} |
private function _sendMail($recipient, $subject, $message, $add_headers='') { |
return @mail( |
$this->QB_SECURE_MAIL_PARAM($recipient), |
$this->QB_SECURE_MAIL_PARAM($subject), |
$this->QB_SECURE_MAIL_PARAM($message, 1), |
$this->getHeaders().$add_headers |
); |
} |
public function sendMail($recipient, $subject, $message) { |
return $this->_sendMail($recipient, $subject, $message, ''); |
} |
// TODO: generate plain from html (strip tags), optional |
public function sendMailHTMLandPlainMultipart($to, $subject, $msg_html, $msg_plain) { |
$boundary = uniqid('np'); |
$msg_html = $this->QB_SECURE_MAIL_PARAM($msg_html, 1); |
$msg_plain = $this->QB_SECURE_MAIL_PARAM($msg_plain, 1); |
$add_headers = $this->headerLine('MIME-Version', '1.0'); |
$add_headers .= $this->headerLine('Content-Type', 'multipart/alternative; boundary="'.$boundary.'"'); |
$message = "This is a MIME encoded message."; |
$message .= self::endl; |
$message .= self::endl; |
$message .= "--" . $boundary . self::endl; |
$message .= "Content-type: text/plain; charset=utf-8".self::endl; |
$message .= "Content-Transfer-Encoding: base64".self::endl; |
$message .= self::endl; |
$message .= $this->mail_base64_encode($msg_plain); // better than wordwrap"ed-printable because of long lines (e.g. links) |
$message .= self::endl; |
$message .= self::endl; |
$message .= "--" . $boundary . self::endl; |
$message .= "Content-type: text/html; charset=utf-8".self::endl; |
$message .= "Content-Transfer-Encoding: base64".self::endl; |
$message .= self::endl; |
$message .= $this->mail_base64_encode($msg_html); |
$message .= self::endl; |
$message .= self::endl."--" . $boundary . "--"; |
return @mail( |
$this->QB_SECURE_MAIL_PARAM($to), |
$this->QB_SECURE_MAIL_PARAM($subject), |
$message, |
$this->getHeaders().$add_headers |
); |
} |
} |
/trunk/cookie_test.php |
---|
0,0 → 1,21 |
<?php |
if ($cookie_state == 1) |
{ |
if (isset($_COOKIE['TestCookie'])) |
{ |
setcookie('TestCookie', 'test', time()); |
echo 'Cookies werden unterstützt!'; |
} |
else |
{ |
echo 'Es werden keine Cookies unterstützt!'; |
} |
} |
else |
{ |
setcookie('TestCookie', 'test'); |
header('Location: '.$_SERVER['PHP_SELF'].'?cookie_state=1'); |
} |
?> |
/trunk/decode_jwt_token.inc.php |
---|
0,0 → 1,122 |
<?php |
/* |
* JWT Decoder for PHP |
* Copyright 2021 Daniel Marschall, ViaThinkSoft |
* Version 2021-05-15 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
function decode_idtoken($id_token, $verification_certs=null, $allowed_algorithms = array()) { |
// Parts taken and simplified from https://github.com/firebase/php-jwt , licensed by BSD-3-clause |
// Here is a great page for encode and decode tokens for testing: https://jwt.io/ |
$parts = explode('.', $id_token); |
if (count($parts) === 5) return false; // encrypted JWT not yet supported |
if (count($parts) !== 3) return false; |
list($header_base64, $payload_base64, $signature_base64) = $parts; |
$header_ary = json_decode(urlsafeB64Decode($header_base64),true); |
if ($header_ary['typ'] !== 'JWT') return false; |
if ($verification_certs) { |
$key = isset($header_ary['kid']) ? $verification_certs[$header_ary['kid']] : $verification_certs; |
$msg = $header_base64.'.'.$payload_base64; |
$signature = urlsafeB64Decode($signature_base64); |
$jwt_algo = $header_ary['alg']; |
// see https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ |
// https://datatracker.ietf.org/doc/html/rfc8725#section-3.1 |
if (!in_array($jwt_algo, $allowed_algorithms)) return false; |
if ($jwt_algo != 'none') { |
$php_algo = 'SHA'.substr($jwt_algo,2,3); |
switch (substr($jwt_algo,0,2)) { |
case 'ES': |
// OpenSSL expects an ASN.1 DER sequence for ES256 signatures |
$signature = signatureToDER($signature); |
if (!function_exists('openssl_verify')) break; // if OpenSSL is not installed, we just accept the JWT |
if (!openssl_verify($msg, $signature, $key, $php_algo)) return false; |
break; |
case 'RS': |
if (!function_exists('openssl_verify')) break; // if OpenSSL is not installed, we just accept the JWT |
if (!openssl_verify($msg, $signature, $key, $php_algo)) return false; |
break; |
case 'HS': |
$hash = @hash_hmac($php_algo, $msg, $key, true); |
if (!$hash) break; // if the hash algo is not available, we just accept the JWT |
if (!hash_equals($signature, $hash)) return false; |
break; |
case 'PS': |
// This feature is new and not yet available in php-jwt |
file_put_contents($msg_file = tempnam("/tmp", ""), $msg); |
file_put_contents($sig_file = tempnam("/tmp", ""), $signature); |
file_put_contents($key_file = tempnam("/tmp", ""), $key); |
$ec = -1; |
$out = array(); |
$cmd = "openssl dgst -".strtolower($php_algo)." -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -verify ".escapeshellarg($key_file)." -signature ".escapeshellarg($sig_file)." ".escapeshellarg($msg_file); |
$cmd .= (strtoupper(substr(PHP_OS,0,3)) === 'WIN') ? ' 2> NUL' : ' 2> /dev/null'; |
exec($cmd, $out, $ec); |
unlink($msg_file); |
unlink($sig_file); |
unlink($key_file); |
if (($ec !== 0) && (count($out) === 0)) break; // If OpenSSL is not found, we just accept the JWT |
if (($ec !== 0) || (strpos(implode("\n",$out),"Verified OK") === false)) return false; |
break; |
default: |
return false; |
} |
} |
} |
$payload_ary = json_decode(urlsafeB64Decode($payload_base64), true); |
$leeway = 60; // 1 Minute |
if (isset($payload_ary['nbf']) && (time()+$leeway<$payload_ary['nbf'])) return false; |
if (isset($payload_ary['exp']) && (time()-$leeway>$payload_ary['exp'])) return false; |
return $payload_ary; |
} |
function urlsafeB64Decode($input) { |
// Taken from https://github.com/firebase/php-jwt , licensed by BSD-3-clause |
$remainder = strlen($input) % 4; |
if ($remainder) { |
$padlen = 4 - $remainder; |
$input .= str_repeat('=', $padlen); |
} |
return base64_decode(strtr($input, '-_', '+/')); |
} |
function signatureToDER($sig) { |
// Taken from https://github.com/firebase/php-jwt , licensed by BSD-3-clause, modified |
// Separate the signature into r-value and s-value |
list($r, $s) = str_split($sig, (int) (strlen($sig) / 2)); |
// Trim leading zeros |
$r = ltrim($r, "\x00"); |
$s = ltrim($s, "\x00"); |
// Convert r-value and s-value from unsigned big-endian integers to signed two's complement |
if (ord($r[0]) > 0x7f) $r = "\x00" . $r; |
if (ord($s[0]) > 0x7f) $s = "\x00" . $s; |
$der_r = chr(0x00/*primitive*/ | 0x02/*INTEGER*/).chr(strlen($r)).$r; |
$der_s = chr(0x00/*primitive*/ | 0x02/*INTEGER*/).chr(strlen($s)).$s; |
$der = chr(0x20/*constructed*/ | 0x10/*SEQUENCE*/).chr(strlen($der_r.$der_s)).$der_r.$der_s; |
return $der; |
} |
/trunk/easterdates.php |
---|
0,0 → 1,101 |
<?php |
// Neujahr setzen (fester Feiertag am 1. Januar) |
// Hl. Drei Könige setzen (fester Feiertag am 6. Januar) |
// Rosenmontag berechnen (beweglicher Feiertag; 48 Tage vor Ostern) |
// Aschermittwoch berechnen (beweglicher Feiertag; 46 Tage vor Ostern) |
// Karfreitag berechnen (beweglicher Feiertag; 2 Tage vor Ostern) |
// Ostersonntag |
// Ostermontag berechnen (beweglicher Feiertag; 1 Tag nach Ostern) |
// Maifeiertag setzen (fester Feiertag am 1. Mai) |
// Christi Himmelfahrt berechnen (beweglicher Feiertag; 39 Tage nach Ostern) |
// Pfingstsonntag berechnen (beweglicher Feiertag; 49 Tage nach Ostern) |
// Pfingstmontag berechnen (beweglicher Feiertag; 50 Tage nach Ostern) |
// Fronleichnam berechnen (beweglicher Feiertag; 60 Tage nach Ostern) |
// Mariä Himmelfahrt setzen (fester Feiertag am 15. August) |
// Tag der deutschen Einheit setzen (fester Feiertag am 3. Oktober) |
// Reformationstag setzen (fester Feiertag am 31. Oktober) |
// Allerheiligen setzen (fester Feiertag am 1. November) |
// Heiligabend setzen (fester 'Feiertag' am 24. Dezember) |
// Erster Weihnachtstag setzen (fester 'Feiertag' am 25. Dezember) |
// Zweiter Weihnachtstag setzen (fester 'Feiertag' am 26. Dezember) |
// Sylvester setzen (fester 'Feiertag' am 31. Dezember) |
function ostersonntag($year) { |
$J = date ("Y", mktime(0, 0, 0, 1, 1, $year)); |
$a = $J % 19; |
$b = $J % 4; |
$c = $J % 7; |
$m = number_format (8 * number_format ($J / 100) + 13) / 25 - 2; |
$s = number_format ($J / 100 ) - number_format ($J / 400) - 2; |
$M = (15 + $s - $m) % 30; |
$N = (6 + $s) % 7; |
$d = ($M + 19 * $a) % 30; |
if ($d == 29) { |
$D = 28; |
} else if ($d == 28 and $a >= 11) { |
$D = 27; |
} else { |
$D = $d; |
} |
$e = (2 * $b + 4 * $c + 6 * $D + $N) % 7; |
$easter = mktime (0, 0, 0, 3, 21, $J) + (($D + $e + 1) * 86400); |
return $easter; |
} |
function get_easter_depending_days($year) { |
$es = ostersonntag($year); |
$sd = 24 * 60 * 60; |
$days = array( |
'rose_monday' => $es - (48 * $sd), |
'shrove_tuesday' => $es - (47 * $sd), |
'ash_wednesday' => $es - (46 * $sd), |
'palm_sunday' => $es - (7 * $sd), |
'good_friday' => $es - (2 * $sd), |
'easter_sunday' => $es, |
'easter_monday' => $es + (1 * $sd), |
'low_sunday' => $es + (7 * $sd), |
'ascension_day' => $es + (39 * $sd), |
'whit_sunday' => $es + (49 * $sd), |
'whit_monday' => $es + (50 * $sd), |
'corpus_christi' => $es + (60 * $sd) |
); |
return($days); |
} |
$days = get_easter_depending_days(date("Y")); |
echo "Rosemontag: ", |
date ("d.m.Y", $days['rose_monday']), "<br>"; |
echo "Fastnachtsdienstag: ", |
date ("d.m.Y", $days['shrove_tuesday']), "<br>"; |
echo "Aschermittwoch: ", |
date ("d.m.Y", $days['ash_wednesday']), "<br>"; |
echo "Palmsonntag: ", |
date ("d.m.Y", $days['palm_sunday']), "<br>"; |
echo "Karfreitag: ", |
date ("d.m.Y", $days['good_friday']), "<br>"; |
echo "Ostersonntag: ", |
date ("d.m.Y", $days['easter_sunday']), "<br>"; |
echo "Ostermontag: ", |
date ("d.m.Y", $days['easter_monday']), "<br>"; |
echo "Weißer Sonntag: ", |
date ("d.m.Y", $days['low_sunday']), "<br>"; |
echo "Christi Himmelfahrt: ", |
date ("d.m.Y", $days['ascension_day']), "<br>"; |
echo "Pfingstsonntag: ", |
date ("d.m.Y", $days['whit_sunday']), "<br>"; |
echo "Pfingstmontag: ", |
date ("d.m.Y", $days['whit_monday']), "<br>"; |
echo "Fronleichnam: ", |
date ("d.m.Y", $days['corpus_christi']), "<br>"; |
?> |
/trunk/functions_diff.inc.php |
---|
0,0 → 1,84 |
<?php |
/* |
* PHP diff functions |
* Copyright 2012 Daniel Marschall, ViaThinkSoft |
* Revision 2012-11-16 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
define('TABS_WS', 6); |
function output_unified_diff($fileA, $fileB, $num_lines=3) { |
$fileA = realpath($fileA); |
$fileB = realpath($fileB); |
ob_start(); |
system("diff -wbB --ignore-blank-lines -U ".escapeshellarg($num_lines)." ".escapeshellarg($fileA)." ".escapeshellarg($fileB)); |
$cont = ob_get_contents(); |
ob_end_clean(); |
$ary = explode("\n", $cont); |
foreach ($ary as $n => $a) { |
$c = substr($a, 0, 1); |
$c2 = substr($a, 0, 2); |
$c3 = substr($a, 0, 3); |
echo '<code>'; |
if (($c3 == '+++') || ($c3 == '---')) { |
echo '<b><font color="gray">'.html_format($a).'</font></b>'; |
} else if ($c2 == '@@') { |
echo '<b><font color="blue">'.html_format($a).'</font></b>'; |
} else if ($c == '+') { |
echo '<font color="green">'.html_format($a).'</font>'; |
} else if ($c == '-') { |
echo '<font color="red">'.html_format($a).'</font>'; |
} else { |
echo html_format($a); |
} |
echo "</code><br />\n"; |
} |
} |
function output_diff($fileA, $fileB, $num_lines=3) { |
$fileA = realpath($fileA); |
$fileB = realpath($fileB); |
ob_start(); |
system("diff -wbB --ignore-blank-lines ".escapeshellarg($fileA)." ".escapeshellarg($fileB)); |
$cont = ob_get_contents(); |
ob_end_clean(); |
$ary = explode("\n", $cont); |
foreach ($ary as $n => $a) { |
$c = substr($a, 0, 1); |
echo '<code>'; |
if (($c == '>') || ($c == '<')) { |
echo '<b><font color="blue">'.html_format($c).'</font></b>'.html_format(substr($a, 1)); |
} else { |
echo '<b><font color="blue">'.html_format($a).'</font></b>'; |
} |
echo "</code><br />\n"; |
} |
} |
function html_format($x) { |
$x = htmlentities($x); |
$x = str_replace("\t", str_repeat(' ', TABS_WS), $x); |
$x = str_replace(' ', ' ', $x); |
return $x; |
} |
?> |
/trunk/gmp_supplement.inc.php |
---|
0,0 → 1,829 |
<?php |
/* |
* PHP GMP-Supplement implemented using BCMath |
* Copyright 2020-2021 Daniel Marschall, ViaThinkSoft |
* Version 2021-05-21 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
if (function_exists('bcadd')) { |
// ----------------- Implementation of GMP functions using BCMath ----------------- |
if (!function_exists('gmp_init') ) { |
define('GMP_ROUND_ZERO', 0); |
define('GMP_ROUND_PLUSINF', 1); |
define('GMP_ROUND_MINUSINF', 2); |
define('GMP_MSW_FIRST', 1); |
define('GMP_LSW_FIRST', 2); |
define('GMP_LITTLE_ENDIAN', 4); |
define('GMP_BIG_ENDIAN', 8); |
define('GMP_NATIVE_ENDIAN', 16); |
define('GMP_VERSION', '6.0.0'); |
// gmp_abs ( GMP $a ) : GMP |
// Absolute value |
function gmp_abs($a) { |
bcscale(0); |
if (bccomp($a, "0") == 1) { |
return $a; |
} else { |
return bcmul($a, "-1"); |
} |
} |
// gmp_add ( GMP $a , GMP $b ) : GMP |
// Add numbers |
function gmp_add($a, $b) { |
bcscale(0); |
// bcadd ( string $left_operand , string $right_operand [, int $scale = 0 ] ) : string |
return bcadd($a, $b); |
} |
// gmp_and ( GMP $a , GMP $b ) : GMP |
// Bitwise AND |
function gmp_and($a, $b) { |
bcscale(0); |
// Convert $a and $b to a binary string |
$ab = bc_dec2bin($a); |
$bb = bc_dec2bin($b); |
$length = max(strlen($ab), strlen($bb)); |
$ab = str_pad($ab, $length, "0", STR_PAD_LEFT); |
$bb = str_pad($bb, $length, "0", STR_PAD_LEFT); |
// Do the bitwise binary operation |
$cb = ''; |
for ($i=0; $i<$length; $i++) { |
$cb .= (($ab[$i] == 1) and ($bb[$i] == 1)) ? '1' : '0'; |
} |
// Convert back to a decimal number |
return bc_bin2dec($cb); |
} |
// gmp_binomial ( mixed $n , int $k ) : GMP |
// Calculates binomial coefficient |
function gmp_binomial($n, $k) { |
bcscale(0); |
throw new Exception("gmp_binomial() NOT IMPLEMENTED"); |
} |
// gmp_clrbit ( GMP $a , int $index ) : void |
// Clear bit |
function gmp_clrbit(&$a, $index) { |
bcscale(0); |
gmp_setbit($a, $index, false); |
} |
// gmp_cmp ( GMP $a , GMP $b ) : int |
// Compare numbers |
function gmp_cmp($a, $b) { |
bcscale(0); |
// bccomp ( string $left_operand , string $right_operand [, int $scale = 0 ] ) : int |
return bccomp($a, $b); |
} |
// gmp_com ( GMP $a ) : GMP |
// Calculates one's complement |
function gmp_com($a) { |
bcscale(0); |
// Convert $a and $b to a binary string |
$ab = bc_dec2bin($a); |
// Swap every bit |
for ($i=0; $i<strlen($ab); $i++) { |
$ab[$i] = ($ab[$i] == '1' ? '0' : '1'); |
} |
// Convert back to a decimal number |
return bc_bin2dec($ab); |
} |
// gmp_div_q ( GMP $a , GMP $b [, int $round = GMP_ROUND_ZERO ] ) : GMP |
// Divide numbers |
function gmp_div_q($a, $b, $round = GMP_ROUND_ZERO/*$round not implemented*/) { |
bcscale(0); |
// bcdiv ( string $dividend , string $divisor [, int $scale = 0 ] ) : string |
return bcdiv($a, $b); |
} |
// Divide numbers and get quotient and remainder |
// gmp_div_qr ( GMP $n , GMP $d [, int $round = GMP_ROUND_ZERO ] ) : array |
function gmp_div_qr($n, $d, $round = GMP_ROUND_ZERO/*$round not implemented*/) { |
bcscale(0); |
return array( |
gmp_div_q($n, $d, $round), |
gmp_div_r($n, $d, $round) |
); |
} |
// Remainder of the division of numbers |
// gmp_div_r ( GMP $n , GMP $d [, int $round = GMP_ROUND_ZERO ] ) : GMP |
function gmp_div_r($n, $d, $round = GMP_ROUND_ZERO/*$round not implemented*/) { |
bcscale(0); |
// The remainder operator can be used with negative integers. The rule is: |
// - Perform the operation as if both operands were positive. |
// - If the left operand is negative, then make the result negative. |
// - If the left operand is positive, then make the result positive. |
// - Ignore the sign of the right operand in all cases. |
$r = bcmod($n, $d); |
if (bccomp($n, "0") < 0) $r = bcmul($r, "-1"); |
return $r; |
} |
// gmp_div ( GMP $a , GMP $b [, int $round = GMP_ROUND_ZERO ] ) : GMP |
// Divide numbers |
function gmp_div($a, $b, $round = GMP_ROUND_ZERO/*$round not implemented*/) { |
bcscale(0); |
return gmp_div_q($a, $b, $round); // Alias von gmp_div_q |
} |
// gmp_divexact ( GMP $n , GMP $d ) : GMP |
// Exact division of numbers |
function gmp_divexact($n, $d) { |
bcscale(0); |
return bcdiv($n, $d); |
} |
// gmp_export ( GMP $gmpnumber [, int $word_size = 1 [, int $options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN ]] ) : string |
// Export to a binary string |
function gmp_export($gmpnumber, $word_size = 1, $options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN) { |
if ($word_size != 1) throw new Exception("Word size != 1 not implemented"); |
if ($options != GMP_MSW_FIRST | GMP_NATIVE_ENDIAN) throw new Exception("Different options not implemented"); |
bcscale(0); |
$gmpnumber = bcmul($gmpnumber,"1"); // normalize |
return gmp_init(bin2hex($gmpnumber), 16); |
} |
// gmp_fact ( mixed $a ) : GMP |
// Factorial |
function gmp_fact($a) { |
bcscale(0); |
return bcfact($a); |
} |
// gmp_gcd ( GMP $a , GMP $b ) : GMP |
// Calculate GCD |
function gmp_gcd($a, $b) { |
bcscale(0); |
return gmp_gcdext($a, $b)['g']; |
} |
// gmp_gcdext ( GMP $a , GMP $b ) : array |
// Calculate GCD and multipliers |
function gmp_gcdext($a, $b) { |
bcscale(0); |
// Source: https://github.com/phpseclib/phpseclib/blob/master/phpseclib/Math/BigInteger/Engines/BCMath.php#L285 |
// modified to make it fit here and to be compatible with gmp_gcdext |
$s = '1'; |
$t = '0'; |
$s_ = '0'; |
$t_ = '1'; |
while (bccomp($b, '0', 0) != 0) { |
$q = bcdiv($a, $b, 0); |
$temp = $a; |
$a = $b; |
$b = bcsub($temp, bcmul($b, $q, 0), 0); |
$temp = $s; |
$s = $s_; |
$s_ = bcsub($temp, bcmul($s, $q, 0), 0); |
$temp = $t; |
$t = $t_; |
$t_ = bcsub($temp, bcmul($t, $q, 0), 0); |
} |
return [ |
'g' => /*$this->normalize*/($a), |
's' => /*$this->normalize*/($s), |
't' => /*$this->normalize*/($t) |
]; |
} |
// gmp_hamdist ( GMP $a , GMP $b ) : int |
// Hamming distance |
function gmp_hamdist($a, $b) { |
bcscale(0); |
throw new Exception("gmp_hamdist() NOT IMPLEMENTED"); |
} |
// gmp_import ( string $data [, int $word_size = 1 [, int $options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN ]] ) : GMP |
// Import from a binary string |
function gmp_import($data, $word_size=1, $options=GMP_MSW_FIRST | GMP_NATIVE_ENDIAN) { |
bcscale(0); |
if ($word_size != 1) throw new Exception("Word size != 1 not implemented"); |
if ($options != GMP_MSW_FIRST | GMP_NATIVE_ENDIAN) throw new Exception("Different options not implemented"); |
return gmp_init(hex2bin(gmp_strval(gmp_init($data), 16))); |
} |
// gmp_init ( mixed $number [, int $base = 0 ] ) : GMP |
// Create GMP number |
function gmp_init($number, $base=0) { |
bcscale(0); |
if ($base == 0) { |
// If base is 0 (default value), the actual base is determined from the leading characters: |
// if the first two characters are 0x or 0X, hexadecimal is assumed, |
// otherwise if the first character is "0", octal is assumed, |
// otherwise decimal is assumed. |
if (strtoupper(substr($number, 0, 2)) == '0X') { |
$base = 16; |
} else if (strtoupper(substr($number, 0, 1)) == '0') { |
$base = 8; |
} else { |
$base = 10; |
} |
} |
if ($base == 10) { |
return $number; |
} else { |
return base_convert_bigint($number, $base, 10); |
} |
} |
// gmp_intval ( GMP $gmpnumber ) : int |
// Convert GMP number to integer |
function gmp_intval($gmpnumber) { |
bcscale(0); |
return (int)$gmpnumber; |
} |
// gmp_invert ( GMP $a , GMP $b ) : GMP |
// Inverse by modulo |
function gmp_invert($a, $b) { |
bcscale(0); |
// Source: https://github.com/CityOfZion/neo-php/blob/master/src/Crypto/NumberTheory.php#L246 |
while (bccomp($a, '0')==-1) { |
$a=bcadd($b, $a); |
} |
while (bccomp($b, $a)==-1) { |
$a=bcmod($a, $b); |
} |
$c=$a; |
$d=$b; |
$uc=1; |
$vc=0; |
$ud=0; |
$vd=1; |
while (bccomp($c, '0')!=0) { |
$temp1=$c; |
$q=bcdiv($d, $c, 0); |
$c=bcmod($d, $c); |
$d=$temp1; |
$temp2=$uc; |
$temp3=$vc; |
$uc=bcsub($ud, bcmul($q, $uc)); |
$vc=bcsub($vd, bcmul($q, $vc)); |
$ud=$temp2; |
$vd=$temp3; |
} |
$result=''; |
if (bccomp($d, '1')==0) { |
if (bccomp($ud, '0')==1) { |
$result=$ud; |
} else { |
$result=bcadd($ud, $b); |
} |
} else { |
throw new ErrorException("ERROR: $a and $b are NOT relatively prime."); |
} |
return $result; |
} |
// gmp_jacobi ( GMP $a , GMP $p ) : int |
// Jacobi symbol |
function gmp_jacobi($a, $p) { |
bcscale(0); |
// Source: https://github.com/CityOfZion/neo-php/blob/master/src/Crypto/NumberTheory.php#L136 |
if ($p>=3 && $p%2==1) { |
$a = bcmod($a, $p); |
if ($a == '0') return '0'; |
if ($a == '1') return '1'; |
$a1 = $a; |
$e = 0; |
while (bcmod($a1, '2') == '0') { |
$a1 = bcdiv($a1, '2'); |
$e = bcadd($e, '1'); |
} |
$s = (bcmod($e, '2')=='0' || bcmod($p, '8')=='1' || bcmod($p, '8')=='7') ? '1' : '-1'; |
if ($a1 == '1') return $s; |
if (bcmod($p, '4')=='3' && bcmod($a1, '4')=='3') $s = -$s; |
return bcmul($s, (string)gmp_jacobi(bcmod($p, $a1), $a1)); |
} else { |
return false; |
} |
} |
// gmp_kronecker ( mixed $a , mixed $b ) : int |
// Kronecker symbol |
function gmp_kronecker($a, $b) { |
bcscale(0); |
throw new Exception("gmp_kronecker() NOT IMPLEMENTED"); |
} |
// gmp_lcm ( mixed $a , mixed $b ) : GMP |
// Calculate LCM |
function gmp_lcm($a, $b) { |
bcscale(0); |
if ((bccomp($a,'0')==0) && (bccomp($b,'0')==0)) { |
return '0'; |
} else { |
return gmp_div(gmp_abs(gmp_mul($a,$b)), gmp_gcd($a,$b)); |
} |
} |
// gmp_legendre ( GMP $a , GMP $p ) : int |
// Legendre symbol |
function gmp_legendre($a, $p) { |
bcscale(0); |
throw new Exception("gmp_legendre() NOT IMPLEMENTED"); |
} |
// gmp_mod ( GMP $n , GMP $d ) : GMP |
// Modulo operation |
function gmp_mod($n, $d) { |
bcscale(0); |
// bcmod ( string $dividend , string $divisor [, int $scale = 0 ] ) : string |
return bcmod($n, $d); |
} |
// gmp_mul ( GMP $a , GMP $b ) : GMP |
// Multiply numbers |
function gmp_mul($a, $b) { |
bcscale(0); |
// bcmul ( string $left_operand , string $right_operand [, int $scale = 0 ] ) : string |
return bcmul($a, $b); |
} |
// gmp_neg ( GMP $a ) : GMP |
// Negate number |
function gmp_neg($a) { |
bcscale(0); |
return bcmul($a, "-1"); |
} |
// gmp_nextprime ( int $a ) : GMP |
// Find next prime number |
function gmp_nextprime($a) { |
bcscale(0); |
// Source: https://github.com/CityOfZion/neo-php/blob/master/src/Crypto/NumberTheory.php#L692 |
if (bccomp($a, '2') == '-1') { |
return '2'; |
} |
$result = gmp_or(bcadd($a, '1'), '1'); |
while (!gmp_prob_prime($result)) { |
$result = bcadd($result, '2'); |
} |
return $result; |
} |
// gmp_or ( GMP $a , GMP $b ) : GMP |
// Bitwise OR |
function gmp_or($a, $b) { |
bcscale(0); |
// Convert $a and $b to a binary string |
$ab = bc_dec2bin($a); |
$bb = bc_dec2bin($b); |
$length = max(strlen($ab), strlen($bb)); |
$ab = str_pad($ab, $length, "0", STR_PAD_LEFT); |
$bb = str_pad($bb, $length, "0", STR_PAD_LEFT); |
// Do the bitwise binary operation |
$cb = ''; |
for ($i=0; $i<$length; $i++) { |
$cb .= (($ab[$i] == 1) or ($bb[$i] == 1)) ? '1' : '0'; |
} |
// Convert back to a decimal number |
return bc_bin2dec($cb); |
} |
// gmp_perfect_power ( mixed $a ) : bool |
// Perfect power check |
function gmp_perfect_power($a) { |
bcscale(0); |
throw new Exception("gmp_perfect_power() NOT IMPLEMENTED"); |
} |
// gmp_perfect_square ( GMP $a ) : bool |
// Perfect square check |
function gmp_perfect_square($a) { |
bcscale(0); |
throw new Exception("gmp_perfect_square() NOT IMPLEMENTED"); |
} |
// gmp_popcount ( GMP $a ) : int |
// Population count |
function gmp_popcount($a) { |
bcscale(0); |
$ab = bc_dec2bin($a); |
return substr_count($ab, '1'); |
} |
// gmp_pow ( GMP $base , int $exp ) : GMP |
// Raise number into power |
function gmp_pow($base, $exp) { |
bcscale(0); |
// bcpow ( string $base , string $exponent [, int $scale = 0 ] ) : string |
return bcpow($base, $exp); |
} |
// gmp_powm ( GMP $base , GMP $exp , GMP $mod ) : GMP |
// Raise number into power with modulo |
function gmp_powm($base, $exp, $mod) { |
bcscale(0); |
// bcpowmod ( string $base , string $exponent , string $modulus [, int $scale = 0 ] ) : string |
return bcpowmod($base, $exp, $mod); |
} |
// gmp_prob_prime ( GMP $a [, int $reps = 10 ] ) : int |
// Check if number is "probably prime" |
function gmp_prob_prime($a, $reps=10) { |
bcscale(0); |
// Source: https://github.com/CityOfZion/neo-php/blob/master/src/Crypto/NumberTheory.php#L655 |
$t = 40; |
$k = 0; |
$m = bcsub($reps, '1'); |
while (bcmod($m, '2') == '0') { |
$k = bcadd($k, '1'); |
$m = bcdiv($m, '2'); |
} |
for ($i=0; $i<$t; $i++) { |
$a = bcrand('1', bcsub($reps, '1')); |
if ($m < 0) { |
return new ErrorException("Negative exponents ($m) not allowed"); |
} else { |
$b0 = bcpowmod($a, $m, $reps); |
} |
if ($b0!=1 && $b0!=bcsub($reps, '1')) { |
$j = 1; |
while ($j<=$k-1 && $b0!=bcsub($reps, '1')) { |
$b0 = bcpowmod($b0, '2', $reps); |
if ($b0 == 1) { |
return false; |
} |
$j++; |
} |
if ($b0 != bcsub($reps, '1')) { |
return false; |
} |
} |
} |
return true; |
} |
// gmp_random_bits ( int $bits ) : GMP |
// Random number |
function gmp_random_bits($bits) { |
bcscale(0); |
$min = 0; |
$max = bcsub(bcpow('2', $bits), '1'); |
return bcrand($min, $max); |
} |
// gmp_random_range ( GMP $min , GMP $max ) : GMP |
// Random number |
function gmp_random_range($min, $max) { |
bcscale(0); |
return bcrand($min, $max); |
} |
// gmp_random_seed ( mixed $seed ) : void |
// Sets the RNG seed |
function gmp_random_seed($seed) { |
bcscale(0); |
bcrand_seed($seed); |
} |
// gmp_random ([ int $limiter = 20 ] ) : GMP |
// Random number (deprecated) |
function gmp_random($limiter=20) { |
bcscale(0); |
throw new Exception("gmp_random() is deprecated! Please use gmp_random_bits() or gmp_random_range() instead."); |
} |
// gmp_root ( GMP $a , int $nth ) : GMP |
// Take the integer part of nth root |
function gmp_root($a, $nth) { |
bcscale(0); |
throw new Exception("gmp_root() NOT IMPLEMENTED"); |
} |
// gmp_rootrem ( GMP $a , int $nth ) : array |
// Take the integer part and remainder of nth root |
function gmp_rootrem($a, $nth) { |
bcscale(0); |
throw new Exception("gmp_rootrem() NOT IMPLEMENTED"); |
} |
// gmp_scan0 ( GMP $a , int $start ) : int |
// Scan for 0 |
function gmp_scan0($a, $start) { |
bcscale(0); |
$ab = bc_dec2bin($a); |
if ($start < 0) throw new Exception("Starting index must be greater than or equal to zero"); |
if ($start >= strlen($ab)) return $start; |
for ($i=$start; $i<strlen($ab); $i++) { |
if ($ab[strlen($ab)-1-$i] == '0') { |
return $i; |
} |
} |
return false; |
} |
// gmp_scan1 ( GMP $a , int $start ) : int |
// Scan for 1 |
function gmp_scan1($a, $start) { |
bcscale(0); |
$ab = bc_dec2bin($a); |
if ($start < 0) throw new Exception("Starting index must be greater than or equal to zero"); |
if ($start >= strlen($ab)) return -1; |
for ($i=$start; $i<strlen($ab); $i++) { |
if ($ab[strlen($ab)-1-$i] == '1') { |
return $i; |
} |
} |
return false; |
} |
// gmp_setbit ( GMP $a , int $index [, bool $bit_on = TRUE ] ) : void |
// Set bit |
function gmp_setbit(&$a, $index, $bit_on=TRUE) { |
bcscale(0); |
$ab = bc_dec2bin($a); |
if ($index < 0) throw new Exception("Invalid index"); |
if ($index >= strlen($ab)) { |
$ab = str_pad($ab, $index+1, '0', STR_PAD_LEFT); |
} |
$ab[strlen($ab)-1-$index] = $bit_on ? '1' : '0'; |
$a = bc_bin2dec($ab); |
} |
// gmp_sign ( GMP $a ) : int |
// Sign of number |
function gmp_sign($a) { |
bcscale(0); |
return bccomp($a, "0"); |
} |
// gmp_sqrt ( GMP $a ) : GMP |
// Calculate square root |
function gmp_sqrt($a) { |
bcscale(0); |
// bcsqrt ( string $operand [, int $scale = 0 ] ) : string |
return bcsqrt($a); |
} |
// gmp_sqrtrem ( GMP $a ) : array |
// Square root with remainder |
function gmp_sqrtrem($a) { |
bcscale(0); |
throw new Exception("gmp_sqrtrem() NOT IMPLEMENTED"); |
} |
// gmp_strval ( GMP $gmpnumber [, int $base = 10 ] ) : string |
// Convert GMP number to string |
function gmp_strval($gmpnumber, $base=10) { |
bcscale(0); |
if ($base == 10) { |
return $gmpnumber; |
} else { |
return base_convert_bigint($gmpnumber, 10, $base); |
} |
} |
// gmp_sub ( GMP $a , GMP $b ) : GMP |
// Subtract numbers |
function gmp_sub($a, $b) { |
bcscale(0); |
// bcsub ( string $left_operand , string $right_operand [, int $scale = 0 ] ) : string |
return bcsub($a, $b); |
} |
// gmp_testbit ( GMP $a , int $index ) : bool |
// Tests if a bit is set |
function gmp_testbit($a, $index) { |
bcscale(0); |
$ab = bc_dec2bin($a); |
if ($index < 0) throw new Exception("Invalid index"); |
if ($index >= strlen($ab)) return ('0' == '1'); |
return $ab[strlen($ab)-1-$index] == '1'; |
} |
// gmp_xor ( GMP $a , GMP $b ) : GMP |
// Bitwise XOR |
function gmp_xor($a, $b) { |
bcscale(0); |
// Convert $a and $b to a binary string |
$ab = bc_dec2bin($a); |
$bb = bc_dec2bin($b); |
$length = max(strlen($ab), strlen($bb)); |
$ab = str_pad($ab, $length, "0", STR_PAD_LEFT); |
$bb = str_pad($bb, $length, "0", STR_PAD_LEFT); |
// Do the bitwise binary operation |
$cb = ''; |
for ($i=0; $i<$length; $i++) { |
$cb .= (($ab[$i] == 1) xor ($bb[$i] == 1)) ? '1' : '0'; |
} |
// Convert back to a decimal number |
return bc_bin2dec($cb); |
} |
} |
// ----------------- Helper functions ----------------- |
function base_convert_bigint($numstring, $frombase, $tobase) { |
$frombase_str = ''; |
for ($i=0; $i<$frombase; $i++) { |
$frombase_str .= strtoupper(base_convert((string)$i, 10, 36)); |
} |
$tobase_str = ''; |
for ($i=0; $i<$tobase; $i++) { |
$tobase_str .= strtoupper(base_convert((string)$i, 10, 36)); |
} |
$length = strlen($numstring); |
$result = ''; |
$number = array(); |
for ($i = 0; $i < $length; $i++) { |
$number[$i] = stripos($frombase_str, $numstring[$i]); |
} |
do { // Loop until whole number is converted |
$divide = 0; |
$newlen = 0; |
for ($i = 0; $i < $length; $i++) { // Perform division manually (which is why this works with big numbers) |
$divide = $divide * $frombase + $number[$i]; |
if ($divide >= $tobase) { |
$number[$newlen++] = (int)($divide / $tobase); |
$divide = $divide % $tobase; |
} else if ($newlen > 0) { |
$number[$newlen++] = 0; |
} |
} |
$length = $newlen; |
$result = $tobase_str[$divide] . $result; // Divide is basically $numstring % $tobase (i.e. the new character) |
} |
while ($newlen != 0); |
return $result; |
} |
function bc_dec2bin($decimal_i) { |
// https://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ |
bcscale(0); |
$binary_i = ''; |
do { |
$binary_i = bcmod($decimal_i,'2') . $binary_i; |
$decimal_i = bcdiv($decimal_i,'2'); |
} while (bccomp($decimal_i,'0')); |
return $binary_i; |
} |
function bc_bin2dec($binary_i) { |
// https://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ |
bcscale(0); |
$decimal_i = '0'; |
for ($i = 0; $i < strlen($binary_i); $i++) { |
$decimal_i = bcmul($decimal_i,'2'); |
$decimal_i = bcadd($decimal_i,$binary_i[$i]); |
} |
return $decimal_i; |
} |
// ----------------- New functions ----------------- |
// Newly added: gmp_not / bcnot |
function bcnot($a) { |
bcscale(0); |
// Convert $a to a binary string |
$ab = bc_dec2bin($a); |
$length = strlen($ab); |
// Do the bitwise binary operation |
$cb = ''; |
for ($i=0; $i<$length; $i++) { |
$cb .= ($ab[$i] == 1) ? '0' : '1'; |
} |
// Convert back to a decimal number |
return bc_bin2dec($cb); |
} |
function gmp_not($a) { |
bcscale(0); |
return bcnot($a); |
} |
// Newly added: bcshiftl / gmp_shiftl |
function bcshiftl($num, $bits) { |
bcscale(0); |
return bcmul($num, bcpow('2', $bits)); |
} |
function gmp_shiftl($num, $bits) { |
bcscale(0); |
return bcshiftl($num, $bits); |
} |
// Newly added: bcshiftr / gmp_shiftr |
function bcshiftr($num, $bits) { |
bcscale(0); |
return bcdiv($num, bcpow('2', $bits)); |
} |
function gmp_shiftr($num, $bits) { |
bcscale(0); |
return bcshiftr($num, $bits); |
} |
// Newly added: bcfact (used by gmp_fact) |
function bcfact($a) { |
bcscale(0); |
// Source: https://www.php.net/manual/de/book.bc.php#116510 |
if (!filter_var($a, FILTER_VALIDATE_INT) || $a <= 0) { |
throw new InvalidArgumentException(sprintf('Argument must be natural number, "%s" given.', $a)); |
} |
for ($result = '1'; $a > 0; $a--) { |
$result = bcmul($result, $a); |
} |
return $result; |
} |
// Newly added (used by gmp_prob_prime, gmp_random_range and gmp_random_bits) |
function bcrand($min, $max = false) { |
bcscale(0); |
// Source: https://github.com/CityOfZion/neo-php/blob/master/src/Crypto/BCMathUtils.php#L7 |
// Fixed: https://github.com/CityOfZion/neo-php/issues/16 |
if (!$max) { |
$max = $min; |
$min = 0; |
} |
return bcadd(bcmul(bcdiv((string)mt_rand(), (string)mt_getrandmax(), strlen($max)), bcsub(bcadd($max, '1'), $min)), $min); |
} |
// Newly added (used by gmp_random_seed) |
function bcrand_seed($seed) { |
bcscale(0); |
mt_srand($seed); |
} |
} |
/trunk/googlecache.inc.php |
---|
0,0 → 1,39 |
<?php |
/* |
* Google GetCache |
* Copyright 2015 Daniel Marschall, ViaThinkSoft |
* Version 2015-06-26 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
function google_getcache($url) { |
$options = array( |
'http'=>array( |
'method'=>"GET", |
'header'=>"Accept-language: en\r\n" . |
"Cookie: foo=bar\r\n" . // check function.stream-context-create on php.net |
"User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" |
) |
); |
$context = stream_context_create($options); |
$url = 'https://www.google.de/search?q='.urlencode($url); |
$cont = file_get_contents($url, false, $context); |
preg_match_all('@(http://webcache.googleusercontent.com/.+)"@ismU', $cont, $m); |
if (!isset($m[1][0])) return false; |
$url = urldecode($m[1][0]); |
return file_get_contents($url, false, $context); |
} |
/trunk/grep_funcs.inc.php |
---|
0,0 → 1,43 |
<?php |
/* |
* Grep functions for PHP |
* Copyright 2012-2013 Daniel Marschall, ViaThinkSoft |
* Version 2013-03-08 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
# TODO: if console available, use it |
// "grep" |
function grep(&$array, $substr) { |
if (!is_array($array)) return false; |
$ret = array(); |
foreach ($array as &$a) { |
if (strpos($a, $substr) !== false) $ret[] = $a; |
} |
return $ret; |
} |
// "grep -v" |
function antigrep(&$array, $substr) { |
if (!is_array($array)) return false; |
$ret = array(); |
foreach ($array as &$a) { |
if (strpos($a, $substr) === false) $ret[] = $a; |
} |
return $ret; |
} |
?> |
/trunk/ip_functions.inc.php |
---|
0,0 → 1,61 |
<?php |
/* |
* IP functions |
* Copyright 2015 Daniel Marschall, ViaThinkSoft |
* Version 2015-10-27 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
function get_real_ip() { |
/* Eindeutige IP Adresse erhalten, auch bei Proxies und (neu:) von SSH connections im CLI modus */ |
// http://lists.phpbar.de/pipermail/php/Week-of-Mon-20040322/007749.html |
// Modificated by VTS |
// Version: 2015-10-27 |
// TODO: ipv6 |
if (isset($_SERVER['SSH_CLIENT'])) { $ary = explode(' ', $_SERVER['SSH_CLIENT']); return $ary[0]; } |
if (isset($_SERVER['SSH_CONNECTION'])) { $ary = explode(' ', $_SERVER['SSH_CONNECTION']); return $ary[0]; } |
$client_ip = (isset($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : ''; |
// It is not secure to use these, since they are not validated: http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ |
// $x_forwarded_for = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; |
$x_forwarded_for = ''; |
$remote_addr = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : ''; |
if (!empty($client_ip)) { |
$ip_expl = explode('.', $client_ip); |
$referer = explode('.', $remote_addr); |
if ($referer[0] != $ip_expl[0]) { |
$ip = array_reverse($ip_expl); |
$return = implode('.', $ip); |
} else { |
$return = $client_ip; |
} |
} else if (!empty($x_forwarded_for)) { |
if (strstr($x_forwarded_for, ',')) { |
$ip_expl = explode(',', $x_forwarded_for); |
$return = end($ip_expl); |
} else { |
$return = $x_forwarded_for; |
} |
} else { |
$return = $remote_addr; |
} |
unset ($client_ip, $x_forwarded_for, $remote_addr, $ip_expl); |
return $return; |
} |
/trunk/ipresolution.inc.php |
---|
0,0 → 1,105 |
<?php |
/* |
* IP resolution functions |
* Copyright 2012 Daniel Marschall, ViaThinkSoft |
* Version 2012-02-02 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
/* -- Testcases -- |
print_r(gethostbynamel6('example.com')); |
print_r(gethostbynamel6('ipv6.google.com')); |
print_r(gethostbynamel6('google.de')); |
print_r(gethostbynamel6('ipv6.google.de')); |
print_r(gethostbynamel6('abc')); |
print_r(gethostbynamel6('111.111.111.111')); |
print_r(gethostbynamel6('2620::2d0:200:0:0:0:10')); |
*/ |
function resolveip($host) { |
return gethostbynamel6($host); |
} |
# http://www.php.net/manual/en/function.gethostbyname.php#70936 |
# Modified by ViaThinkSoft |
# VTS-Modified: try_a default false -> true |
function gethostbyname6($host, $try_a = /* false */ true) { |
// get AAAA record for $host |
// if $try_a is true, if AAAA fails, it tries for A |
// the first match found is returned |
// otherwise returns false |
$dns = gethostbynamel6($host, $try_a); |
if ($dns == false) { |
return false; |
} else { |
return $dns[0]; |
} |
} |
# VTS-Modified: try_a default false -> true |
function gethostbynamel6($host, $try_a = /* false */ true) { |
# Added by VTS |
$ipfilter = filter_var($host,FILTER_VALIDATE_IP); |
if ($ipfilter != '') return array($ipfilter); |
// get AAAA records for $host, |
// if $try_a is true, if AAAA fails, it tries for A |
// results are returned in an array of ips found matching type |
// otherwise returns false |
$dns6 = dns_get_record($host, DNS_AAAA); |
if ($try_a == true) { |
$dns4 = dns_get_record($host, DNS_A); |
$dns = array_merge($dns4, $dns6); |
} else { |
$dns = $dns6; |
} |
$ip6 = array(); |
$ip4 = array(); |
foreach ($dns as $record) { |
if ($record["type"] == "A") { |
$ip4[] = $record["ip"]; |
} |
if ($record["type"] == "AAAA") { |
$ip6[] = $record["ipv6"]; |
} |
} |
# VTS-Modified: IP4+IP6 merged |
$merged = array_merge($ip4, $ip6); |
if (count($merged) < 1) { |
return false; |
} else { |
return $merged; |
} |
if (count($ip6) < 1) { |
if ($try_a == true) { |
if (count($ip4) < 1) { |
return false; |
} else { |
return $ip4; |
} |
} else { |
return false; |
} |
} else { |
return $ip6; |
} |
} |
?> |
/trunk/ipv4_functions.inc.php |
---|
0,0 → 1,667 |
<?php |
/* |
* IPv4 functions for PHP |
* Copyright 2012-2021 Daniel Marschall, ViaThinkSoft |
* Version 2021-05-21 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
// TODO: oop, exceptions? |
// Very small self-test: |
/* |
function ipv4_selftest() { |
$iv_b = ipv4_complete('1.2'); |
$iv_m = 20; |
$r = ipv4_cidr2range($iv_b, $iv_m); |
echo "$iv_b/$iv_m => $r[0] - $r[1]\n"; |
$rev = ipv4_range2cidr($r[0], $r[1]); |
$rev = implode("\n", $rev); |
echo "$r[0] - $r[1] => $rev ["; |
$ok = $rev == "$iv_b/$iv_m"; |
echo $ok ? 'OK' : 'Mismatch'; |
echo "]\n"; |
echo "In-CIDR-Test: "; |
echo ipv4_in_cidr("$iv_b/$iv_m", "$iv_b/$iv_m") ? 'OK' : 'Fail'; |
echo "\n"; |
} |
ipv4_selftest(); |
*/ |
function ipv4_cidr2range($baseip_or_cidr, $subnet='') { |
# (C) 2012 ViaThinkSoft |
# Version 1.1 |
# This function converts an CIDR notation <baseip>/<subnet> into an IPv4 address block array($low_ip, $high_ip) |
if (strpos($baseip_or_cidr, '/') !== false) { |
$tmp = explode('/', $baseip_or_cidr, 2); |
$baseip_or_cidr = $tmp[0]; |
$subnet = $tmp[1]; |
unset($tmp); |
} |
if (($subnet < 0) || ($subnet > 32)) return false; |
$maxint32 = 0xFFFFFFFF; |
$netmask = $maxint32 << (32-$subnet); |
$netmask = $netmask & $maxint32; // crop to 32 bits |
$wildcard = $maxint32 ^ $netmask; // ~$netmask; |
$x = ipv4_incomplete_ip2long($baseip_or_cidr) & $netmask; |
$nums = $wildcard; |
$low = long2ip($x); |
$high = long2ip($x + $nums); |
return array($low, $high); |
} |
function ipv4_range2cidr($baseip, $topip, $shortening=false) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# This function converts an IPv4 address block into valid CIDR blocks (There may be multiple blocks!) |
$out = array(); |
if (ipv4_cmp($baseip, $topip) > 0) return false; |
while (ipv4_incomplete_ip2long($baseip)-1 != ipv4_incomplete_ip2long($topip)) { |
$i = -1; |
do { |
$i++; |
$range = ipv4_cidr2range($baseip, $i); |
$l = $range[0]; |
$t = $range[1]; |
} while ((ipv4_cmp($l, $baseip) != 0) || (ipv4_cmp($t, $topip) > 0)); |
# Shortening: Stroke ".0" at the end |
if ($shortening) $baseip = ipv4_shortening($baseip); |
$out[] = "$baseip/$i"; |
$baseip = ipv4_add($t, 1); |
} |
return $out; |
} |
function ipv4_shortening($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return preg_replace("|(\\.0{1,3}){0,3}\$|ismU", '', $ip); |
} |
function ipv4_add($baseip, $num) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return long2ip(ipv4_incomplete_ip2long($baseip) + $num); |
} |
function ipv4_sub($baseip, $num) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return long2ip(ipv4_incomplete_ip2long($baseip) - $num); |
} |
function ipv4_cmp($a, $b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$a = ipv4_incomplete_ip2long($a); |
$b = ipv4_incomplete_ip2long($b); |
if ($a == $b) return 0; |
if ($a < $b) return -1; |
if ($a > $b) return 1; |
} |
function ipv4_in_cidr($haystack, $needle) { |
# (C) 2012 ViaThinkSoft |
# Version 1.1 |
$x = explode('/', $haystack); |
$ha = ipv4_cidr2range($x[0], $x[1]); |
$x = explode('/', $needle); |
if (!isset($x[1])) $x[1] = '32'; // single IP |
$ne = ipv4_cidr2range($x[0], $x[1]); |
$ha_low = ipv4_incomplete_ip2long($ha[0]); |
$ha_hig = ipv4_incomplete_ip2long($ha[1]); |
$ne_low = ipv4_incomplete_ip2long($ne[0]); |
$ne_hig = ipv4_incomplete_ip2long($ne[1]); |
# HA: low[ ]high |
# NE: low[ ]high |
return ($ne_low >= $ha_low) && ($ne_hig <= $ha_hig); |
} |
function ipv4_complete($short_form) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$short_form = trim($short_form); |
if ($short_form == '') return '0.0.0.0'; |
$c = substr_count($short_form, '.'); |
if ($c > 3) return false; |
if ($c == 3) return $short_form; |
$c = substr_count($short_form, '.'); |
$short_form .= str_repeat('.0', 3-$c); |
return $short_form; |
} |
function ipv4_incomplete_ip2long($ip) { |
# (C) 2012-2014 ViaThinkSoft |
# Version 1.2 |
# return sprintf('%u', ip2long(ipv4_complete($ip))); |
return sprintf('%u', ip2long(ipv4_normalize($ip))); |
} |
// IMPORTANT! $cmp_ary[x]=y MUST HAVE x<=y ! |
function ipv4_merge_address_blocks($data, $debug = false, $shortening = false) { |
# (C) 2012-2013 ViaThinkSoft |
# Version 2.2 |
if ($debug !== false) $STARTZEIT = time(); |
// 1. Convert IPs to numbers |
$cmp_ary = array(); |
foreach ($data as $a => &$b) { |
$a = ipv4_incomplete_ip2long($a); |
$b = ipv4_incomplete_ip2long($b); |
$cmp_ary[$a] = $b; |
unset($a); |
unset($b); |
} |
// 2. Sort array |
ksort($cmp_ary); |
// 3. Merge the blocks in an intelligent way (and remove redundant blocks) |
# Merge overlapping blocks |
# [ ] |
# [ ] -> [ ] |
# Merge neighbor blocks |
# [ ][ ] -> [ ] |
# Remove redundant blocks |
# [ ] -> [ ] |
# [ ] |
$merge_count = 0; |
$redundant_deleted_count = 0; |
$round_count = 0; |
do { |
if ($debug !== false) { |
$LAUFZEIT = time() - $STARTZEIT; |
echo $debug."Merging... $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\r"; |
} |
$round_count++; |
$clean = true; |
foreach ($cmp_ary as $a => &$b) { |
foreach ($cmp_ary as $x => &$y) { |
// x in range [a+1..b+1] ? |
if ($x<=$a) continue; |
if ($x>$b+1) break; |
// Merge |
$clean = false; |
if ($y>$b) { |
$merge_count++; |
$b = $y; |
unset($cmp_ary[$x]); |
} else { |
$redundant_deleted_count++; |
unset($cmp_ary[$x]); |
} |
} |
} |
} while (!$clean); |
if ($debug !== false) { |
$LAUFZEIT = time() - $STARTZEIT; |
echo $debug."Merge completed. $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\n"; |
} |
// 4. Convert back to IPs |
$out_ary = array(); |
foreach ($cmp_ary as $a => &$b) { |
$a = long2ip($a); |
$b = long2ip($b); |
if ($shortening) { |
$a = ipv4_shortening($a); |
$b = ipv4_shortening($b); |
} |
$out_ary[$a] = $b; |
} |
return $out_ary; |
} |
function ipv4_merge_arrays($data_a, $data_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.2 |
$normalized_data_a = array(); |
foreach ($data_a as $from => &$to) { |
$normalized_data_a[ipv4_normalize($from)] = ipv4_normalize($to); |
} |
$normalized_data_b = array(); |
foreach ($data_b as $from => &$to) { |
$normalized_data_b[ipv4_normalize($from)] = ipv4_normalize($to); |
} |
$data = array(); |
foreach ($normalized_data_a as $from => &$to) { |
if (isset($normalized_data_b[$from])) { |
$data[$from] = ipv4_max($to, $normalized_data_b[$from]); |
} else { |
$data[$from] = $to; |
} |
} |
foreach ($normalized_data_b as $from => &$to) { |
if (!isset($normalized_data_a[$from])) { |
$data[$from] = $to; |
} |
} |
return $data; |
} |
function ipv4_valid($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# return ipv4_incomplete_ip2long($ip) !== false; |
return ip2long($ip) !== false; |
} |
function ipv4_normalize($ip) { |
# (C) 2012-2013 ViaThinkSoft |
# Version 1.1.1 |
# Example: |
# 100.010.001.000 -> 100.10.1.0 |
$ip = ipv4_complete($ip); |
if (!$ip) return false; |
# ip2long buggy: 001.0.0.0 is not accepted |
## $cry = explode('.', $ip); |
## $cry[0] = preg_replace('@^0+@', '', $cry[0]); if ($cry[0] == '') $cry[0] = '0'; |
## $cry[1] = preg_replace('@^0+@', '', $cry[1]); if ($cry[1] == '') $cry[1] = '0'; |
## $cry[2] = preg_replace('@^0+@', '', $cry[2]); if ($cry[2] == '') $cry[2] = '0'; |
## $cry[3] = preg_replace('@^0+@', '', $cry[3]); if ($cry[3] == '') $cry[3] = '0'; |
## $ip = implode('.', $cry); |
## return $ip; |
return preg_replace('@^0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})$@', '\\1.\\2.\\3.\\4', $ip); |
} |
function ipv4_expand($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# Example: |
# 100.10.1.0 -> 100.010.001.000 |
$ip = ipv4_complete($ip); |
if (!$ip) return false; |
$cry = explode('.', $ip); |
$cry[0] = str_pad($cry[0], 3, '0', STR_PAD_LEFT); |
$cry[1] = str_pad($cry[1], 3, '0', STR_PAD_LEFT); |
$cry[2] = str_pad($cry[2], 3, '0', STR_PAD_LEFT); |
$cry[3] = str_pad($cry[3], 3, '0', STR_PAD_LEFT); |
return implode('.', $cry); |
} |
function ipv4_min($ip_a, $ip_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
if (ipv4_cmp($ip_a, $ip_b) == -1) { |
return $ip_a; |
} else { |
return $ip_b; |
} |
} |
function ipv4_max($ip_a, $ip_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
if (ipv4_cmp($ip_a, $ip_b) == 1) { |
return $ip_a; |
} else { |
return $ip_b; |
} |
} |
function ipv4_ipcount($data) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$cnt = 0; |
foreach ($data as $from => &$to) { |
$cnt += ipv4_incomplete_ip2long($to) - ipv4_incomplete_ip2long($from); |
} |
return $cnt; |
} |
function ipv4_read_file($file) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$data = array(); |
$lines = file($file); |
foreach ($lines as &$line) { |
$rng = ipv4_line2range($line); |
$data[$rng[0]] = $rng[1]; |
} |
return $data; |
} |
function ipv4_line2range($line) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$line = trim($line); |
if (strpos($line, '/') !== false) { |
$rng = ipv4_cidr2range($line); |
} else { |
$rng = explode('-', $line); |
$rng[0] = trim($rng[0]); |
$rng[1] = trim($rng[1]); |
$rng[0] = ipv4_normalize($rng[0]); |
if (!isset($rng[1])) $rng[1] = $rng[0]; |
$rng[1] = ipv4_normalize($rng[1]); |
} |
return $rng; |
} |
# --- New 16,12,12 |
define('IPV4_BITS', 32); |
function ipv4_distance($ipOrCIDR_Searchterm, $ipOrCIDR_Candidate) { |
$ary = ipv4_cidr_split($ipOrCIDR_Searchterm); |
$ip = $ary[0]; |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
return false; |
} |
$ary = ipv4_cidr_split($ipOrCIDR_Candidate); |
$ip = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
return false; |
} |
$x = ipv4_trackdown($ipOrCIDR_Searchterm); |
if (ipv4_in_cidr($x[0], $ip.'/'.$cidr_bits)) { |
$ary = ipv4_cidr_split($x[0]); |
$cidr_bits2 = $ary[1]; |
if ($cidr_bits2 > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
return $cidr_bits2-$cidr_bits; |
} |
$i = 0; |
$max = false; |
foreach ($x as &$y) { |
if (ipv4_in_cidr($ip.'/'.$cidr_bits, $y)) { |
$max = $i; |
} |
$i++; |
} |
return $max; |
} |
function ipv4_cidr_split($ipOrCIDR) { |
$ary = explode('/', $ipOrCIDR, 2); |
$cidr_bits = isset($ary[1]) ? $ary[1] : IPV4_BITS; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$ip = $ary[0]; |
return array($ip, $cidr_bits); |
} |
function ipv4_equals($ipOrCIDRA, $ipOrCIDRB) { |
return ipv4_normalize_range($ipOrCIDRA) == ipv4_normalize_range($ipOrCIDRB); |
} |
function ipv4_cidr_min_ip($ipOrCIDR) { |
$ary = ipv4_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
return bin2ip($m); |
} |
function ipv4_cidr_max_ip($ipOrCIDR) { |
$ary = ipv4_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('1', IPV4_BITS-$cidr_bits); |
return bin2ip($m); |
} |
function ipv4_normalize_range($ipOrCIDR) { |
$ary = ipv4_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
return bin2ip($m) . '/' . $cidr_bits; |
} |
function ipv4_trackdown($ipOrCIDR) { |
$ary = ipv4_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$out = array(); |
$m = ip2bin($ipOrCIDR); |
for ($i=$cidr_bits; $i>=0; $i--) { |
$m = substr($m, 0, $i) . str_repeat('0', IPV4_BITS-$i); |
$out[] = bin2ip($m) . '/' . $i; |
} |
return $out; |
} |
# --- |
if (!function_exists('ip2bin')) { |
function ip2bin($ip) { |
# Source: http://php.net/manual/en/function.ip2long.php#104163 |
# modified by VTS |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) { |
$iplong = ip2long($ip); |
assert($iplong !== false); |
return base_convert((string)$iplong, 10, 2); |
} |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
return false; |
} |
if (($ip_n = inet_pton($ip)) === false) { |
return false; |
} |
$bits = 15; // 16 x 8 bit = 128bit (ipv6) |
$ipbin = ''; # added by vts to avoid warning |
while ($bits >= 0) { |
$bin = sprintf('%08b', (ord($ip_n[$bits]))); |
$ipbin = $bin.$ipbin; |
$bits--; |
} |
return $ipbin; |
} |
} |
if (!function_exists('bin2ip')) { |
function bin2ip($bin) { |
# Source: http://php.net/manual/en/function.ip2long.php#104163 |
# modified by VTS |
if (strlen($bin) <= 32) { // 32bits (ipv4) |
$iplong = base_convert($bin, 2, 10); |
return long2ip(intval($iplong)); |
} |
if (strlen($bin) != 128) { |
return false; |
} |
$pad = 128 - strlen($bin); |
for ($i = 1; $i <= $pad; $i++) { |
$bin = '0'.$bin; |
} |
$bits = 0; |
$ipv6 = ''; # added by vts to avoid warning |
while ($bits <= 7) { |
$bin_part = substr($bin,($bits*16),16); |
$ipv6 .= dechex(bindec($bin_part)) . ':'; |
$bits++; |
} |
return inet_ntop(inet_pton(substr($ipv6, 0, -1))); |
} |
} |
# --- TEST |
/* |
assert(ipv4_normalize('100.010.001.000') == '100.10.1.0'); |
assert(ipv4_normalize('100.010.01.000') == '100.10.1.0'); |
assert(ipv4_normalize('100.10.001.000') == '100.10.1.0'); |
assert(ipv4_normalize('1.010.001.000') == '1.10.1.0'); |
assert(ipv4_normalize('1.10.001.000') == '1.10.1.0'); |
assert(ipv4_distance('192.168.0.0/16', '192.168.64.0/18') == -2); |
assert(ipv4_distance('192.168.0.0/17', '192.168.64.0/18') == -1); |
assert(ipv4_distance('192.168.64.0/18', '192.168.64.0/18') == 0); |
assert(ipv4_distance('192.168.64.0/19', '192.168.64.0/18') == 1); |
assert(ipv4_distance('192.168.64.0/20', '192.168.64.0/18') == 2); |
assert(ipv4_distance('192.168.69.202/31', '192.168.69.200/31') === false); |
assert(ipv4_distance('192.168.69.201/32', '192.168.69.200/32') === false); |
assert(ipv4_distance('192.168.69.201', '192.168.69.200') === false); |
*/ |
/* |
$test = '192.168.69.123'; |
$x = ipv4_trackdown($test); |
foreach ($x as &$cidr) { |
$min = ipv4_cidr_min_ip($cidr); |
$max = ipv4_cidr_max_ip($cidr); |
echo "$cidr ($min - $max)\n"; |
} |
*/ |
function ipv4_sort($ary) { |
$f = array(); |
foreach ($ary as $c) { |
$a = explode('/', $c); |
$ip = $a[0]; |
$bits = isset($a[1]) ? $a[1] : 32; |
$d = ip2bin($ip); |
# ord('*') must be smaller than ord('0') |
$d = substr($d, 0, $bits).str_repeat('*', 32-$bits); |
$f[$d] = $c; |
} |
return $f; |
} |
function ipv4_make_tree($ary) { |
$ary = ipv4_sort($ary); |
if (count($ary) == 0) return array(); |
$sub_begin = ''; |
$sub_begin_ip = ''; |
foreach ($ary as $n => $d) { |
$sub_begin = substr($n, 0, strpos($n, '*')); |
$sub_begin_ip = $d; |
unset($ary[$n]); |
break; |
} |
$sub = array(); |
$nonsub = array(); |
foreach ($ary as $n => $d) { |
if (substr($n, 0, strlen($sub_begin)) == $sub_begin) { |
$sub[$n] = $d; |
} else { |
$nonsub[$n] = $d; |
} |
} |
$out = array(); |
$out[$sub_begin_ip] = ipv4_make_tree($sub); |
$a = ipv4_make_tree($nonsub); |
$out = array_merge($out, $a); |
return $out; |
} |
/trunk/ipv6_functions.inc.php |
---|
0,0 → 1,769 |
<?php |
/* |
* IPv6 functions for PHP |
* Copyright 2012-2021 Daniel Marschall, ViaThinkSoft |
* Version 2021-05-21 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
# This library requires either the GMP extension (or BCMath if gmp_supplement.inc.php is present) |
// TODO: oop, exceptions? |
// TODO: variant without gmp ? |
// TODO: IPv6 resolution 'ffff::192.168.69.1' -> 'ffff:0000:0000:0000:0000:0000:c0a8:4501' does not work! |
if (file_exists(__DIR__ . '/gmp_supplement.inc.php')) include_once __DIR__ . '/gmp_supplement.inc.php'; |
define('GMP_ONE', gmp_init('1')); |
// Very small self-test: |
/* |
function ipv6_selftest() { |
$iv_b = 'c0ff:ee00::'; |
$iv_m = 32; |
$r = ipv6_cidr2range($iv_b, $iv_m); |
echo "$iv_b/$iv_m => $r[0] - $r[1]\n"; |
$rev = ipv6_range2cidr($r[0], $r[1]); |
$rev = implode("\n", $rev); |
echo "$r[0] - $r[1] => $rev ["; |
$ok = $rev == "$iv_b/$iv_m"; |
echo $ok ? 'OK' : 'Mismatch'; |
echo "]\n"; |
echo "In-CIDR-Test: "; |
echo ipv6_in_cidr("$iv_b/$iv_m", "$iv_b/$iv_m") ? 'OK' : 'Fail'; |
echo "\n"; |
} |
ipv6_selftest(); |
*/ |
$cache_ipv6_cidr2range = array(); |
function ipv6_cidr2range($baseip_or_cidr, $subnet='') { |
# (C) 2012 ViaThinkSoft |
# Version 1.1 |
# This function converts an CIDR notation <baseip>/<subnet> into an IPv6 address block array($low_ip, $high_ip) |
global $cache_ipv6_cidr2range; |
$vvv = $baseip_or_cidr.'|'.$subnet; |
if (isset($cache_ipv6_cidr2range[$vvv])) return $cache_ipv6_cidr2range[$vvv]; |
if (strpos($baseip_or_cidr, '/') !== false) { |
$tmp = explode('/', $baseip_or_cidr, 2); |
$baseip_or_cidr = $tmp[0]; |
$subnet = $tmp[1]; |
unset($tmp); |
} |
if (($subnet < 0) || ($subnet > 128)) { |
$cache_ipv6_cidr2range[$vvv] = false; |
return false; |
} |
$maxint128 = gmp_sub(gmp_pow('2', 128), GMP_ONE); # TODO: GMP_TWO ? |
$netmask = gmp_shiftl($maxint128, 128-$subnet); |
$netmask = gmp_and($netmask, $maxint128); // crop to 128 bit |
$wildcard = gmp_xor($maxint128, $netmask); |
$x = gmp_and(ip2long6($baseip_or_cidr), $netmask); |
$nums = $wildcard; |
$low = long2ip6($x); |
$high = long2ip6(gmp_add($x, $nums)); |
$out = array($low, $high); |
$cache_ipv6_cidr2range[$vvv] = $out; |
return $out; |
} |
$cache_ipv6_range2cidr = array(); |
function ipv6_range2cidr($baseip, $topip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# This function converts an IPv6 address block into valid CIDR blocks (There may be multiple blocks!) |
global $cache_ipv6_range2cidr; |
$vvv = $baseip.'|'.$topip; |
if (isset($cache_ipv6_range2cidr[$vvv])) return $cache_ipv6_range2cidr[$vvv]; |
$out = array(); |
if (ipv6_cmp($baseip, $topip) > 0) { |
$cache_ipv6_range2cidr[$vvv] = false; |
return false; |
} |
while (gmp_cmp(gmp_sub(ip2long6($baseip), GMP_ONE), ip2long6($topip)) != 0) { |
$i = -1; |
do { |
$i++; |
$range = ipv6_cidr2range($baseip, $i); |
$l = $range[0]; |
$t = $range[1]; |
} while ((ipv6_cmp($l, $baseip) != 0) || (ipv6_cmp($t, $topip) > 0)); |
$out[] = "$baseip/$i"; |
$baseip = ipv6_add($t, GMP_ONE); |
} |
$cache_ipv6_range2cidr[$vvv] = $out; |
return $out; |
} |
function ipv6_add($baseip, $num) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return long2ip6(gmp_add(ip2long6($baseip), $num)); |
} |
function ipv6_sub($baseip, $num) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return long2ip6(gmp_sub(ip2long6($baseip), $num)); |
} |
function ipv6_cmp($a, $b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return gmp_cmp(ip2long6($a), ip2long6($b)); |
} |
$cache_ipv6_in_cidr = array(); |
function ipv6_in_cidr($haystack, $needle) { |
# (C) 2012 ViaThinkSoft |
# Version 1.1 |
global $cache_ipv6_in_cidr; |
$vvv = $haystack.'|'.$needle; |
if (isset($cache_ipv6_in_cidr[$vvv])) return $cache_ipv6_in_cidr[$vvv]; |
$x = explode('/', $haystack); |
$ha = ipv6_cidr2range($x[0], $x[1]); |
$x = explode('/', $needle); |
if (!isset($x[1])) $x[1] = 128; // single IP |
$ne = ipv6_cidr2range($x[0], $x[1]); |
$ha_low = ip2long6($ha[0]); |
$ha_hig = ip2long6($ha[1]); |
$ne_low = ip2long6($ne[0]); |
$ne_hig = ip2long6($ne[1]); |
# HA: low[ ]high |
# NE: low[ ]high |
$out = (gmp_cmp($ne_low, $ha_low) >= 0) && (gmp_cmp($ne_hig, $ha_hig) <= 0); |
$cache_ipv6_in_cidr[$vvv] = $out; |
return $out; |
} |
// IMPORTANT! $cmp_ary[x]=y MUST HAVE x<=y ! |
function ipv6_merge_address_blocks($data, $debug = false) { |
# (C) 2012-2013 ViaThinkSoft |
# Version 2.2 |
if ($debug !== false) $STARTZEIT = time(); |
// 1. Convert IPs to numbers |
$cmp_ary = array(); |
foreach ($data as $a => &$b) { |
$a = ip2long6($a); |
$b = ip2long6($b); |
$cmp_ary[gmp_strval($a)] = gmp_strval($b); |
unset($a); |
unset($b); |
} |
// 2. Sort array |
ksort($cmp_ary); |
// 3. Merge the blocks in an intelligent way (and remove redundant blocks) |
# Merge overlapping blocks |
# [ ] |
# [ ] -> [ ] |
# Merge neighbor blocks |
# [ ][ ] -> [ ] |
# Remove redundant blocks |
# [ ] -> [ ] |
# [ ] |
$merge_count = 0; |
$redundant_deleted_count = 0; |
$round_count = 0; |
do { |
if ($debug !== false) { |
$LAUFZEIT = time() - $STARTZEIT; |
echo $debug."Merging... $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\r"; |
} |
$round_count++; |
$clean = true; |
foreach ($cmp_ary as $a => &$b) { |
foreach ($cmp_ary as $x => &$y) { |
// x in range [a+1..b+1] ? |
if (gmp_cmp(gmp_init($x), gmp_init($a)) <= 0) continue; |
if (gmp_cmp(gmp_init($x), gmp_add(gmp_init($b), GMP_ONE)) > 0) break; |
// Merge |
$clean = false; |
if (gmp_cmp(gmp_init($y), gmp_init($b)) > 0) { |
$merge_count++; |
$b = $y; |
unset($cmp_ary[$x]); |
} else { |
$redundant_deleted_count++; |
unset($cmp_ary[$x]); |
} |
} |
} |
} while (!$clean); |
if ($debug !== false) { |
$LAUFZEIT = time() - $STARTZEIT; |
echo $debug."Merge completed. $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\n"; |
} |
// 4. Convert back to IPs |
$out_ary = array(); |
foreach ($cmp_ary as $a => &$b) { |
$a = long2ip6(gmp_init($a)); |
$b = long2ip6(gmp_init($b)); |
$out_ary[$a] = $b; |
} |
return $out_ary; |
} |
function ipv6_merge_arrays($data_a, $data_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.2 |
$normalized_data_a = array(); |
foreach ($data_a as $from => &$to) { |
$normalized_data_a[ipv6_normalize($from)] = ipv6_normalize($to); |
} |
$normalized_data_b = array(); |
foreach ($data_b as $from => &$to) { |
$normalized_data_b[ipv6_normalize($from)] = ipv6_normalize($to); |
} |
$data = array(); |
foreach ($normalized_data_a as $from => &$to) { |
if (isset($normalized_data_b[$from])) { |
$data[$from] = ipv6_max($to, $normalized_data_b[$from]); |
} else { |
$data[$from] = $to; |
} |
} |
foreach ($normalized_data_b as $from => &$to) { |
if (!isset($normalized_data_a[$from])) { |
$data[$from] = $to; |
} |
} |
return $data; |
} |
function ipv6_valid($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
return ip2long6($ip) !== false; |
} |
function ipv6_normalize($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# Example: |
# 2001:0000:0000::1 -> 2001::1 |
$long = ip2long6($ip); |
if ($long == -1 || $long === FALSE) return false; |
return long2ip6($long); |
} |
function ipv6_expand($ip) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
# Example: |
# 2001::1 -> 2001:0000:0000:0000:0000:0000:0000:0000 |
$long = ip2long6($ip); |
if ($long == -1 || $long === FALSE) return false; |
return long2ip6($long, false); |
} |
function ipv6_min($ip_a, $ip_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
if (ipv6_cmp($ip_a, $ip_b) == -1) { |
return $ip_a; |
} else { |
return $ip_b; |
} |
} |
function ipv6_max($ip_a, $ip_b) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
if (ipv6_cmp($ip_a, $ip_b) == 1) { |
return $ip_a; |
} else { |
return $ip_b; |
} |
} |
function ipv6_ipcount($data) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$cnt = gmp_init('0'); |
foreach ($data as $from => &$to) { |
$cnt = gmp_add($cnt, gmp_sub(ip2long6($to), ip2long6($from))); |
} |
return gmp_strval($cnt, 10); |
} |
function ipv6_read_file($file) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$data = array(); |
$lines = file($file); |
foreach ($lines as &$line) { |
$rng = ipv6_line2range($line); |
$data[$rng[0]] = $rng[1]; |
} |
return $data; |
} |
function ipv6_line2range($line) { |
# (C) 2012 ViaThinkSoft |
# Version 1.0 |
$line = trim($line); |
if (strpos($line, '/') !== false) { |
$rng = ipv6_cidr2range($line); |
} else { |
$rng = explode('-', $line); |
$rng[0] = trim($rng[0]); |
$rng[1] = trim($rng[1]); |
$rng[0] = ipv6_normalize($rng[0]); |
if (!isset($rng[1])) $rng[1] = $rng[0]; |
$rng[1] = ipv6_normalize($rng[1]); |
} |
return $rng; |
} |
# --- |
if (!function_exists('gmp_shiftl')) { |
function gmp_shiftl($x, $n) { // shift left |
// http://www.php.net/manual/en/ref.gmp.php#99788 |
return gmp_mul($x, gmp_pow('2', $n)); |
} |
} |
if (!function_exists('gmp_shiftr')) { |
function gmp_shiftr($x, $n) { // shift right |
// http://www.php.net/manual/en/ref.gmp.php#99788 |
return gmp_div($x, gmp_pow('2', $n)); |
} |
} |
$cache_ip2long6 = array(); |
function ip2long6($ipv6) { |
// Source: |
// http://www.netz-guru.de/2009/11/07/php-ipv6-ip2long-und-long2ip-funktionen/ |
// Slightly modified |
global $cache_ip2long6; |
if (isset($cache_ip2long6[$ipv6])) return $cache_ip2long6[$ipv6]; |
if ($ipv6 == '') $ipv6 = '::'; |
if (filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
$cache_ip2long6[$ipv6] = false; |
return false; |
} |
$ip_n = @inet_pton($ipv6); |
if ($ip_n === false) { |
$cache_ip2long6[$ipv6] = false; |
return false; // modified |
} |
$bytes = 16; // 16 bytes x 8 bit/byte = 128bit |
$ipv6long = ''; |
while ($bytes > 0) { |
$bin = sprintf('%08b',(ord($ip_n[$bytes-1]))); |
$ipv6long = $bin.$ipv6long; |
$bytes--; |
} |
// $out = gmp_strval(gmp_init($ipv6long, 2), 10); |
$out = gmp_init($ipv6long, 2); |
$cache_ip2long6[$ipv6] = $out; |
return $out; |
} |
$cache_long2ip6 = array(); |
function long2ip6($ipv6long, $compress=true) { |
// Source: |
// http://www.netz-guru.de/2009/11/07/php-ipv6-ip2long-und-long2ip-funktionen/ |
// Slightly modified |
global $cache_long2ip6; |
$vvv = ($compress ? 'T' : 'F').$ipv6long; |
if (isset($cache_long2ip6[$vvv])) return $cache_long2ip6[$vvv]; |
// $bin = gmp_strval(gmp_init($ipv6long, 10), 2); |
$bin = gmp_strval($ipv6long, 2); |
if (strlen($bin) < 128) { |
$pad = 128 - strlen($bin); |
for ($i = 1; $i <= $pad; $i++) { |
$bin = '0'.$bin; |
} |
} |
$bytes = 0; |
$ipv6 = ''; |
while ($bytes < 8) { // 16 bytes x 8 bit/byte = 128bit |
$bin_part = substr($bin,($bytes*16),16); |
$part = dechex(bindec($bin_part)); |
if (!$compress) { |
$part = str_pad($part, 4, '0', STR_PAD_LEFT); |
} |
$ipv6 .= $part.':'; |
$bytes++; |
} |
if ($compress) { |
$out = inet_ntop(inet_pton(substr($ipv6, 0, -1))); |
} else { |
$out = substr($ipv6, 0, strlen($ipv6)-1); |
} |
$cache_long2ip6[$vvv] = $out; |
return $out; |
} |
# --- New 16,12,12 |
define('IPV6_BITS', 128); |
$global_ipv6_distance = array(); |
function ipv6_distance($ipOrCIDR_Searchterm, $ipOrCIDR_Candidate) { |
global $global_ipv6_distance; |
$vvv = $ipOrCIDR_Searchterm.'|'.$ipOrCIDR_Candidate; |
if (isset($global_ipv6_distance[$vvv])) return $global_ipv6_distance[$vvv]; |
$ary = ipv6_cidr_split($ipOrCIDR_Searchterm); |
$ip = $ary[0]; |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
$global_ipv6_distance[$vvv] = false; |
return false; |
} |
$ary = ipv6_cidr_split($ipOrCIDR_Candidate); |
$ip = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV6_BITS) { |
$global_ipv6_distance[$vvv] = false; |
return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
} |
if (!is_numeric($cidr_bits)) return false; |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
$global_ipv6_distance[$vvv] = false; |
return false; |
} |
$x = ipv6_trackdown($ipOrCIDR_Searchterm); |
if (ipv6_in_cidr($x[0], $ip.'/'.$cidr_bits)) { |
$ary = ipv6_cidr_split($x[0]); |
$cidr_bits2 = $ary[1]; |
if ($cidr_bits2 > IPV6_BITS) { |
$global_ipv6_distance[$vvv] = false; |
return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
} |
$out = $cidr_bits2-$cidr_bits; |
$global_ipv6_distance[$vvv] = $out; |
return $out; |
} |
$i = 0; |
$max = false; |
foreach ($x as &$y) { |
if (ipv6_in_cidr($ip.'/'.$cidr_bits, $y)) { |
$max = $i; |
} |
$i++; |
} |
$global_ipv6_distance[$vvv] = $max; |
return $max; |
} |
function ipv6_cidr_split($ipOrCIDR) { |
$ary = explode('/', $ipOrCIDR, 2); |
$cidr_bits = isset($ary[1]) ? $ary[1] : IPV6_BITS; |
if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$ip = $ary[0]; |
return array($ip, $cidr_bits); |
} |
function ipv6_equals($ipOrCIDRA, $ipOrCIDRB) { |
return ipv6_normalize_range($ipOrCIDRA) == ipv6_normalize_range($ipOrCIDRB); |
} |
function ipv6_cidr_min_ip($ipOrCIDR) { |
$ary = ipv6_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV6_BITS-$cidr_bits); |
return bin2ip($m); |
} |
function ipv6_cidr_max_ip($ipOrCIDR) { |
$ary = ipv6_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('1', IPV6_BITS-$cidr_bits); |
return bin2ip($m); |
} |
function ipv6_normalize_range($ipOrCIDR) { |
# 2001:1800::1/21 |
# --> 2001:1800::/21 |
# 2001:1af8:4100:a061:0001::1337 |
# --> 2001:1af8:4100:a061:1::1337/128 |
$ary = ipv6_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$m = ip2bin($ipOrCIDR); |
$m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV6_BITS-$cidr_bits); |
return bin2ip($m) . '/' . $cidr_bits; |
} |
function ipv6_trackdown($ipOrCIDR) { |
$ary = ipv6_cidr_split($ipOrCIDR); |
$ipOrCIDR = $ary[0]; |
$cidr_bits = $ary[1]; |
if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS); |
if (!is_numeric($cidr_bits)) return false; |
$out = array(); |
$m = ip2bin($ipOrCIDR); |
for ($i=$cidr_bits; $i>=0; $i--) { |
$m = substr($m, 0, $i) . str_repeat('0', IPV6_BITS-$i); |
$out[] = bin2ip($m) . '/' . $i; |
} |
return $out; |
} |
function ipv6_sort($ary) { |
$f = array(); |
foreach ($ary as $c) { |
$a = explode('/', $c); |
$ip = $a[0]; |
$bits = isset($a[1]) ? $a[1] : 128; |
$d = ip2bin($ip); |
# ord('*') must be smaller than ord('0') |
$d = substr($d, 0, $bits).str_repeat('*', 128-$bits); |
$f[$d] = $c; |
} |
return $f; |
} |
function ipv6_make_tree($ary) { |
$ary = ipv6_sort($ary); |
if (count($ary) == 0) return array(); |
$sub_begin = ''; |
$sub_begin_ip = ''; |
foreach ($ary as $n => $d) { |
$sub_begin = substr($n, 0, strpos($n, '*')); |
$sub_begin_ip = $d; |
unset($ary[$n]); |
break; |
} |
$sub = array(); |
$nonsub = array(); |
foreach ($ary as $n => $d) { |
if (substr($n, 0, strlen($sub_begin)) == $sub_begin) { |
$sub[$n] = $d; |
} else { |
$nonsub[$n] = $d; |
} |
} |
$out = array(); |
$out[$sub_begin_ip] = ipv6_make_tree($sub); |
$a = ipv6_make_tree($nonsub); |
$out = array_merge($out, $a); |
return $out; |
} |
# --- |
if (!function_exists('ip2bin')) { |
$cache_ip2bin = array(); |
function ip2bin($ip) { |
# Source: http://php.net/manual/en/function.ip2long.php#104163 |
# modified by VTS |
global $cache_ip2bin; |
if (isset($cache_ip2bin[$ip])) return $cache_ip2bin[$ip]; |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) { |
$iplong = ip2long($ip); |
assert($iplong !== false); |
$out = base_convert((string)$iplong, 10, 2); |
$cache_ip2bin[$ip] = $out; |
return $out; |
} |
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
$cache_ip2bin[$ip] = false; |
return false; |
} |
if (($ip_n = inet_pton($ip)) === false) { |
$cache_ip2bin[$ip] = false; |
return false; |
} |
$bits = 15; // 16 x 8 bit = 128bit (ipv6) |
$ipbin = ''; # added by vts to avoid warning |
while ($bits >= 0) { |
$bin = sprintf('%08b', (ord($ip_n[$bits]))); |
$ipbin = $bin.$ipbin; |
$bits--; |
} |
$cache_ip2bin[$ip] = $ipbin; |
return $ipbin; |
} |
} |
if (!function_exists('bin2ip')) { |
$cache_bin2ip = array(); |
function bin2ip($bin) { |
# Source: http://php.net/manual/en/function.ip2long.php#104163 |
# modified by VTS |
global $cache_bin2ip; |
if (isset($cache_bin2ip[$bin])) return $cache_bin2ip[$bin]; |
if (strlen($bin) <= 32) { // 32bits (ipv4) |
$iplong = base_convert($bin, 2, 10); |
$out = long2ip(intval($iplong)); |
$cache_bin2ip[$bin] = $out; |
return $out; |
} |
if (strlen($bin) != 128) { |
$cache_bin2ip[$bin] = false; |
return false; |
} |
$pad = 128 - strlen($bin); |
for ($i = 1; $i <= $pad; $i++) { |
$bin = '0'.$bin; |
} |
$bits = 0; |
$ipv6 = ''; # added by vts to avoid warning |
while ($bits <= 7) { |
$bin_part = substr($bin,($bits*16),16); |
$ipv6 .= dechex(bindec($bin_part)) . ':'; |
$bits++; |
} |
$out = inet_ntop(inet_pton(substr($ipv6, 0, -1))); |
$cache_bin2ip[$bin] = $out; |
return $out; |
} |
} |
# --- TEST |
/* |
assert(ipv6_normalize('2001:0000:0000::1') == '2001::1'); |
assert(ipv6_distance('2001:1ae0::/27', '2001:1af8::/29') == -2); |
assert(ipv6_distance('2001:1af0::/28', '2001:1af8::/29') == -1); |
assert(ipv6_distance('2001:1af8::/29', '2001:1af8::/29') == 0); |
assert(ipv6_distance('2001:1af8::/30', '2001:1af8::/29') == 1); |
assert(ipv6_distance('2001:1af8::/31', '2001:1af8::/29') == 2); |
assert(ipv6_distance('2001:1af8:4100:a061:0001::1336/127', '2001:1af8:4100:a061:0001::1335/127') === false); |
assert(ipv6_distance('2001:1af8:4100:a061:0001::1336/128', '2001:1af8:4100:a061:0001::1337/128') === false); |
assert(ipv6_distance('2001:1af8:4100:a061:0001::1336', '2001:1af8:4100:a061:0001::1337') === false); |
*/ |
/* |
$test = '2001:1af8:4100:a061:0001::1337'; |
$x = ipv6_trackdown($test); |
foreach ($x as &$cidr) { |
$min = ipv6_cidr_min_ip($cidr); |
$max = ipv6_cidr_max_ip($cidr); |
echo "$cidr ($min - $max)\n"; |
} |
*/ |
/trunk/last_weekday_date.php |
---|
0,0 → 1,11 |
<?php |
function get_last_weekday_date($dow) { |
for ($i=0; $i<=6; $i++) { |
$d = ftime()-$i*86400; |
$e = date('N', $d); |
if ($e == $dow) { |
return date('d.m.Y', $d); |
} |
} |
} |
/trunk/marschallHash.php |
---|
0,0 → 1,145 |
<?php |
// Mastercopy of this file: |
// http://www.viathinksoft.de/~daniel-marschall/code/php/marschallHash.phps |
function MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) { |
// -------------------------------------------------------------------------------- |
// MarschallHash: Uncrackable hash with multiple SHA1 iterations in base64 encoding |
// This function is pretty slow because of the iterations, but therefore secure |
// against offline attacks or rainbowtables. Also, the slowlyness of this hash |
// makes the creation of rainbow tables much harder. |
// |
// (C)Copyright 2011 Daniel Marschall, ViaThinkSoft. All rights reserved. |
// www.daniel-marschall.de / www.viathinksoft.de |
// |
// Notation of the hash name: |
// - MHA-1987 (resp. MHA-xxxx where xxxx stands for $iterations) |
// - MHAb-1987 is used for the binary output variant |
// - MD5MHA-1987 is used if $password is a (unsalted!) md5-hash |
// - MD5MHAb-1987 is used for the binary output variant. |
// |
// Default parameters: |
// iteratedSalt = '' --> you should change this value to something |
// user-specific (e.g. username) or something random |
// iterations = 1987 --> you should ONLY change this value to a lower |
// one if you have performance issues |
// binary_output = no --> base64 encoding is chosen by default |
// |
// Format: |
// - MHA has the same length as SHA1. |
// - MHA in base64 format has a constant length of 27 bytes and is case sensitive. |
// - MHA in binary format has a constant length of 20 bytes. |
// |
// Comparison 1: |
// x = '' |
// SHA1(x) = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' (Len = 40) |
// SHA256(x) = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' (Len = 64) |
// MD5(x) = 'd41d8cd98f00b204e9800998ecf8427e' (Len = 32) |
// MHA(x) = 'UOLv7DgK5/4S7994FeSWZkHDJoQ' (Len = 27) |
// |
// Comparison 2: |
// x = 'The quick brown fox jumps over the lazy dog' |
// SHA1(x) = '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12' (Len = 40) |
// SHA256(x) = 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592' (Len = 64) |
// MD5(x) = '9e107d9d372bb6826bd81d3542a419d6' (Len = 32) |
// MHA(x) = 'Bqdd38sigmurBt6kU/0q99GWSnE' (Len = 27) |
// |
// Mechanism: |
// MHA(x, iteratedSalt, iterations) = optionalBase64(rec(iterations, x, iteratedSalt)) |
// rec[n, x, iteratedSalt] = binarySHA1(iteratedSalt || rec[n-1, x, iteratedSalt] || iteratedSalt) |
// rec[0, x, iteratedSalt] = x |
// |
// Recommended usage: |
// - Use the username as iteratedSalt |
// MHA($password, $username) == $database_hash |
// - If you want to upgrade your existing user-database, e.g. already hashed with md5(): |
// a) Update your database: |
// $database_hash_new = MHA($database_hash_old, $username) |
// b) Compare with this variant: |
// MHA(md5($password), $username) == $database_hash_new |
// or |
// MD5_MHA($password, $username) == $database_hash_new |
// |
// Revision: 2011-07-21 (fixed typo in 2013-03-09) |
// -------------------------------------------------------------------------------- |
if ($iterations < 1) { |
trigger_error('at function ' . __FUNCTION__ . ': $iterations has to be greater or equal 1', E_USER_ERROR); |
return false; |
} |
$m = $password; |
for ($i=1; $i<=$iterations; $i++) { |
$m = sha1($iteratedSalt.$m.$iteratedSalt, true); // SHA1 with binary output |
} |
if (!$binary_output) { |
$m = base64_encode($m); |
// Remove single "=" at the end |
# $m = str_replace('=', '', $m); |
$m = substr($m, 0, 27); |
} |
return $m; |
} |
// --- The following functions are useable for database migration --- |
function MD5_TO_MD5_MHA($md5_hash, $iteratedSalt='', $iterations=1987, $binary_output=false) { |
// Use this function to migrate a (unsalted!) md5 hash into a MD5MHA hash |
// |
// Actually, this is just an alias of MHA() |
return marschallHash($md5_hash, $iteratedSalt, $iterations, $binary_output); |
} |
function MD5_MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) { |
// Use this function if you have a MD5MHA hash instead of a MHA hash |
// |
// MD5MHA() is equal to MHA(MD5()) where MD5() is unsalted! |
return MHA(md5($password), $iteratedSalt, $iterations, $binary_output); |
} |
function MD5MHA($password, $iteratedSalt='', $iterations=1987, $binary_output=false) { |
// Alias of MD5_MHA() |
return MD5_MHA($password, $iteratedSalt, $iterations, $binary_output); |
} |
function MHA_AddIterations($mha, $iteratedSalt='', $additionalIterations, $binary_output=false) { |
// This function converts a MHA with x itertions into a MHA with |
// x+additionalIterations iterations, if the iteratedSalt is equal. |
// Use this function if you want to upgrade your database to a higher MHA strength. |
// |
// Example: |
// MHA_AddIterations(MHA('test', 'salt', 1987), 'salt', 13) == MHA('test', 'salt', 1987+13); |
// |
// Of course, you cannot lower the strength of a MHA, so additionalIterations has to be >= 0. |
// Is it Base64 input? |
# if (strlen($mha) == 28) $mha = base64_decode($mha); |
if (strlen($mha) == 27) $mha = base64_decode($mha); |
// Is it now binary input? |
// (Que) Will there be problems if the input string looks like multibyte? |
if (strlen($mha) != 20) { |
trigger_error('at function ' . __FUNCTION__ . ': does not seem to be a MHA', E_USER_ERROR); |
return false; |
} |
if ($additionalIterations == 0) return $mha; |
if ($additionalIterations < 0) { |
trigger_error('at function ' . __FUNCTION__ . ': additionalIterations has to be 0 or higher.', E_USER_ERROR); |
return false; |
} |
return marschallHash($mha, $iteratedSalt, $additionalIterations, $binary_output); |
} |
?> |
/trunk/oid_utils.inc.php |
---|
0,0 → 1,915 |
<?php |
/* |
* OID-Utilities for PHP |
* Copyright 2011-2021 Daniel Marschall, ViaThinkSoft |
* Version 2021-05-21 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
// All functions in this library are compatible with leading zeroes (not recommended) and leading dots |
// TODO: change some function names, so that they have a uniform naming schema, and rename "oid identifier" into "ASN.1 alphanumeric identifier" |
// oid_id_is_valid() => asn1_alpha_id_valid() |
define('OID_DOT_FORBIDDEN', 0); |
define('OID_DOT_OPTIONAL', 1); |
define('OID_DOT_REQUIRED', 2); |
/** |
* Checks if an OID has a valid dot notation. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param string $oid<br /> |
* An OID in dot notation. |
* @param boolean $allow_leading_zeroes<br /> |
* true of leading zeroes are allowed or not. |
* @param boolean $allow_leading_dot<br /> |
* true of leading dots are allowed or not. |
* @return boolean true if the dot notation is valid. |
**/ |
function oid_valid_dotnotation($oid, $allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
$regex = oid_validation_regex($allow_leading_zeroes, $allow_leading_dot, $min_len); |
$m = array(); |
return preg_match($regex, $oid, $m) ? true : false; |
} |
/** |
* Returns a full regular expression to validate an OID in dot-notation |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param boolean $allow_leading_zeroes<br /> |
* true of leading zeroes are allowed or not. |
* @param boolean $allow_leading_dot<br /> |
* true of leading dots are allowed or not. |
* @return string The regular expression |
**/ |
function oid_validation_regex($allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
$leading_dot_policy = $allow_leading_dot ? OID_DOT_OPTIONAL : OID_DOT_FORBIDDEN; |
$part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
return '@^'.$part_regex.'$@'; |
} |
/** |
* Returns a partial regular expression which matches valid OIDs in dot notation. |
* It can be inserted into regular expressions. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param int $min_len<br /> |
* 0="." and greater will be recognized, but not ""<br /> |
* 1=".2" and greater will be recognized<br /> |
* 2=".2.999" and greater will be recognized (default)<br /> |
* etc. |
* @param boolean $allow_leading_zeroes<br /> |
* true: ".2.0999" will be recognized<br /> |
* false: ".2.0999" won't be recognized (default) |
* @param int $leading_dot_policy<br /> |
* 0 (OID_DOT_FORBIDDEN): forbidden<br /> |
* 1 (OID_DOT_OPTIONAL) : optional (default)<br /> |
* 2 (OID_DOT_REQUIRED) : enforced |
* @return string|false A regular expression which matches OIDs in dot notation |
**/ |
function oid_part_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL) { |
switch ($leading_dot_policy) { |
case 0: // forbidden |
$lead_dot = ''; |
break; |
case 1: // optional |
$lead_dot = '\\.{0,1}'; |
break; |
case 2: // enforced |
$lead_dot = '\\.'; |
break; |
default: |
assert(false); |
return false; |
} |
$lead_zero = $allow_leading_zeroes ? '0*' : ''; |
$zero_till_thirtynine = '(([0-9])|([1-3][0-9]))'; // second arc is limited to 0..39 if root arc is 0..1 |
$singledot_option = ($min_len == 0) && ($leading_dot_policy != OID_DOT_FORBIDDEN) ? '|\\.' : ''; |
$only_root_option = ($min_len <= 1) ? '|('.$lead_dot.$lead_zero.'[0-2])' : ''; |
$regex = ' |
( |
( |
( |
('.$lead_dot.$lead_zero.'[0-1]) |
\\.'.$lead_zero.$zero_till_thirtynine.' |
(\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-2).',} |
)|( |
('.$lead_dot.$lead_zero.'[2]) |
(\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-1).',} |
) |
'.$only_root_option.' |
'.$singledot_option.' |
) |
)'; |
// Remove the indentations which are used to maintain this large regular expression in a human friendly way |
$regex = str_replace("\n", '', $regex); |
$regex = str_replace("\r", '', $regex); |
$regex = str_replace("\t", '', $regex); |
$regex = str_replace(' ', '', $regex); |
return $regex; |
} |
/** |
* Searches all OIDs in $text and outputs them as array. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param string $text<br /> |
* The text to be parsed |
* @param int $min_len<br /> |
* 0="." and greater will be recognized, but not ""<br /> |
* 1=".2" and greater will be recognized<br /> |
* 2=".2.999" and greater will be recognized (default)<br /> |
* etc. |
* @param boolean $allow_leading_zeroes<br /> |
* true: ".2.0999" will be recognized<br /> |
* false: ".2.0999" won't be recognized (default) |
* @param int $leading_dot_policy<br /> |
* 0 (OID_DOT_FORBIDDEN): forbidden<br /> |
* 1 (OID_DOT_OPTIONAL) : optional (default)<br /> |
* 2 (OID_DOT_REQUIRED) : enforced |
* @param boolean $requires_whitespace_delimiters<br /> |
* true: "2.999" will be recognized, as well as " 2.999 " (default)<br /> |
* false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
* @return string[] An array of OIDs in dot notation |
**/ |
function parse_oids($text, $min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
$regex = oid_detection_regex($min_len, $allow_leading_zeroes, $leading_dot_policy, $requires_whitespace_delimiters); |
$matches = array(); |
preg_match_all($regex, $text, $matches); |
return $matches[1]; |
} |
/** |
* Returns a full regular expression for detecting OIDs in dot notation inside a text. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param int $min_len<br /> |
* 0="." and greater will be recognized, but not ""<br /> |
* 1=".2" and greater will be recognized<br /> |
* 2=".2.999" and greater will be recognized (default)<br /> |
* etc. |
* @param boolean $allow_leading_zeroes<br /> |
* true: ".2.0999" will be recognized<br /> |
* false: ".2.0999" won't be recognized (default) |
* @param int $leading_dot_policy<br /> |
* 0 (OID_DOT_FORBIDDEN): forbidden<br /> |
* 1 (OID_DOT_OPTIONAL) : optional (default)<br /> |
* 2 (OID_DOT_REQUIRED) : enforced |
* @param boolean $requires_whitespace_delimiters<br /> |
* true: "2.999" will be recognized, as well as " 2.999 " (default)<br /> |
* false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
* @return string The regular expression |
**/ |
function oid_detection_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
if ($requires_whitespace_delimiters) { |
// A fully qualified regular expression which can be used by preg_match() |
$begin_condition = '(?<=^|\\s)'; |
$end_condition = '(?=\\s|$)'; |
} else { |
// A partial expression which can be used inside another regular expression |
$begin_condition = '(?<![\d])'; |
$end_condition = '(?![\d])'; |
} |
$part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
return '@'.$begin_condition.$part_regex.$end_condition.'@'; |
} |
/** |
* Returns the parent of an OID in dot notation or the OID itself, if it is the root.<br /> |
* Leading dots and leading zeroes are tolerated. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-16 |
* @param string $oid<br /> |
* An OID in dot notation. |
* @return string|false The parent OID in dot notation. |
**/ |
function oid_up($oid) { |
$oid = sanitizeOID($oid, 'auto'); |
if ($oid === false) return false; |
$p = strrpos($oid, '.'); |
if ($p === false) return $oid; |
if ($p == 0) return '.'; |
return substr($oid, 0, $p); |
} |
/** |
* Outputs the depth of an OID. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param string $oid An OID in dot notation (with or without leading dot) |
* @return int The depth of the OID, e.g. 2.999 and .2.999 has the length 2. |
**/ |
function oid_len($oid) { |
if ($oid == '') return 0; |
if ($oid[0] == '.') $oid = substr($oid, 1); |
return substr_count($oid, '.')+1; |
} |
function oid_depth($oid) { |
return oid_len($oid); |
} |
/** |
* Lists all parents of an OID. |
* This function tolerates leading dots. The parent of '.' stays '.'. |
* The OID will not be checked for validity! |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-17 |
* @param string $oid<br /> |
* An OID in dot notation. |
* @return string[] An array with all parent OIDs. |
**/ |
function oid_parents($oid) { |
$parents = array(); |
while (oid_len($oid) > 1) { |
$oid = oid_up($oid); |
$parents[] = $oid; |
} |
if (substr($oid, 0, 1) == '.') $parents[] = '.'; |
return $parents; |
} |
/* |
assert(oid_parents('.1.2.999') == array('.1.2', '.1', '.')); |
assert(oid_parents('1.2.999') == array('1.2', '1')); |
assert(oid_parents('.') == array('.')); |
assert(oid_parents('') == array()); |
*/ |
/** |
* Sorts an array containing OIDs in dot notation. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-09 |
* @param string[] $ary<br /> |
* An array of OIDs in dot notation.<br /> |
* This array will be changed by this method. |
* @param boolean $output_with_leading_dot<br /> |
* true: The array will be normalized to OIDs with a leading dot. |
* false: The array will be normalized to OIDs without a leading dot. (default) |
**/ |
function oidSort(&$ary, $output_with_leading_dot=false) { |
$out = array(); |
$none = $output_with_leading_dot ? '.' : ''; |
$d = array(); |
$oid = null; |
foreach ($ary as &$oid) { |
if (($oid == '') || ($oid == '.')) { |
$out[] = $none; |
} else { |
$oid = sanitizeOID($oid, 'auto'); // strike leading zeroes |
$bry = explode('.', $oid, 2); |
$firstarc = $bry[0]; |
$rest = (isset($bry[1])) ? $bry[1] : ''; |
$d[$firstarc][] = $rest; |
} |
} |
unset($oid); |
ksort($d); |
$data = null; |
foreach ($d as $firstarc => &$data) { |
oidSort($data); |
foreach ($data as &$rest) { |
$out[] = ($output_with_leading_dot ? '.' : '')."$firstarc" . (($rest != $none) ? ".$rest" : ''); |
} |
} |
unset($data); |
$ary = $out; |
} |
/** |
* Checks if two OIDs in dot-notation are equal |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-05-27 |
* @param string $oidA<br /> |
* First OID |
* @param string $oidB<br /> |
* Second OID |
* @return boolean|null True if the OIDs are equal, null if one of the OIDs are invalid |
**/ |
function oid_dotnotation_equal($oidA, $oidB) { |
$oidA = sanitizeOID($oidA, false); |
if ($oidA === false) return null; |
$oidB = sanitizeOID($oidB, false); |
if ($oidB === false) return null; |
return $oidA === $oidB; |
} |
/** |
* Removes leading zeroes from an OID in dot notation. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2015-08-17 |
* @param string $oid<br /> |
* An OID in dot notation. |
* @param boolean $leading_dot<br /> |
* true: The OID is valid, if it contains a leading dot.<br /> |
* false (default): The OID is valid, if it does not contain a leading dot. |
* 'auto: Allow both |
* @return string|false The OID without leading dots, or <code>false</code> if the OID is syntactically wrong. |
**/ |
$oid_sanitize_cache = array(); |
function sanitizeOID($oid, $leading_dot=false) { |
if ($leading_dot) $leading_dot = substr($oid,0,1) == '.'; |
// We are using a cache, since this function is used very often by OIDplus |
global $oid_sanitize_cache; |
$v = ($leading_dot ? 'T' : 'F').$oid; |
if (isset($oid_sanitize_cache[$v])) return $oid_sanitize_cache[$v]; |
if ($leading_dot) { |
if ($oid == '.') return ''; |
} else { |
if ($oid == '') return ''; |
} |
$out = ''; |
$ary = explode('.', $oid); |
foreach ($ary as $n => &$a) { |
if (($leading_dot) && ($n == 0)) { |
if ($a != '') return false; |
continue; |
} |
if (!ctype_digit($a)) return false; // does contain something other than digits |
// strike leading zeroes |
$a = preg_replace("@^0+@", '', $a); |
if ($a == '') $a = 0; |
if (($leading_dot) || ($n != 0)) $out .= '.'; |
$out .= $a; |
} |
unset($a); |
unset($ary); |
$oid_sanitize_cache[$v] = $out; |
return $out; |
} |
/** |
* Shows the top arc of an OID. |
* This function tolerates leading dots. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-16 |
* @param string $oid<br /> |
* An OID in dot notation. |
* @return string|false The top arc of the OID or empty string if it is already the root ('.') |
**/ |
function oid_toparc($oid) { |
$leadingdot = substr($oid,0,1) == '.'; |
$oid = sanitizeOID($oid, $leadingdot); |
if ($oid === false) return false; |
if (!$leadingdot) $oid = '.'.$oid; |
$p = strrpos($oid, '.'); |
if ($p === false) return false; |
$r = substr($oid, $p+1); |
if ($leadingdot) { |
# if ($r == '') return '.'; |
return $r; |
} else { |
return substr($r, 1); |
} |
} |
/** |
* Calculates the distance between two OIDs. |
* This function tolerates leading dots and leading zeroes. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-20 |
* @param string $a<br /> |
* An OID. |
* @param string $b<br /> |
* An OID. |
* @return int|false false if both OIDs do not have a child-parent or parent-child relation, e.g. oid_distance('2.999.1.2.3', '2.999.4.5') = false, or if one of the OIDs is syntactially invalid<br /> |
* >0 if $a is more specific than $b , e.g. oid_distance('2.999.1.2', '2.999') = 2<br /> |
* <0 if $a is more common than $b , e.g. oid_distance('2.999', '2.999.1.2') = -2 |
**/ |
function oid_distance($a, $b) { |
if (substr($a,0,1) == '.') $a = substr($a,1); |
if (substr($b,0,1) == '.') $b = substr($b,1); |
$a = sanitizeOID($a, false); |
if ($a === false) return false; |
$b = sanitizeOID($b, false); |
if ($b === false) return false; |
$ary = explode('.', $a); |
$bry = explode('.', $b); |
$min_len = min(count($ary), count($bry)); |
for ($i=0; $i<$min_len; $i++) { |
if ($ary[$i] != $bry[$i]) return false; |
} |
return count($ary) - count($bry); |
} |
/* |
assert(oid_distance('2.999.1.2.3', '2.999.4.5') === false); |
assert(oid_distance('2.999.1.2', '2.999') === 2); |
assert(oid_distance('2.999', '2.999.1.2') === -2); |
*/ |
/** |
* Adds a leading dot to an OID. |
* Leading zeroes are tolerated. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-20 |
* @param string $oid<br /> |
* An OID. |
* @return string|false The OID with a leading dot or false if the OID is syntactially wrong. |
**/ |
function oid_add_leading_dot($oid) { |
$oid = sanitizeOID($oid, 'auto'); |
if ($oid === false) return false; |
if ($oid[0] != '.') $oid = '.'.$oid; |
return $oid; |
} |
/** |
* Removes a leading dot to an OID. |
* Leading zeroes are tolerated. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-20 |
* @param string $oid<br /> |
* An OID. |
* @return string|false The OID without a leading dot or false if the OID is syntactially wrong. |
**/ |
function oid_remove_leading_dot($oid) { |
$oid = sanitizeOID($oid, 'auto'); |
if ($oid === false) return false; |
if (substr($oid,0,1) == '.') $oid = substr($oid, 1); |
return $oid; |
} |
/** |
* Find the common ancestor of two or more OIDs |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-05-27 |
* @param string[] $oids<br /> |
* An array of multiple OIDs, e.g. 2.999.1 and 2.999.2.3.4 |
* @return string|false The common ancestor, e.g. 2.999, or false if there is no common ancestor. |
**/ |
function oid_common_ancestor(array $oids) { |
$shared = array(); |
if (!is_array($oids)) return false; |
if (count($oids) === 0) return false; |
foreach ($oids as &$oid) { |
$oid = sanitizeOID($oid, false); |
if ($oid === false) return false; |
$oid = explode('.', $oid); |
} |
$max_ok = strlen($oids[0]); |
for ($i=1; $i<count($oids); $i++) { |
for ($j=0; $j<min(strlen($oids[$i]),strlen($oids[0])); $j++) { |
if ($oids[$i][$j] != $oids[0][$j]) { |
if ($j < $max_ok) $max_ok = $j; |
break; |
} |
} |
if ($j < $max_ok) $max_ok = $j; |
} |
$out = array(); |
for ($i=0; $i<$max_ok; $i++) { |
$out[] = $oids[0][$i]; |
} |
return implode('.', $out); |
} |
/* |
assert(oid_shared_ancestor(array('2.999.4.5.3', '2.999.4.5')) === "2.999.4.5"); |
assert(oid_shared_ancestor(array('2.999.4.5', '2.999.4.5.3')) === "2.999.4.5"); |
assert(oid_shared_ancestor(array('2.999.1.2.3', '2.999.4.5')) === "2.999"); |
*/ |
# === OID-IRI NOTATION FUNCTIONS === |
if (!function_exists('mb_ord')) { |
# http://stackoverflow.com/a/24755772/3544341 |
function mb_ord($char, $encoding = 'UTF-8') { |
if ($encoding === 'UCS-4BE') { |
list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char); |
return $ord; |
} else { |
return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE'); |
} |
} |
} |
function iri_char_valid($c, $firstchar, $lastchar) { |
// see Rec. ITU-T X.660, clause 7.5 |
if (($firstchar || $lastchar) && ($c == '-')) return false; |
if ($c == '-') return true; |
if ($c == '.') return true; |
if ($c == '_') return true; |
if ($c == '~') return true; |
if (($c >= '0') && ($c <= '9') && (!$firstchar)) return true; |
if (($c >= 'A') && ($c <= 'Z')) return true; |
if (($c >= 'a') && ($c <= 'z')) return true; |
$v = mb_ord($c); |
if (($v >= 0x000000A0) && ($v <= 0x0000DFFE)) return true; |
if (($v >= 0x0000F900) && ($v <= 0x0000FDCF)) return true; |
if (($v >= 0x0000FDF0) && ($v <= 0x0000FFEF)) return true; |
if (($v >= 0x00010000) && ($v <= 0x0001FFFD)) return true; |
if (($v >= 0x00020000) && ($v <= 0x0002FFFD)) return true; |
if (($v >= 0x00030000) && ($v <= 0x0003FFFD)) return true; |
if (($v >= 0x00040000) && ($v <= 0x0004FFFD)) return true; |
if (($v >= 0x00050000) && ($v <= 0x0005FFFD)) return true; |
if (($v >= 0x00060000) && ($v <= 0x0006FFFD)) return true; |
if (($v >= 0x00070000) && ($v <= 0x0007FFFD)) return true; |
if (($v >= 0x00080000) && ($v <= 0x0008FFFD)) return true; |
if (($v >= 0x00090000) && ($v <= 0x0009FFFD)) return true; |
if (($v >= 0x000A0000) && ($v <= 0x000AFFFD)) return true; |
if (($v >= 0x000B0000) && ($v <= 0x000BFFFD)) return true; |
if (($v >= 0x000C0000) && ($v <= 0x000CFFFD)) return true; |
if (($v >= 0x000D0000) && ($v <= 0x000DFFFD)) return true; |
if (($v >= 0x000E1000) && ($v <= 0x000EFFFD)) return true; |
// Note: Rec. ITU-T X.660, clause 7.5.3 would also forbid ranges which are marked in ISO/IEC 10646 as "(This position shall not be used)" |
// But tool implementers should be tolerate them, since these limitations can be removed in future. |
return false; |
} |
function iri_arc_valid($arc, $allow_numeric=true) { |
if ($arc == '') return false; |
$m = array(); |
if ($allow_numeric && preg_match('@^(\\d+)$@', $arc, $m)) return true; # numeric arc |
// Question: Should we strip RTL/LTR characters? |
if (mb_substr($arc, 2, 2) == '--') return false; // see Rec. ITU-T X.660, clause 7.5.4 |
$array = array(); |
preg_match_all('/./u', $arc, $array, PREG_SET_ORDER); |
$len = count($array); |
foreach ($array as $i => $char) { |
if (!iri_char_valid($char[0], $i==0, $i==$len-1)) return false; |
} |
return true; |
} |
/** |
* Checks if an IRI identifier is valid or not. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-17 |
* @param string $iri<br /> |
* An OID in OID-IRI notation, e.g. /Example/test |
* @return boolean true if the IRI identifier is valid. |
**/ |
function iri_valid($iri) { |
if ($iri == '/') return true; // OK? |
if (substr($iri, 0, 1) != '/') return false; |
$ary = explode('/', $iri); |
array_shift($ary); |
foreach ($ary as $a) { |
if (!iri_arc_valid($a)) return false; |
} |
return true; |
} |
/* |
assert(iri_arc_valid('ABCDEF')); |
assert(!iri_arc_valid('-ABCDEF')); |
assert(!iri_arc_valid('ABCDEF-')); |
assert(!iri_arc_valid(' ABCDEF')); |
assert(!iri_arc_valid('2 ABCDEF')); |
assert(!iri_arc_valid('')); |
assert(!iri_valid('')); |
assert(iri_valid('/')); |
assert(iri_valid('/hello/world')); |
assert(iri_valid('/123/world')); |
assert(!iri_valid('/hello/0world')); |
assert(!iri_valid('/hello/xo--test')); |
assert(!iri_valid('/hello/-super-/sd')); |
*/ |
/** |
* Returns an associative array in the form 'ASN.1' => '/2/1' . |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2018-01-05 |
* @see http://itu.int/go/X660 |
* @return array<string,string> An associative array in the form 'ASN.1' => '/2/1' . |
**/ |
function iri_get_long_arcs() { |
$iri_long_arcs = array(); |
$iri_long_arcs['ASN.1'] = '/2/1'; |
$iri_long_arcs['Country'] = '/2/16'; |
$iri_long_arcs['International-Organizations'] = '/2/23'; |
$iri_long_arcs['UUID'] = '/2/25'; |
$iri_long_arcs['Tag-Based'] = '/2/27'; |
$iri_long_arcs['BIP'] = '/2/41'; |
$iri_long_arcs['Telebiometrics'] = '/2/42'; |
$iri_long_arcs['Cybersecurity'] = '/2/48'; |
$iri_long_arcs['Alerting'] = '/2/49'; |
$iri_long_arcs['OIDResolutionSystem'] = '/2/50'; |
$iri_long_arcs['GS1'] = '/2/51'; |
$iri_long_arcs['Example'] = '/2/999'; // English |
$iri_long_arcs['Exemple'] = '/2/999'; // French |
$iri_long_arcs['Ejemplo'] = '/2/999'; // Spanish |
$iri_long_arcs["\u{0627}\u{0644}\u{0645}\u{062B}\u{0627}\u{0644}"] = '/2/999'; // Arabic |
$iri_long_arcs["\u{8303}\u{4F8B}"] = '/2/999'; // Chinese |
$iri_long_arcs["\u{041F}\u{0440}\u{0438}\u{043C}\u{0435}\u{0440}"] = '/2/999'; // Russian |
$iri_long_arcs["\u{C608}\u{C81C}"] = '/2/999'; // Korean |
$iri_long_arcs["\u{4F8B}"] = '/2/999'; // Japanese |
$iri_long_arcs['Beispiel'] = '/2/999'; // German |
return $iri_long_arcs; |
} |
/** |
* Tries to shorten/simplify an IRI by applying "long arcs", e.g. /2/999/123 -> /Example/123 . |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-05-22 |
* @param string $iri<br /> |
* An OID in OID-IRI notation, e.g. /Example/test |
* @return string|false The modified IRI. |
**/ |
function iri_add_longarcs($iri) { |
$iri_long_arcs = iri_get_long_arcs(); |
if (!iri_valid($iri)) return false; |
$ary = explode('/', $iri); |
$ary_number_iri = $ary; |
if ($ary_number_iri[1] == 'Joint-ISO-ITU-T') $ary_number_iri[1] = '2'; |
$number_iri = implode('/', $ary_number_iri); |
foreach ($iri_long_arcs as $cur_longarc => $cur_iri) { |
assert(iri_valid($cur_iri)); |
if (strpos($number_iri.'/', $cur_iri.'/') === 0) { |
$cnt = substr_count($cur_iri, '/'); |
for ($i=1; $i<$cnt; $i++) { |
array_shift($ary); |
} |
$ary[0] = ''; |
$ary[1] = $cur_longarc; |
$iri = implode('/', $ary); |
break; |
} |
} |
return $iri; |
} |
/* |
assert(iri_add_longarcs('/2/999/123') === '/Example/123'); |
*/ |
# === FUNCTIONS FOR OIDS IN ASN.1 NOTATION === |
/** |
* Checks if an ASN.1 identifier is valid. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-05-22 |
* @param string $id<br /> |
* An ASN.1 identifier, e.g. "example". Not "example(99)" or "99" and not a path like "{ 2 999 }" |
* Note: Use asn1_path_valid() for validating a whole ASN.1 notation path. |
* @return boolean true, if the identifier is valid: It begins with an lowercase letter and contains only 0-9, a-z, A-Z and "-" |
**/ |
function oid_id_is_valid($id) { |
// see Rec. ITU-T X.660 | ISO/IEC 9834-1, clause 7.7 |
// and Rec. ITU-T X.680 | ISO/IEC 8824-1, clause 12.3 |
if (substr($id,-1,1) == '-') return false; |
if (strstr($id,'--')) return false; |
return preg_match('/^([a-z][a-zA-Z0-9-]*)$/', $id) != 0; |
} |
/** |
* Checks if the ASN.1 notation of an OID is valid. |
* This function does not tolerate leading zeros. |
* This function will fail (return false) if there are unresolved symbols, e.g. {iso test} is not valid while { iso 123 } is valid. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-17 |
* @param string $asn1<br /> |
* An OID in ASN.1 notation. |
* @return boolean true if the identifier is valid. |
**/ |
function asn1_path_valid($asn1) { |
return asn1_to_dot($asn1) != false; |
} |
/** |
* Returns an array of standardized ASN.1 alphanumeric identifiers which do not require a numeric identifier, e.g. { 2 example } |
* The array has the form '0.0.a' -> '0.0.1' |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2019-03-25 |
* @see http://www.oid-info.com/name-forms.htm |
* @return array<string,string> Associative array of standardized ASN.1 alphanumeric identifiers |
**/ |
function asn1_get_standardized_array() { |
// Taken from oid-info.com |
// http://www.oid-info.com/name-forms.htm |
$standardized = array(); |
$standardized['itu-t'] = '0'; |
$standardized['ccitt'] = '0'; |
$standardized['iso'] = '1'; |
$standardized['joint-iso-itu-t'] = '2'; |
$standardized['joint-iso-ccitt'] = '2'; |
$standardized['0.recommendation'] = '0.0'; |
$standardized['0.0.a'] = '0.0.1'; |
$standardized['0.0.b'] = '0.0.2'; |
$standardized['0.0.c'] = '0.0.3'; |
$standardized['0.0.d'] = '0.0.4'; |
$standardized['0.0.e'] = '0.0.5'; |
$standardized['0.0.f'] = '0.0.6'; |
$standardized['0.0.g'] = '0.0.7'; |
$standardized['0.0.h'] = '0.0.8'; |
$standardized['0.0.i'] = '0.0.9'; |
$standardized['0.0.j'] = '0.0.10'; |
$standardized['0.0.k'] = '0.0.11'; |
$standardized['0.0.l'] = '0.0.12'; |
$standardized['0.0.m'] = '0.0.13'; |
$standardized['0.0.n'] = '0.0.14'; |
$standardized['0.0.o'] = '0.0.15'; |
$standardized['0.0.p'] = '0.0.16'; |
$standardized['0.0.q'] = '0.0.17'; |
$standardized['0.0.r'] = '0.0.18'; |
$standardized['0.0.s'] = '0.0.19'; |
$standardized['0.0.t'] = '0.0.20'; |
$standardized['0.0.u'] = '0.0.21'; |
$standardized['0.0.v'] = '0.0.22'; |
$standardized['0.0.w'] = '0.0.23'; // actually, this OID does not exist |
$standardized['0.0.x'] = '0.0.24'; |
$standardized['0.0.y'] = '0.0.25'; |
$standardized['0.0.z'] = '0.0.26'; |
$standardized['0.question'] = '0.1'; |
$standardized['0.administration'] = '0.2'; |
$standardized['0.network-operator'] = '0.3'; |
$standardized['0.identified-organization'] = '0.4'; |
$standardized['1.standard'] = '1.0'; |
$standardized['1.registration-authority'] = '1.1'; |
$standardized['1.member-body'] = '1.2'; |
$standardized['1.identified-organization'] = '1.3'; |
return $standardized; |
} |
/** |
* Converts an OID in ASN.1 notation into an OID in dot notation and tries to resolve well-known identifiers.<br /> |
* e.g. {joint-iso-itu-t(2) example(999) 1 2 3} --> 2.999.1.2.3<br /> |
* e.g. {iso 3} --> 1.3 |
* This function does not tolerate leading zeros. |
* This function will fail (return false) if there are unresolved symbols, e.g. {iso test} will not be resolved to 1.test |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2014-12-17 |
* @param string $asn<br /> |
* An OID in ASN.1 notation. |
* @return string|false An OID in dot notation without leading dot or false if the path is invalid. |
**/ |
function asn1_to_dot($asn) { |
$standardized = asn1_get_standardized_array(); |
// Clean up |
$count = -1; |
$asn = preg_replace('@^\\{(.+)\\}$@', '\\1', $asn, -1, $count); |
if ($count == 0) return false; // { and } are required. The ASN.1 path will NOT be trimmed by this function |
// If identifier is set, apply it (no check if it overrides a standardized identifier) |
$asn = preg_replace('|\s*([a-z][a-zA-Z0-9-]*)\s*\((\d+)\)|', ' \\2', $asn); |
$asn = trim($asn); |
// Set dots |
$asn = preg_replace('|\s+|', '.', $asn); |
// Apply standardized identifiers (case sensitive) |
$asn .= '.'; |
foreach ($standardized as $s => $r) { |
$asn = preg_replace("@^".preg_quote($s,"@")."@", $r, $asn); |
} |
$asn = substr($asn, 0, strlen($asn)-1); |
// Check if all numbers are OK |
// -> every arc must be resolved |
// -> numeric arcs must not have a leading zero |
// -> invalid stuff will be recognized, e.g. a "(1)" without an identifier in front of it |
$ary = explode('.', $asn); |
foreach ($ary as $a) { |
$m = array(); |
if (!preg_match('@^(0|([1-9]\\d*))$@', $a, $m)) return false; |
} |
return $asn; |
} |
/* |
assert(asn1_to_dot('{2 999 (1)}') == false); |
assert(asn1_to_dot('{2 999 test}') == false); |
assert(asn1_to_dot('{2 999 1}') == '2.999.1'); |
assert(asn1_to_dot(' {2 999 1} ') == false); |
assert(asn1_to_dot('2 999 1') == false); |
assert(asn1_to_dot('{2 999 01}') == false); |
assert(asn1_to_dot('{ 0 question 123 }') == '0.1.123'); |
assert(asn1_to_dot('{ iso }') == '1'); |
assert(asn1_to_dot('{ iso(1) }') == '1'); |
assert(asn1_to_dot('{ iso(2) }') == '2'); |
assert(asn1_to_dot('{ iso 3 }') == '1.3'); |
*/ |
/** |
* Gets the last numeric identifier of an ASN.1 notation OID. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-06-11 |
* @param string $asn1id<br /> |
* An ASN.1 identifier string, e.g. { 2 example(999) test(1) } |
* @return int|false The last numeric identifier arc, e.g. "1" or false if the ID is invalid |
**/ |
function asn1_last_identifier($asn1id) { |
$asn1id = preg_replace('@\(\s*\d+\s*\)@', '', $asn1id); |
$asn1id = trim(str_replace(array('{', '}', "\t"), ' ', $asn1id)); |
$ary = explode(' ', $asn1id); |
$asn1id = $ary[count($ary)-1]; |
return preg_match('#[^0-9]#',$asn1id) ? (int)$asn1id : false; |
} |
/** |
* "Soft corrects" an invalid ASN.1 identifier.<br /> |
* Attention, by "soft correcting" the ID, it is not authoritative anymore, and might not be able to be resolved by ORS. |
* @author Daniel Marschall, ViaThinkSoft |
* @version 2020-05-22 |
* @param string $id<br /> |
* An ASN.1 identifier. |
* @param boolean $append_id_prefix<br /> |
* true (default): If the identifier doesn't start with a-Z, the problem will be solved by prepending "id-" to the identifier.<br /> |
* false: If the identifier doesn't start with a-Z, then the problem cannot be solved (method returns empty string). |
* @return string The "soft corrected" ASN.1 identifier.<br /> |
* Invalid characters will be removed.<br /> |
* Uncorrectable start elements (0-9 or "-") will be either removed or solved by prepending "id-" (see <code>$append_id_prefix</code>)<br /> |
* If the identifier begins with an upper case letter, the letter will be converted into lower case. |
**/ |
function oid_soft_correct_id($id, $append_id_prefix = true) { |
// Convert "_" to "-" |
$id = str_replace('_', '-', $id); |
// Convert "--" to "-" |
$id = str_replace('--', '-', $id); |
// Remove invalid characters |
$id = preg_replace('/[^a-zA-Z0-9-]+/', '', $id); |
// Remove uncorrectable start elements (0-9 or "-") |
if ($append_id_prefix) { |
$id = preg_replace('/^([^a-zA-Z]+)/', 'id-$1', $id); |
} else { |
$id = preg_replace('/^([^a-zA-Z]+)/', '', $id); |
} |
// "Correct" upper case beginning letter by converting it to lower case |
if (preg_match('/^[A-Z]/', $id)) { |
$id = strtolower($id[0]) . substr($id, 1); |
} |
return $id; |
} |
/trunk/simplexml_supplement.inc.php |
---|
0,0 → 1,329 |
<?php |
/* |
* PHP SimpleXML-Supplement |
* Copyright 2020 - 2021 Daniel Marschall, ViaThinkSoft |
* Revision 2021-05-25 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
// ======== ATTENTION, PLEASE READ ======== |
// This supplement script was created to support rare PHP installations that |
// do not contain SimpleXML, for example at PHP you need to explicitly |
// install the package "php-xml" if you want to have SimpleXML (In the PHP |
// documentation, it is written that SimpleXML is available to all, which is |
// not true). |
// |
// Beware that the supplement behaves differently than the real SimpleXML! |
// (If you know how to improve this, please feel free to send me a patch) |
// |
// Just a few differences towards the original SimpleXML |
// - print_r() looks different |
// - The supplement requires that an XML string begins with "<!DOCTYPE" or "<?xml", |
// otherwise, the first element will not be stripped away |
// - The supplement is slow because of regular expressions |
// - Many functions like "asXML" are not implemented |
// - There might be other incompatibilities |
// |
// So, if you want to use the SimpleXML supplement, then please carefully |
// test it with your application if it works. |
// ======================================== |
if (!function_exists('simplexml_load_string')) { |
// We cannot store the number 0, 1, 2, ... as items in the SimpleXMLElement, because PHP 7.0 had a bug |
// that prevented /get_object_vars() from working correctly |
// https://stackoverflow.com/questions/46000541/get-object-vars-returning-different-results-depending-on-php-version |
// https://stackoverflow.com/questions/4914376/failed-to-get-dynamic-instance-variables-via-phps-reflection/4914405#comment76610293_4914405 |
define('SIMPLEXML_SUPPLEMENT_MAGIC', '_SIMPLEXML_SUPPLEMENT_IDX_'); |
function _simplexml_supplement_isnumeric($x) { |
return substr($x,0,strlen(SIMPLEXML_SUPPLEMENT_MAGIC)) === SIMPLEXML_SUPPLEMENT_MAGIC; |
} |
function _simplexml_supplement_getnumber($x) { |
return (int)substr($x,strlen(SIMPLEXML_SUPPLEMENT_MAGIC)); |
} |
function _simplexml_supplement_addnumberprefix($x) { |
return SIMPLEXML_SUPPLEMENT_MAGIC.$x; |
} |
// We may not store the fields "position" and "attrs" in the SimpleXMLElement object, |
// otherweise the typecast SimpleXMLElement=>array will include them |
$_simplexml_supplement_properties = array(); |
function simplexml_load_file($file): SimpleXMLElement { |
return simplexml_load_string(file_get_contents($file)); |
} |
function simplexml_load_string($testxml): SimpleXMLElement { |
$out = new SimpleXMLElement(); /** @phpstan-ignore-line */ |
$testxml = preg_replace('@<!\\-\\-.+\\-\\->@','',$testxml); // remove comments |
$testxml = preg_replace('@<([^>\\s]+)\\s*/>@smU','<\\1></\\1>',$testxml); // <x/> => <x></x> |
if ((stripos($testxml, '<?xml') !== false) || (stripos($testxml, '<!doctype') !== false)) { |
$testxml = preg_replace('@<\\?.+\\?>@','',$testxml); |
$testxml = preg_replace('@<!doctype.+>@i','',$testxml); |
$m = array(); |
preg_match('@<(\\S+?)[^>]*>(.*)</\\1>@smU',$testxml,$m); // find root element |
$root_element = $m[1]; |
} else { |
$root_element = null; |
} |
$m = array(); |
preg_match_all('@<(\\S+?)([^>]*)>(.*)</\\1>@smU', $testxml, $m, PREG_SET_ORDER); |
foreach ($m as $n) { |
$name = $n[1]; |
$other = $n[2]; |
$val = $n[3]; |
$val = str_replace('<![CDATA[', '', $val); |
$val = str_replace(']]>', '', $val); |
$val = trim($val); |
$new = $out->addChild($name, $val); |
$m2 = array(); |
preg_match_all('@(\S+)=\\"([^\\"]+)\\"@smU', $other, $m2, PREG_SET_ORDER); |
foreach ($m2 as $n2) { |
$att_name = $n2[1]; |
$att_val = $n2[2]; |
$new->addAttribute($att_name, $att_val); |
} |
} |
if (!is_null($root_element)) { |
$out = $out->$root_element; |
} |
return $out; |
} |
class SimpleXMLElement implements ArrayAccess, Iterator { |
function __destruct() { |
global $_simplexml_supplement_properties; |
unset($_simplexml_supplement_properties[spl_object_hash($this)]); |
} |
public function addAttribute($name, $val) { |
global $_simplexml_supplement_properties; |
$_simplexml_supplement_properties[spl_object_hash($this)]['attrs'][$name] = $val; |
} |
public function attributes() { |
global $_simplexml_supplement_properties; |
return $_simplexml_supplement_properties[spl_object_hash($this)]['attrs']; |
} |
public function isSupplement() { |
return true; |
} |
public function __construct($val=null) { |
global $_simplexml_supplement_properties; |
$_simplexml_supplement_properties[spl_object_hash($this)] = array( |
"position" => 0, |
"attrs" => array() |
); |
if (!is_null($val)) { |
$this->{_simplexml_supplement_addnumberprefix(0)} = $val; |
} |
} |
public function isArray() { |
$vars = get_object_vars($this); |
$max = -1; |
foreach ($vars as $x => $dummy) { |
if (!_simplexml_supplement_isnumeric($x)) { |
$max = -1; |
break; |
} else { |
$num = _simplexml_supplement_getnumber($x); |
if ($num > $max) $max = $num; |
} |
} |
return $max > 0; |
} |
public function addToArray($val) { |
$vars = get_object_vars($this); |
$max = -1; |
foreach ($vars as $x => $dummy) { |
if (!_simplexml_supplement_isnumeric($x)) { |
$max = -1; |
break; |
} else { |
$num = _simplexml_supplement_getnumber($x); |
if ($num > $max) $max = $num; |
} |
} |
$max++; |
$this->{_simplexml_supplement_addnumberprefix($max)} = $val; |
} |
public function __toString() { |
$data = get_object_vars($this); |
if (is_array($data)) { |
if (isset($data[_simplexml_supplement_addnumberprefix(0)])) { |
return $data[_simplexml_supplement_addnumberprefix(0)]; |
} else { |
return ''; |
} |
} else { |
return $data; |
} |
} |
public function offsetExists($offset) { |
return isset($this->$offset); |
} |
public function offsetGet($offset) { |
return $this->$offset; |
} |
public function offsetSet($offset, $value) { |
$this->$offset = $value; |
} |
public function offsetUnset($offset) { |
unset($this->$offset); |
} |
public function __get($name) { |
// Output nothing |
return new SimpleXMLElement(); /** @phpstan-ignore-line */ |
} |
public function addChild($name, $val=null) { |
global $_simplexml_supplement_properties; |
if ($val == null) $val = new SimpleXMLElement(); /** @phpstan-ignore-line */ |
if ((substr(trim($val),0,1) === '<') || (trim($val) == '')) { |
$val = simplexml_load_string($val); |
} |
$data = get_object_vars($this); |
if (!isset($data[$name])) { |
if ($val instanceof SimpleXMLElement) { |
$this->$name = $val; |
} else { |
$this->$name = new SimpleXMLElement($val); |
} |
} else { |
if (!($val instanceof SimpleXMLElement)) { |
$val = new SimpleXMLElement($val); |
} |
if ($data[$name]->isArray()) { |
$data[$name]->addToArray($val); |
} else { |
$tmp = new SimpleXMLElement(); /** @phpstan-ignore-line */ |
$tmp->addToArray($data[$name]); |
$tmp->addToArray($val); |
$this->$name = $tmp; |
$_simplexml_supplement_properties[spl_object_hash($this)]['attrs'] = array(); |
} |
return $val; |
} |
return $this->$name; |
} |
public function rewind() { |
global $_simplexml_supplement_properties; |
$_simplexml_supplement_properties[spl_object_hash($this)]['position'] = 0; |
} |
public function current() { |
global $_simplexml_supplement_properties; |
$vars = get_object_vars($this); |
$cnt = 0; |
foreach ($vars as $x => $dummy) { |
if (($dummy instanceof SimpleXMLElement) && !_simplexml_supplement_isnumeric($x) && $dummy->isArray()) { |
$vars2 = get_object_vars($dummy); |
foreach ($vars2 as $x2 => $dummy2) { |
if ($cnt == $_simplexml_supplement_properties[spl_object_hash($this)]['position']) { |
if ($dummy2 instanceof SimpleXMLElement) { |
return $dummy2; |
} else { |
return new SimpleXMLElement($dummy2); |
} |
} |
$cnt++; |
} |
} else { |
if ($cnt == $_simplexml_supplement_properties[spl_object_hash($this)]['position']) { |
if ($dummy instanceof SimpleXMLElement) { |
return $dummy; |
} else { |
return new SimpleXMLElement($dummy); |
} |
} |
$cnt++; |
} |
} |
} |
public function key() { |
global $_simplexml_supplement_properties; |
$vars = get_object_vars($this); |
$cnt = 0; |
foreach ($vars as $x => $dummy) { |
if (($dummy instanceof SimpleXMLElement) && !_simplexml_supplement_isnumeric($x) && $dummy->isArray()) { |
$vars2 = get_object_vars($dummy); |
foreach ($vars2 as $x2 => $dummy2) { |
if ($cnt == $_simplexml_supplement_properties[spl_object_hash($this)]['position']) return $x/*sic*/; |
$cnt++; |
} |
} else { |
if ($cnt == $_simplexml_supplement_properties[spl_object_hash($this)]['position']) return $x; |
$cnt++; |
} |
} |
} |
public function next() { |
global $_simplexml_supplement_properties; |
++$_simplexml_supplement_properties[spl_object_hash($this)]['position']; |
} |
public function valid() { |
global $_simplexml_supplement_properties; |
$vars = get_object_vars($this); |
$cnt = 0; |
foreach ($vars as $x => $dummy) { |
if (($dummy instanceof SimpleXMLElement) && !_simplexml_supplement_isnumeric($x) && $dummy->isArray()) { |
$vars2 = get_object_vars($dummy); |
foreach ($vars2 as $x2 => $dummy2) { |
$cnt++; |
} |
} else { |
$cnt++; |
} |
} |
return $_simplexml_supplement_properties[spl_object_hash($this)]['position'] < $cnt; |
} |
} |
} |
/trunk/vtor_get_contents.inc.php |
---|
0,0 → 1,12 |
<?php |
define('UA_NAME', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'); |
function file_get_contents2($url) { |
$out = array(); |
exec("vtor -- wget -q -U ".escapeshellarg(UA_NAME)." -O - ".escapeshellarg($url), $out, $code); |
if ($code != 0) return false; |
return implode("\n", $out); |
} |
?> |
/trunk/x_509_utils.inc.php |
---|
0,0 → 1,403 |
<?php |
/* |
* X.509 Utilities for PHP |
* Copyright 2011-2014 Daniel Marschall, ViaThinkSoft |
* Version 2014-11-17 |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
# define('OPENSSL_EXEC', 'openssl'); |
# define('OPENSSL_EXEC', 'torify openssl'); |
define('OPENSSL_EXEC', 'vtor -cr 1 -- openssl'); |
# ToDo: For every function 2 modes: certFile, certPEM |
function x_509_matching_issuer($cert, $issuer) { |
exec(OPENSSL_EXEC.' verify -purpose any -CApath /dev/null -CAfile '.escapeshellarg($issuer).' '.escapeshellarg($cert), $out, $code); |
$out = implode("\n", $out); |
# Ab 1.0 wird hier ein Errorcode zurückgeliefert |
# if ($code != 0) return false; |
# TODO |
# error 20 at 0 depth lookup:unable to get local issuer certificate |
$chain0_ok = strpos($out, "error 2 at 1 depth lookup:unable to get issuer certificate") !== false; |
$all_ok = substr($out, -2) == 'OK'; |
$ok = $chain0_ok | $all_ok; |
return $ok; |
} |
function x_509_is_crl_file($infile) { # Only PEM files |
$cx = file($infile); |
return trim($cx[0]) == '-----BEGIN X509 CRL-----'; |
} |
function x_509_chain($infile, $CApath) { |
$chain = array(); |
$chain[] = $infile; |
while (true) { |
$out = array(); |
exec(OPENSSL_EXEC.' x509 -issuer_hash -in '.escapeshellarg($infile).' -noout', $out, $code); |
if ($code != 0) return false; |
$hash = $out[0]; |
unset($out); |
# $ary = glob($CApath . $hash . '.*'); |
# $aryr = glob($CApath . $hash . '.r*'); |
$ary = array(); |
$aryr = array(); |
$all_trusted = glob($CApath . '*.pem'); |
foreach ($all_trusted as &$a) { |
if (x_509_is_crl_file($a)) { |
$out = array(); |
exec(OPENSSL_EXEC.' crl -hash -noout -in '.escapeshellarg($a), $out, $code); |
if ($code != 0) return false; |
$this_hash = trim($out[0]); |
unset($out); |
# echo "CRL $a : $this_hash == $hash<br>\n"; |
if ($this_hash == $hash) { |
$aryr[] = $a; |
} |
if ($code != 0) return false; |
} else { |
$out = array(); |
exec(OPENSSL_EXEC.' x509 -subject_hash -noout -in '.escapeshellarg($a), $out, $code); |
if ($code != 0) return false; |
$this_hash = trim($out[0]); |
unset($out); |
# echo "CERT $a : $this_hash == $hash<br>\n"; |
if ($this_hash == $hash) { |
$ary[] = $a; |
} |
} |
} |
$found = false; |
# echo "Searching issuer for $infile... (Hash = $hash)<br>\n"; |
foreach ($ary as &$a) { |
if (in_array($a, $aryr)) continue; |
# echo "Check $a...<br>\n"; |
if (x_509_matching_issuer($infile, $a)) { |
# echo "Found! New file is $a<br>\n"; |
$found = true; |
$infile = $a; |
if (in_array($a, $chain)) { |
# echo "Finished.\n"; |
return $chain; |
} |
$chain[] = $a; |
break; |
} |
} |
if (!$found) { |
# echo "No issuer found!\n"; |
return false; |
} |
} |
} |
function x_509_get_ocsp_uris($infile) { |
exec(OPENSSL_EXEC.' x509 -ocsp_uri -in '.escapeshellarg($infile).' -noout', $out, $code); |
if ($code != 0) return false; |
return $out; |
} |
function x_509_ocsp_check_chain($infile, $CApath) { |
return '(Skipped)'; # TODO: we need caching, otherwise the page is too slow |
$x = x_509_chain($infile, $CApath); |
if ($x === false) { |
return 'Error: Could not complete chain!'; |
} |
# echo 'Chain: '; |
# print_r($x); |
$found_ocsp = false; |
$diag_nonce_err = false; |
$diag_verify_err = false; |
$diag_revoked = false; |
$diag_unknown = false; |
foreach ($x as $n => &$y) { |
if (isset($x[$n+1])) { |
$issuer = $x[$n+1]; |
} else { |
$issuer = $y; // Root |
} |
$uris = x_509_get_ocsp_uris($y); |
foreach ($uris as &$uri) { |
$found_ocsp = true; |
$out = array(); |
$xx = parse_url($uri); |
$host = $xx['host']; |
# $cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CApath ".escapeshellarg($CApath)." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
# TODO: trusted.pem nicht hartcoden |
$cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CAfile ".escapeshellarg($CApath.'/../trusted.pem')." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
#echo $cmd; |
exec($cmd, $out, $code); |
if ($code != 0) { |
if (($out[0] == 'Error querying OCSP responsder') || |
($out[0] == 'Error querying OCSP responder')) { |
# TODO: openssl has a typo 'Error querying OCSP responsder' |
# TODO: why does this error occour for comodo CA? |
return "Error querying OCSP responder (Code $code)"; |
} |
# print_r($out); |
return 'Error: OpenSSL-Exec failure ('.$code.')!'; |
} |
$outc = implode("\n", $out); |
if (strpos($outc, "Response verify OK") === false) $diag_verify_err = true; |
if (strpos($outc, "WARNING: no nonce in response") !== false) $diag_nonce_err = true; |
# We are currently not watching for other warnings (ToDo) |
if (strpos($outc, "$y: unknown") !== false) { |
$diag_unknown = true; |
} else if (strpos($outc, "$y: revoked") !== false) { |
$diag_revoked = true; |
} else if (strpos($outc, "$y: good") === false) { |
#echo "C = $outc<br>\n"; |
#Ã TODO: |
# COMODO sagt |
# C = Responder Error: unauthorized |
# STARTCOM sagt |
# C = Responder Error: malformedrequest |
return "Error: Unexpected OCSP state! ($outc)"; |
} |
# print_r($out); |
unset($out); |
} |
} |
# echo "Found OCSP = ".($found_ocsp ? 1 : 0)."\n"; |
# echo "Diag Nonce Error = ".($diag_nonce_err ? 1 : 0)."\n"; |
# echo "Diag Verify Error = ".($diag_verify_err ? 1 : 0)."\n"; |
# echo "Diag Revoked Error = ".($diag_revoked ? 1 : 0)."\n"; |
# echo "Diag Unknown Error = ".($diag_unknown ? 1 : 0)."\n"; |
if (!$found_ocsp) { |
return 'No OCSP responders found in chain.'; |
} |
if ($diag_verify_err) { |
return 'Error: OCSP Verification failure!'; |
} |
if ($diag_revoked) { |
return 'Error: Some certs are revoked!'; |
} |
if ($diag_unknown) { |
return 'Warning: Some certs have unknown state!'; |
} |
if ($diag_nonce_err) { |
return 'OK, but NONCE missing'; |
} |
return 'OK'; |
} |
function _opensslVerify($cert, $mode = 0, $crl_mode = 0) { |
# mode |
# 0 = cert is a file |
# 1 = cert is pem string |
# crl_mode |
# 0 = no crl check |
# 1 = 1 crl check |
# 2 = all crl check |
$params = ''; |
if ($crl_mode == 0) { |
$params = ''; |
} else if ($crl_mode == 1) { |
$params = '-crl_check '; |
} else if ($crl_mode == 2) { |
$params = '-crl_check_all '; |
} else { |
return false; |
} |
if ($mode == 0) { |
# $cmd = OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/').' '.escapeshellarg($cert); |
$cmd = OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem').' '.escapeshellarg($cert); |
} else if ($mode == 1) { |
# $cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/'); |
$cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem'); |
} else { |
return false; |
} |
$out = array(); |
exec($cmd, $out, $code); |
if ($code != 0) return false; |
return $out; |
} |
function opensslVerify($cert, $mode = 0) { |
# 0 = cert is a file |
# 1 = cert is pem string |
$out = _opensslVerify($cert, $mode, 0); |
if ($out === false) return 'Internal error'; |
$outtext = implode("\n", $out); |
$out_crl = _opensslVerify($cert, $mode, 2); |
if ($out_crl === false) return 'Internal error'; |
$outtext_crl = implode("\n", $out_crl); |
if (strpos($outtext, "unable to get local issuer certificate") !== false) { |
return 'CA unknown'; |
} else if (strpos($outtext, "certificate signature failure") !== false) { |
return 'Fraudulent!'; |
} |
$stat_expired = (strpos($outtext, "certificate has expired") !== false); |
$stat_revoked = (strpos($outtext_crl, "certificate revoked") !== false); |
# (ToDo) We are currently not looking for warnings |
# $stat_crl_expired = (strpos($outtext_crl, "CRL has expired") !== false); |
if ($stat_expired && $stat_revoked) { |
return 'Expired & Revoked'; |
} else if ($stat_revoked) { |
return 'Revoked'; |
} else if ($stat_expired) { |
return 'Expired'; |
} |
if (strpos($out[0], ': OK') !== false) { |
return 'Verified'; |
} |
return 'Unknown error'; |
} |
function getTextdump($cert, $mode = 0, $format = 0) { |
# mode |
# 0 = cert is a file |
# 1 = cert is pem string |
# format |
# 0 = normal |
# 1 = nameopt |
if ($format == 0) { |
$params = ''; |
} else if ($format == 1) { |
$params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
} else { |
return false; |
} |
if ($mode == 0) { |
exec(OPENSSL_EXEC.' x509 -noout -text'.$params.' -in '.escapeshellarg($cert), $out, $code); |
} else if ($mode == 1) { |
exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout -text'.$params, $out, $code); |
} else { |
return false; |
} |
if ($code != 0) return false; |
$text = implode("\n", $out); |
$text = str_replace("\n\n", "\n", $text); # TODO: repeat until no \n\n exist anymore |
return $text; |
} |
function getAttributes($cert, $mode = 0, $issuer = false, $longnames = false) { |
# mode |
# 0 = cert is a file |
# 1 = cert is pem string |
if ($longnames) { |
$params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
} else { |
$params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq"'; |
} |
if ($issuer) { |
$params .= ' -issuer'; |
} else { |
$params .= ' -subject'; |
} |
if ($mode == 0) { |
exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
} else if ($mode == 1) { |
exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
} else { |
return false; |
} |
$attributes = array(); |
foreach ($out as $n => &$o) { |
if ($n == 0) continue; |
preg_match("| (.*) = (.*)$|ismU", $o, $m); |
if (!isset($attributes[$m[1]])) $attributes[$m[1]] = array(); |
$attributes[$m[1]][] = $m[2]; |
} |
return $attributes; |
} |
function openssl_get_sig_base64($cert, $mode = 0) { |
# mode |
# 0 = cert is a file |
# 1 = cert is pem string |
$out = array(); |
if ($mode == 0) { |
exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
} else if ($mode == 1) { |
exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
} else { |
return false; |
} |
$dump = implode("\n", $out); |
/* |
Signature Algorithm: sha1WithRSAEncryption |
65:f0:6f:f0:1d:66:a4:fe:d1:38:85:6f:5e:06:7b:f3:a7:08: |
... |
1a:13:37 |
*/ |
$regex = "@\n {4}Signature Algorithm: (\S+)\n(( {8}([a-f0-9][a-f0-9]:){18}\n)* {8}([a-f0-9][a-f0-9](:[a-f0-9][a-f0-9]){0,17}\n))@sm"; |
preg_match_all($regex, "$dump\n", $m); |
if (!isset($m[2][0])) return false; |
$x = preg_replace("@[^a-z0-9]@", "", $m[2][0]); |
$x = hex2bin($x); |
return base64_encode($x); |
} |
/trunk/xml_utils.inc.php |
---|
0,0 → 1,190 |
<?php |
/* |
* XML Encoding Utilities |
* Copyright 2011-2020 Daniel Marschall, ViaThinkSoft |
* Version 1.7.2 (2020-12-06) |
* |
* Licensed under the Apache License, Version 2.0 (the "License"); |
* you may not use this file except in compliance with the License. |
* You may obtain a copy of the License at |
* |
* http://www.apache.org/licenses/LICENSE-2.0 |
* |
* Unless required by applicable law or agreed to in writing, software |
* distributed under the License is distributed on an "AS IS" BASIS, |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* See the License for the specific language governing permissions and |
* limitations under the License. |
*/ |
// http://www.viathinksoft.de/?page=codelib&showid=89 |
// Unicode-proof htmlentities. |
// Returns 'normal' chars as chars and weirdos as numeric html entites. |
// Source: http://www.php.net/manual/en/function.htmlentities.php#107985 ; modified |
// Modified by Daniel Marschall, ViaThinkSoft |
function htmlentities_numeric($str, $allow_html=false, $encode_linebreaks=false) { |
// Convert $str to UTF-8 if it is not already |
if (mb_detect_encoding($str, "auto", true) != 'UTF-8') { |
# $str = mb_convert_encoding($str, 'UTF-8', 'Windows-1252'); |
# $str = mb_convert_encoding($str, 'UTF-8', 'auto'); |
$str = mb_convert_encoding($str, 'UTF-8'); |
} |
// get rid of existing entities else double-escape |
// DM 24.08.2016 Removed because of OIDplus 1.0 XML export |
//$str = html_entity_decode(stripslashes($str),ENT_QUOTES,'UTF-8'); |
$ar = preg_split('/(?<!^)(?!$)/u', $str); // return array of every multi-byte character |
$str2 = ''; |
foreach ($ar as $c) { |
$o = ord($c); |
if ( |
(strlen($c) > 1) || /* multi-byte [unicode] */ |
($o < 32 || $o > 126) || /* <- control / latin weirdos -> */ |
($o > 33 && $o < 40) || /* quotes + ampersand */ |
($o > 59 && $o < 63) /* html */ |
) { |
// convert to numeric entity |
$c = mb_encode_numericentity($c, array(0x0, 0xffff, 0, 0xffff), 'UTF-8'); |
if ($allow_html) { |
if ($c == '<') $c = '<'; |
if ($c == '>') $c = '>'; |
if ($c == '=') $c = '='; |
if ($c == '"') $c = '"'; |
if ($c == ''') $c = '\''; |
if ($c == '&') $c = '&'; // DM 24.08.2016 Re-added because OIDplus 1.0 XML export |
} |
if (!$encode_linebreaks) { |
if ($allow_html) { |
if ($c == " ") $c = "<br />"; |
if ($c == " ") $c = "<br />"; |
} else { |
if ($c == " ") $c = "\n"; |
if ($c == " ") $c = "\r"; |
} |
} |
} |
$str2 .= $c; |
} |
return $str2; |
} |
function ordUTF8($c, $index = 0, &$bytes = null) { |
// http://de.php.net/manual/en/function.ord.php#78032 |
$len = strlen($c); |
$bytes = 0; |
if ($index >= $len) { |
return false; |
} |
$h = ord($c[$index]); |
if ($h <= 0x7F) { |
$bytes = 1; |
return $h; |
} else if ($h < 0xC2) { |
return false; |
} else if ($h <= 0xDF && $index < $len - 1) { |
$bytes = 2; |
return ($h & 0x1F) << 6 | (ord($c[$index + 1]) & 0x3F); |
} else if ($h <= 0xEF && $index < $len - 2) { |
$bytes = 3; |
return ($h & 0x0F) << 12 | (ord($c[$index + 1]) & 0x3F) << 6 |
| (ord($c[$index + 2]) & 0x3F); |
} else if ($h <= 0xF4 && $index < $len - 3) { |
$bytes = 4; |
return ($h & 0x0F) << 18 | (ord($c[$index + 1]) & 0x3F) << 12 |
| (ord($c[$index + 2]) & 0x3F) << 6 |
| (ord($c[$index + 3]) & 0x3F); |
} else { |
return false; |
} |
} |
function utf16_to_utf8($str) { |
// http://betamode.de/2008/09/08/php-utf-16-zu-utf-8-konvertieren/ |
// http://www.moddular.org/log/utf16-to-utf8 |
$c0 = ord($str[0]); |
$c1 = ord($str[1]); |
if ($c0 == 0xFE && $c1 == 0xFF) { |
$be = true; |
} else if ($c0 == 0xFF && $c1 == 0xFE) { |
$be = false; |
} else { |
return $str; |
} |
$str = substr($str, 2); |
$len = strlen($str); |
$dec = ''; |
for ($i = 0; $i < $len; $i += 2) { |
$c = ($be) ? ord($str[$i]) << 8 | ord($str[$i + 1]) : |
ord($str[$i + 1]) << 8 | ord($str[$i]); |
if ($c >= 0x0001 && $c <= 0x007F) { |
$dec .= chr($c); |
} else if ($c > 0x07FF) { |
$dec .= chr(0xE0 | (($c >> 12) & 0x0F)); |
$dec .= chr(0x80 | (($c >> 6) & 0x3F)); |
$dec .= chr(0x80 | (($c >> 0) & 0x3F)); |
} else { |
$dec .= chr(0xC0 | (($c >> 6) & 0x1F)); |
$dec .= chr(0x80 | (($c >> 0) & 0x3F)); |
} |
} |
return $dec; |
} |
function html_named_to_numeric_entities($str) { |
if (!mb_detect_encoding($str, 'UTF-8', true)) $str = utf8_encode($str); |
return mb_htmlentities(decodeNamedEntities($str)); |
} |
if (!function_exists('decodeNamedEntities')) { |
function decodeNamedEntities($string) { |
// https://stackoverflow.com/questions/20406599/how-to-encode-for-entity-igrave-not-defined-error-in-xml-feed |
static $entities = NULL; |
if (NULL === $entities) { |
$entities = array_flip( |
array_diff( |
get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8'), |
get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_XML1, 'UTF-8') |
) |
); |
} |
return str_replace(array_keys($entities), $entities, $string); |
} |
} |
if (!function_exists('mb_convert_encoding')) { |
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php |
function mb_convert_encoding($str, $to_encoding, $from_encoding = NULL) { |
return iconv(($from_encoding === NULL) ? mb_internal_encoding() : $from_encoding, $to_encoding, $str); |
} |
} |
if (!function_exists('mb_ord')) { |
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php |
function mb_ord($char, $encoding = 'UTF-8') { |
if ($encoding === 'UCS-4BE') { |
list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char); |
return $ord; |
} else { |
return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE'); |
} |
} |
} |
if (!function_exists('mb_htmlentities')) { |
// https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php |
function mb_htmlentities($string, $hex = true, $encoding = 'UTF-8') { |
return preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) use ($hex) { |
return sprintf($hex ? '&#x%X;' : '&#%d;', mb_ord($match[0])); |
}, $string); |
} |
} |