Subversion Repositories php_utils

Rev

Rev 63 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * PHP Utilities - Misc functions
  5.  * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
  6.  * Revision: 2023-08-01
  7.  *
  8.  * Licensed under the Apache License, Version 2.0 (the "License");
  9.  * you may not use this file except in compliance with the License.
  10.  * You may obtain a copy of the License at
  11.  *
  12.  *     http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing, software
  15.  * distributed under the License is distributed on an "AS IS" BASIS,
  16.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17.  * See the License for the specific language governing permissions and
  18.  * limitations under the License.
  19.  */
  20.  
  21. // array(89,51,10,10) => 'Y3\012\012'
  22. function c_literal($byte_array) {
  23.         $out = "'";
  24.         foreach ($byte_array as $c) {
  25.                 if (is_string($c)) $c = ord($c);
  26.                 if ((($c >= 0x00) && ($c <= 0x1F)) || ($c >= 0x7F)) {
  27.                         // For non-printable characters use octal notation:
  28.                         // \000 ... \377
  29.                         $out .= "\\".str_pad(base_convert(''.$c,10,8), 3, '0', STR_PAD_LEFT);
  30.                 } else {
  31.                         if (chr($c) == "'") $out .= '\\';
  32.                         $out .= chr($c);
  33.                 }
  34.         }
  35.         $out .= "'";
  36.         return $out;
  37. }
  38.  
  39. function c_literal_hexstr($hexstr) {
  40.         $odd_char = (strlen($hexstr)%2 != 0) ? '0x'.substr($hexstr,-1).'<<4' : '';
  41.         $hexstr = substr($hexstr,0,2*(int)floor(strlen($hexstr)/2));
  42.         if ($hexstr != '') {
  43.                 $ary = str_split(hex2bin($hexstr));
  44.                 foreach ($ary as &$a) $a = ord($a);
  45.                 return rtrim(c_literal($ary).' '.$odd_char);
  46.         } else {
  47.                 return $odd_char;
  48.         }
  49. }
  50.  
  51. function generateRandomString($length) {
  52.         // Note: This function can be used in temporary file names, so you
  53.         // may not generate illegal file name characters.
  54.         $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  55.         $charactersLength = strlen($characters);
  56.         $randomString = '';
  57.         for ($i = 0; $i < $length; $i++) {
  58.                 $randomString .= $characters[rand(0, $charactersLength - 1)];
  59.         }
  60.         return $randomString;
  61. }
  62.  
  63. function trim_br($html) {
  64.         $count = 0;
  65.         do { $html = preg_replace('@^\s*<\s*br\s*/{0,1}\s*>@isU', '', $html, -1, $count); } while ($count > 0); // left trim
  66.         do { $html = preg_replace('@<\s*br\s*/{0,1}\s*>\s*$@isU', '', $html, -1, $count); } while ($count > 0); // right trim
  67.         return $html;
  68. }
  69.  
  70. function insertWhitespace($str, $index) {
  71.         return substr($str, 0, $index) . ' ' . substr($str, $index);
  72. }
  73.  
  74. function js_escape($data) {
  75.         // TODO.... json_encode??
  76.         $data = str_replace('\\', '\\\\', $data);
  77.         $data = str_replace('\'', '\\\'', $data);
  78.         return "'" . $data . "'";
  79. }
  80.  
  81. function get_calling_function() {
  82.         $ex = new Exception();
  83.         $trace = $ex->getTrace();
  84.         if (!isset($trace[2])) return '(main)';
  85.         $final_call = $trace[2];
  86.         return $final_call['file'].':'.$final_call['line'].'/'.$final_call['function'].'()';
  87. }
  88.  
  89. function convert_to_utf8_no_bom($cont) {
  90.         $cont = vts_utf8_encode($cont);
  91.  
  92.         // Remove BOM
  93.         $bom = pack('H*','EFBBBF');
  94.         $cont = preg_replace("/^$bom/", '', $cont);
  95.         return $cont;
  96. }
  97.  
  98. function vts_utf8_encode($text) {
  99.         $enc = mb_detect_encoding($text, null, true);
  100.         if ($enc === false) $enc = mb_detect_encoding($text, ['ASCII', 'UTF-8', 'Windows-1252', 'ISO-8859-1'], true);
  101.         if ($enc === false) $enc = null;
  102.  
  103.         if ($enc === 'UTF-8') return $text;
  104.  
  105.         $res = mb_convert_encoding($text, 'UTF-8', $enc);
  106.         if ($res === false) $res = iconv('UTF-8', 'UTF-8//IGNORE', $text);
  107.  
  108.         return $res;
  109. }
  110.  
  111. function vts_utf8_decode($text) {
  112.         $enc = mb_detect_encoding($text, null, true);
  113.         if ($enc === false) $enc = mb_detect_encoding($text, ['ASCII', 'UTF-8', 'Windows-1252', 'ISO-8859-1'], true);
  114.         if ($enc === false) $enc = null;
  115.  
  116.         if ($enc !== 'UTF-8') return $text;
  117.  
  118.         $res = mb_convert_encoding($text, 'Windows-1252', $enc);
  119.         if ($res === false) $res = iconv('Windows-1252', 'Windows-1252//IGNORE', $text);
  120.  
  121.         return $res;
  122. }
  123.  
  124. function stripHtmlComments($html) {
  125.         // https://stackoverflow.com/questions/11337332/how-to-remove-html-comments-in-php
  126.         $html = preg_replace("~<!--(?!<!)[^\[>].*?-->~s", "", $html);
  127.         return $html;
  128. }
  129.  
  130. function wildcard_is_dir($dir) {
  131.         // Example usage:  if (!wildcard_is_dir(OIDplus::localpath().'plugins/'.'*'.'/design/'.$value)) throw new Exception("Design does not exist")
  132.         $dirs = @glob($dir);
  133.         if ($dirs) foreach ($dirs as $dir) {
  134.                 if (is_dir($dir)) return true;
  135.         }
  136.         return false;
  137. }
  138.  
  139. function isInternetExplorer() {
  140.         $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  141.         return ((strpos($ua,'MSIE ') !== false) || (strpos($ua,'Trident/') !== false));
  142. }
  143.  
  144. if (!function_exists('str_starts_with')) {
  145.         // PHP 7.x compatibility
  146.         // source: Laravel Framework
  147.         // https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Str.php
  148.         function str_starts_with($haystack, $needle) {
  149.                 return (string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
  150.         }
  151. }
  152.  
  153. if (!function_exists('str_ends_with')) {
  154.         // PHP 7.x compatibility
  155.         // source: Laravel Framework
  156.         // https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Str.php
  157.         function str_ends_with($haystack, $needle) {
  158.                 return $needle !== '' && substr($haystack, -strlen($needle)) === (string)$needle;
  159.         }
  160. }
  161.  
  162. if (!function_exists('str_contains')) {
  163.         // PHP 7.x compatibility
  164.         // source: Laravel Framework
  165.         // https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Str.php
  166.         function str_contains($haystack, $needle) {
  167.                 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
  168.         }
  169. }
  170.  
  171. function random_bytes_ex($len, $raw=true, $force_cryptographically_secure=true) {
  172.         if ($len === 0) return '';
  173.         assert($len > 0);
  174.  
  175.         if (function_exists('random_bytes')) {
  176.                 try {
  177.                         $a = random_bytes($len);
  178.                 } catch (Exception $e) { $a = null; }
  179.                 if ($a) return $raw ? $a : bin2hex($a);
  180.         }
  181.  
  182.         if (function_exists('openssl_random_pseudo_bytes')) {
  183.                 try {
  184.                         $a = openssl_random_pseudo_bytes($len);
  185.                 } catch (Exception $e) { $a = null; }
  186.                 if ($a) return $raw ? $a : bin2hex($a);
  187.         }
  188.  
  189.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_RANDOM')) {
  190.                 try {
  191.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_DEV_RANDOM));
  192.                 } catch (Exception $e) { $a = null; }
  193.                 if ($a) return $raw ? $a : bin2hex($a);
  194.         }
  195.  
  196.         if ($force_cryptographically_secure) {
  197.                 $msg = 'Cannot find a fitting Cryptographically Secure Random Number Generator (CSRNG).';
  198.                 if (version_compare(PHP_VERSION, '8.2.0') >= 0) {
  199.                         throw new \Random\RandomException($msg);
  200.                 } else {
  201.                         throw new \Exception($msg);
  202.                 }
  203.         }
  204.  
  205.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_URANDOM')) {
  206.                 // /dev/urandom uses the same entropy pool than /dev/random, but if there is not enough data
  207.                 // then the security is lowered.
  208.                 try {
  209.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_DEV_URANDOM));
  210.                 } catch (Exception $e) { $a = null; }
  211.                 if ($a) return $raw ? $a : bin2hex($a);
  212.         }
  213.  
  214.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_RAND')) {
  215.                 try {
  216.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_RAND));
  217.                 } catch (Exception $e) { $a = null; }
  218.                 if ($a) return $raw ? $a : bin2hex($a);
  219.         }
  220.  
  221.         // Fallback to non-secure RNG
  222.         $a = '';
  223.         while (strlen($a) < $len*2) {
  224.                 $a .= sha1(uniqid((string)mt_rand(), true));
  225.         }
  226.         $a = substr($a, 0, $len*2);
  227.         return $raw ? hex2bin($a) : $a;
  228. }
  229.