Subversion Repositories php_utils

Rev

Rev 56 | Go to most recent revision | 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-02-27
  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.         // see also includes/oidplus_base.js
  141.         $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  142.         return ((strpos($ua,'MSIE ') !== false) || (strpos($ua,'Trident/') !== false));
  143. }
  144.  
  145. if (!function_exists('str_ends_with')) {
  146.         // PHP 7.x compatibility
  147.         function str_ends_with($haystack, $needle) {
  148.                 $length = strlen($needle);
  149.                 return $length > 0 ? substr($haystack, -$length) === $needle : true;
  150.         }
  151. }
  152.  
  153. if (!function_exists('str_starts_with')) {
  154.         // PHP 7.x compatibility
  155.         function str_starts_with($haystack, $needle) {
  156.                 return strpos($haystack, $needle) === 0;
  157.         }
  158. }
  159.  
  160. function random_bytes_ex($len, $raw=true, $force_cryptographically_secure=true) {
  161.         if ($len === 0) return '';
  162.         assert($len > 0);
  163.  
  164.         if (function_exists('random_bytes')) {
  165.                 try {
  166.                         $a = random_bytes($len);
  167.                 } catch (Exception $e) { $a = null; }
  168.                 if ($a) return $raw ? $a : bin2hex($a);
  169.         }
  170.  
  171.         if (function_exists('openssl_random_pseudo_bytes')) {
  172.                 try {
  173.                         $a = openssl_random_pseudo_bytes($len);
  174.                 } catch (Exception $e) { $a = null; }
  175.                 if ($a) return $raw ? $a : bin2hex($a);
  176.         }
  177.  
  178.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_RANDOM')) {
  179.                 try {
  180.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_DEV_RANDOM));
  181.                 } catch (Exception $e) { $a = null; }
  182.                 if ($a) return $raw ? $a : bin2hex($a);
  183.         }
  184.  
  185.         if ($force_cryptographically_secure) {
  186.                 $msg = 'Cannot find a fitting Cryptographically Secure Random Number Generator (CSRNG).';
  187.                 if (version_compare(PHP_VERSION, '8.2.0') >= 0) {
  188.                         throw new \Random\RandomException($msg);
  189.                 } else {
  190.                         throw new \Exception($msg);
  191.                 }
  192.         }
  193.  
  194.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_URANDOM')) {
  195.                 // /dev/urandom uses the same entropy pool than /dev/random, but if there is not enough data
  196.                 // then the security is lowered.
  197.                 try {
  198.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_DEV_URANDOM));
  199.                 } catch (Exception $e) { $a = null; }
  200.                 if ($a) return $raw ? $a : bin2hex($a);
  201.         }
  202.  
  203.         if (function_exists('mcrypt_create_iv') && defined('MCRYPT_RAND')) {
  204.                 try {
  205.                         $a = bin2hex(mcrypt_create_iv($len, MCRYPT_RAND));
  206.                 } catch (Exception $e) { $a = null; }
  207.                 if ($a) return $raw ? $a : bin2hex($a);
  208.         }
  209.  
  210.         // Fallback to non-secure RNG
  211.         $a = '';
  212.         while (strlen($a) < $len*2) {
  213.                 $a .= sha1(uniqid((string)mt_rand(), true));
  214.         }
  215.         $a = substr($a, 0, $len*2);
  216.         return $raw ? hex2bin($a) : $a;
  217. }
  218.