Subversion Repositories oidplus

Rev

Rev 824 | Rev 847 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *     http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  */
  19.  
  20. function insertWhitespace($str, $index) {
  21.         return substr($str, 0, $index) . ' ' . substr($str, $index);
  22. }
  23.  
  24. function js_escape($data) {
  25.         // TODO.... json_encode??
  26.         $data = str_replace('\\', '\\\\', $data);
  27.         $data = str_replace('\'', '\\\'', $data);
  28.         return "'" . $data . "'";
  29. }
  30.  
  31. function trim_br($html) {
  32.         $count = 0;
  33.         do { $html = preg_replace('@^\s*<\s*br\s*/{0,1}\s*>@isU', '', $html, -1, $count); } while ($count > 0); // left trim
  34.         do { $html = preg_replace('@<\s*br\s*/{0,1}\s*>\s*$@isU', '', $html, -1, $count); } while ($count > 0); // right trim
  35.         return $html;
  36. }
  37.  
  38. function generateRandomString($length) {
  39.         // Note: This function can be used in temporary file names, so you
  40.         // may not generate illegal file name characters.
  41.         $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  42.         $charactersLength = strlen($characters);
  43.         $randomString = '';
  44.         for ($i = 0; $i < $length; $i++) {
  45.                 $randomString .= $characters[rand(0, $charactersLength - 1)];
  46.         }
  47.         return $randomString;
  48. }
  49.  
  50. function is_privatekey_encrypted($privKey) {
  51.         return strpos($privKey,'BEGIN ENCRYPTED PRIVATE KEY') !== false;
  52. }
  53.  
  54. function verify_private_public_key($privKey, $pubKey) {
  55.         if (!function_exists('openssl_public_encrypt')) return false;
  56.         try {
  57.                 if (empty($privKey)) return false;
  58.                 if (empty($pubKey)) return false;
  59.                 $data = generateRandomString(25);
  60.                 $encrypted = '';
  61.                 $decrypted = '';
  62.                 if (!@openssl_public_encrypt($data, $encrypted, $pubKey)) return false;
  63.                 if (!@openssl_private_decrypt($encrypted, $decrypted, $privKey)) return false;
  64.                 return $decrypted == $data;
  65.         } catch (Exception $e) {
  66.                 return false;
  67.         }
  68. }
  69.  
  70. function change_private_key_passphrase($privKeyOld, $passphrase_old, $passphrase_new) {
  71.         $pkey_config = array(
  72.             //"digest_alg" => "sha512",
  73.             //"private_key_bits" => 2048,
  74.             //"private_key_type" => OPENSSL_KEYTYPE_RSA,
  75.             "config" => class_exists("OIDplus") ? OIDplus::getOpenSslCnf() : @getenv('OPENSSL_CONF')
  76.         );
  77.         $privKeyNew = @openssl_pkey_get_private($privKeyOld, $passphrase_old);
  78.         if ($privKeyNew === false) return false;
  79.         @openssl_pkey_export($privKeyNew, $privKeyNewExport, $passphrase_new, $pkey_config);
  80.         if ($privKeyNewExport === false) return false;
  81.         return $privKeyNewExport."";
  82. }
  83.  
  84. function decrypt_private_key($privKey, $passphrase) {
  85.         return change_private_key_passphrase($privKey, $passphrase, null);
  86. }
  87.  
  88. function encrypt_private_key($privKey, $passphrase) {
  89.         return change_private_key_passphrase($privKey, null, $passphrase);
  90. }
  91.  
  92. function smallhash($data) { // get 31 bits from SHA1. Values 0..2147483647
  93.         return (hexdec(substr(sha1($data),-4*2)) & 0x7FFFFFFF);
  94. }
  95.  
  96. function split_firstname_lastname($name) {
  97.         $ary = explode(' ', $name);
  98.         $last_name = array_pop($ary);
  99.         $first_name = implode(' ', $ary);
  100.         return array($first_name, $last_name);
  101. }
  102.  
  103. function originHeaders() {
  104.         // CORS
  105.         // Author: Till Wehowski
  106.         // TODO: add to class OIDplus
  107.  
  108.         header("Access-Control-Allow-Credentials: true");
  109.         header("Access-Control-Allow-Origin: ".strip_tags(((isset($_SERVER['HTTP_ORIGIN'])) ? $_SERVER['HTTP_ORIGIN'] : "*")));
  110.  
  111.         header("Access-Control-Allow-Headers: If-None-Match, X-Requested-With, Origin, X-Frdlweb-Bugs, Etag, X-Forgery-Protection-Token, X-CSRF-Token");
  112.  
  113.         if (isset($_SERVER['HTTP_ORIGIN'])) {
  114.                 header('X-Frame-Options: ALLOW-FROM '.$_SERVER['HTTP_ORIGIN']);
  115.         } else {
  116.                 header_remove("X-Frame-Options");
  117.         }
  118.  
  119.         $expose = array('Etag', 'X-CSRF-Token');
  120.         foreach (headers_list() as $num => $header) {
  121.                 $h = explode(':', $header);
  122.                 $expose[] = trim($h[0]);
  123.         }
  124.         header("Access-Control-Expose-Headers: ".implode(',',$expose));
  125.  
  126.         header("Vary: Origin");
  127. }
  128.  
  129. function get_calling_function() {
  130.         $ex = new Exception();
  131.         $trace = $ex->getTrace();
  132.         if (!isset($trace[2])) return _L('(main)');
  133.         $final_call = $trace[2];
  134.         return $final_call['file'].':'.$final_call['line'].'/'.$final_call['function'].'()';
  135. }
  136.  
  137. if (!function_exists('mb_wordwrap')) {
  138.         function mb_wordwrap($str, $width = 75, $break = "\n", $cut = false) {
  139.                 // https://stackoverflow.com/a/4988494/488539
  140.                 $lines = explode($break, $str);
  141.                 foreach ($lines as &$line) {
  142.                         $line = rtrim($line);
  143.                         if (mb_strlen($line) <= $width) {
  144.                                 continue;
  145.                         }
  146.                         $words = explode(' ', $line);
  147.                         $line = '';
  148.                         $actual = '';
  149.                         foreach ($words as $word) {
  150.                                 if (mb_strlen($actual.$word) <= $width) {
  151.                                         $actual .= $word.' ';
  152.                                 } else {
  153.                                         if ($actual != '') {
  154.                                                 $line .= rtrim($actual).$break;
  155.                                         }
  156.                                         $actual = $word;
  157.                                         if ($cut) {
  158.                                                 while (mb_strlen($actual) > $width) {
  159.                                                         $line .= mb_substr($actual, 0, $width).$break;
  160.                                                         $actual = mb_substr($actual, $width);
  161.                                                 }
  162.                                         }
  163.                                         $actual .= ' ';
  164.                                 }
  165.                         }
  166.                         $line .= trim($actual);
  167.                 }
  168.                 return implode($break, $lines);
  169.         }
  170. }
  171.  
  172. function httpOutWithETag($out, $contentType, $filename='') {
  173.         $etag = md5($out);
  174.         header("Etag: $etag");
  175.         header("Content-MD5: $etag"); // RFC 2616 clause 14.15
  176.         if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && (trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) {
  177.                 header("HTTP/1.1 304 Not Modified");
  178.         } else {
  179.                 header("Content-Type: $contentType");
  180.                 if (!empty($filename)) {
  181.                         header('Content-Disposition:inline; filename="'.$filename.'"');
  182.                 }
  183.                 echo $out;
  184.         }
  185.         die();
  186. }
  187.  
  188. function my_vsprintf($str, $args) {
  189.         $n = 1;
  190.         foreach ($args as $val) {
  191.                 $str = str_replace("%$n", $val, $str);
  192.                 $n++;
  193.         }
  194.         $str = str_replace("%%", "%", $str);
  195.         return $str;
  196. }
  197.  
  198. function _L($str, ...$sprintfArgs) {
  199.         static $translation_array = array();
  200.         static $translation_loaded = null;
  201.  
  202.         $str = trim($str);
  203.  
  204.         if (!class_exists('OIDplus')) {
  205.                 return my_vsprintf($str, $sprintfArgs);
  206.         }
  207.  
  208.         $lang = OIDplus::getCurrentLang();
  209.         $ta = OIDplus::getTranslationArray($lang);
  210.         $res = (isset($ta[$lang]) && isset($ta[$lang][$str])) ? $ta[$lang][$str] : $str;
  211.  
  212.         $res = str_replace('###', OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''), $res);
  213.  
  214.         $res = my_vsprintf($res, $sprintfArgs);
  215.  
  216.         return $res;
  217. }
  218.  
  219. function _CheckParamExists($params, $key) {
  220.         if (class_exists('OIDplusException')) {
  221.                 if (!isset($params[$key])) throw new OIDplusException(_L('Parameter %1 is missing', $key));
  222.         } else {
  223.                 if (!isset($params[$key])) throw new Exception(_L('Parameter %1 is missing', $key));
  224.         }
  225. }
  226.  
  227. function convert_to_utf8_no_bom($cont) {
  228.         if (mb_detect_encoding($cont, "auto", true) != 'UTF-8') {
  229.                 # $cont = mb_convert_encoding($cont, 'UTF-8', 'Windows-1252');
  230.                 # $cont = mb_convert_encoding($cont, 'UTF-8', 'auto');
  231.                 $cont = mb_convert_encoding($cont, 'UTF-8');
  232.         }
  233.  
  234.         // Remove BOM
  235.         $bom = pack('H*','EFBBBF');
  236.         $cont = preg_replace("/^$bom/", '', $cont);
  237.         return $cont;
  238. }
  239.  
  240. function stripHtmlComments($html) {
  241.         // https://stackoverflow.com/questions/11337332/how-to-remove-html-comments-in-php
  242.         $html = preg_replace("~<!--(?!<!)[^\[>].*?-->~s", "", $html);
  243.         return $html;
  244. }
  245.  
  246. function extractHtmlContents($cont) {
  247.         // make sure the program works even if the user provided HTML is not UTF-8
  248.         $cont = convert_to_utf8_no_bom($cont);
  249.  
  250.         $out_js = '';
  251.         $m = array();
  252.         preg_match_all('@<script[^>]*>(.+)</script>@ismU', $cont, $m);
  253.         foreach ($m[1] as $x) {
  254.                 $out_js = $x . "\n\n";
  255.         }
  256.  
  257.         $out_css = '';
  258.         $m = array();
  259.         preg_match_all('@<style[^>]*>(.+)</style>@ismU', $cont, $m);
  260.         foreach ($m[1] as $x) {
  261.                 $out_css = $x . "\n\n";
  262.         }
  263.  
  264.         $out_html = $cont;
  265.         $out_html = preg_replace('@^(.+)<body[^>]*>@isU', '', $out_html);
  266.         $out_html = preg_replace('@</body>.+$@isU', '', $out_html);
  267.         $out_html = preg_replace('@<title>.+</title>@isU', '', $out_html);
  268.         $out_html = preg_replace('@<h1>.+</h1>@isU', '', $out_html, 1);
  269.         $out_html = preg_replace('@<script[^>]*>(.+)</script>@ismU', '', $out_html);
  270.         $out_html = preg_replace('@<style[^>]*>(.+)</style>@ismU', '', $out_html);
  271.  
  272.         return array($out_html, $out_js, $out_css);
  273. }
  274.  
  275. function sha3_512($password, $raw_output=false) {
  276.         if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
  277.                 return hash('sha3-512', $password, $raw_output);
  278.         } else {
  279.                 return bb\Sha3\Sha3::hash($password, 512, $raw_output);
  280.         }
  281. }
  282.  
  283. function sha3_512_hmac($message, $key, $raw_output=false) {
  284.         // RFC 2104 HMAC
  285.                 if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
  286.                                 return hash_hmac('sha3-512', $message, $key, $raw_output);
  287.                 } else {
  288.                 $blocksize = 576; // block size of sha-512!
  289.  
  290.                 if (strlen($key) > ($blocksize/8)) {
  291.                         $k_ = sha3_512($key,true);
  292.                 } else {
  293.                         $k_ = $key;
  294.                 }
  295.  
  296.                 $k_opad = str_repeat(chr(0x5C),($blocksize/8));
  297.                 $k_ipad = str_repeat(chr(0x36),($blocksize/8));
  298.                 for ($i=0; $i<strlen($k_); $i++) {
  299.                         $k_opad[$i] = $k_opad[$i] ^ $k_[$i];
  300.                         $k_ipad[$i] = $k_ipad[$i] ^ $k_[$i];
  301.                 }
  302.  
  303.                 return sha3_512($k_opad . sha3_512($k_ipad . $message, true));
  304.                 }
  305. }
  306.  
  307. if (!function_exists('str_ends_with')) {
  308.         // PHP 7.x compatibility
  309.         function str_ends_with($haystack, $needle) {
  310.                 $length = strlen($needle);
  311.                 return $length > 0 ? substr($haystack, -$length) === $needle : true;
  312.         }
  313. }
  314.  
  315. if (!function_exists('str_starts_with')) {
  316.         // PHP 7.x compatibility
  317.         function str_starts_with($haystack, $needle) {
  318.                 return strpos($haystack, $needle) === 0;
  319.         }
  320. }
  321.  
  322. function rec_is_dir($dir) {
  323.         $dirs = @glob($dir);
  324.         if ($dirs) foreach ($dirs as $dir) {
  325.                 if (is_dir($dir)) return true;
  326.         }
  327.         return false;
  328. }
  329.  
  330. function isInternetExplorer() {
  331.         // see also includes/oidplus_base.js
  332.         $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  333.         return ((strpos($ua,'MSIE ') !== false) || (strpos($ua,'Trident/') !== false));
  334. }
  335.  
  336. function url_get_contents($url) {
  337.         if (function_exists('curl_init')) {
  338.                 $ch = curl_init();
  339.                 if (class_exists('OIDplus')) {
  340.                         if (ini_get('curl.cainfo') == '') curl_setopt($ch, CURLOPT_CAINFO, OIDplus::localpath() . 'vendor/cacert.pem');
  341.                 }
  342.                 curl_setopt($ch, CURLOPT_URL, $url);
  343.                 curl_setopt($ch, CURLOPT_USERAGENT, 'ViaThinkSoft-OIDplus/2.0');
  344.                 curl_setopt($ch, CURLOPT_POST, 0);
  345.                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  346.                 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  347.                 curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  348.                 if (!($res = @curl_exec($ch))) return false;
  349.                 if (@curl_getinfo($ch, CURLINFO_HTTP_CODE) >= 400) return false;
  350.                 @curl_close($ch);
  351.         } else {
  352.                 $opts = [
  353.                         "http" => [
  354.                                 "method" => "GET",
  355.                                 "header" => "User-Agent: ViaThinkSoft-OIDplus/2.0\r\n"
  356.                         ]
  357.                 ];
  358.                 $context = stream_context_create($opts);
  359.                 $res = @file_get_contents($url, false, $context);
  360.                 if ($res === false) return false;
  361.         }
  362.         return $res;
  363. }
  364.  
  365. function getSortedQuery() {
  366.         // https://stackoverflow.com/a/51777249/488539
  367.         $url = [];
  368.         parse_str($_SERVER['QUERY_STRING'], $url);
  369.         ksort($url);
  370.         return http_build_query($url);
  371. }
  372.