Subversion Repositories oidplus

Rev

Rev 660 | Rev 681 | 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 - 2021 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 verify_private_public_key($privKey, $pubKey) {
  51.         try {
  52.                 if (empty($privKey)) return false;
  53.                 if (empty($pubKey)) return false;
  54.                 $data = generateRandomString(25);
  55.                 $encrypted = '';
  56.                 $decrypted = '';
  57.                 if (!@openssl_public_encrypt($data, $encrypted, $pubKey)) return false;
  58.                 if (!@openssl_private_decrypt($encrypted, $decrypted, $privKey)) return false;
  59.                 return $decrypted == $data;
  60.         } catch (Exception $e) {
  61.                 return false;
  62.         }
  63. }
  64.  
  65. function smallhash($data) { // get 31 bits from SHA1. Values 0..2147483647
  66.         return (hexdec(substr(sha1($data),-4*2)) & 0x7FFFFFFF);
  67. }
  68.  
  69. function split_firstname_lastname($name) {
  70.         $ary = explode(' ', $name);
  71.         $last_name = array_pop($ary);
  72.         $first_name = implode(' ', $ary);
  73.         return array($first_name, $last_name);
  74. }
  75.  
  76. function originHeaders() {
  77.         // CORS
  78.         // Author: Till Wehowski
  79.         // TODO: add to class OIDplus
  80.  
  81.         header("Access-Control-Allow-Credentials: true");
  82.         header("Access-Control-Allow-Origin: ".strip_tags(((isset($_SERVER['HTTP_ORIGIN'])) ? $_SERVER['HTTP_ORIGIN'] : "*")));
  83.  
  84.         header("Access-Control-Allow-Headers: If-None-Match, X-Requested-With, Origin, X-Frdlweb-Bugs, Etag, X-Forgery-Protection-Token, X-CSRF-Token");
  85.  
  86.         if (isset($_SERVER['HTTP_ORIGIN'])) {
  87.                 header('X-Frame-Options: ALLOW-FROM '.$_SERVER['HTTP_ORIGIN']);
  88.         } else {
  89.                 header_remove("X-Frame-Options");
  90.         }
  91.  
  92.         $expose = array('Etag', 'X-CSRF-Token');
  93.         foreach (headers_list() as $num => $header) {
  94.                 $h = explode(':', $header);
  95.                 $expose[] = trim($h[0]);
  96.         }
  97.         header("Access-Control-Expose-Headers: ".implode(',',$expose));
  98.  
  99.         header("Vary: Origin");
  100. }
  101.  
  102. function get_calling_function() {
  103.         $ex = new Exception();
  104.         $trace = $ex->getTrace();
  105.         if (!isset($trace[2])) return _L('(main)');
  106.         $final_call = $trace[2];
  107.         return $final_call['file'].':'.$final_call['line'].'/'.$final_call['function'].'()';
  108. }
  109.  
  110. if (!function_exists('mb_wordwrap')) {
  111.         function mb_wordwrap($str, $width = 75, $break = "\n", $cut = false) {
  112.                 // https://stackoverflow.com/a/4988494/488539
  113.                 $lines = explode($break, $str);
  114.                 foreach ($lines as &$line) {
  115.                         $line = rtrim($line);
  116.                         if (mb_strlen($line) <= $width) {
  117.                                 continue;
  118.                         }
  119.                         $words = explode(' ', $line);
  120.                         $line = '';
  121.                         $actual = '';
  122.                         foreach ($words as $word) {
  123.                                 if (mb_strlen($actual.$word) <= $width) {
  124.                                         $actual .= $word.' ';
  125.                                 } else {
  126.                                         if ($actual != '') {
  127.                                                 $line .= rtrim($actual).$break;
  128.                                         }
  129.                                         $actual = $word;
  130.                                         if ($cut) {
  131.                                                 while (mb_strlen($actual) > $width) {
  132.                                                         $line .= mb_substr($actual, 0, $width).$break;
  133.                                                         $actual = mb_substr($actual, $width);
  134.                                                 }
  135.                                         }
  136.                                         $actual .= ' ';
  137.                                 }
  138.                         }
  139.                         $line .= trim($actual);
  140.                 }
  141.                 return implode($break, $lines);
  142.         }
  143. }
  144.  
  145. function httpOutWithETag($out, $contentType, $filename='') {
  146.         $etag = md5($out);
  147.         header("Etag: $etag");
  148.         header("Content-MD5: $etag"); // RFC 2616 clause 14.15
  149.         if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && (trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) {
  150.                 header("HTTP/1.1 304 Not Modified");
  151.         } else {
  152.                 header("Content-Type: $contentType");
  153.                 if (!empty($filename)) {
  154.                         header('Content-Disposition:inline; filename="'.$filename.'"');
  155.                 }
  156.                 echo $out;
  157.         }
  158.         die();
  159. }
  160.  
  161. function my_vsprintf($str, $args) {
  162.         $n = 1;
  163.         foreach ($args as $val) {
  164.                 $str = str_replace("%$n", $val, $str);
  165.                 $n++;
  166.         }
  167.         $str = str_replace("%%", "%", $str);
  168.         return $str;
  169. }
  170.  
  171. function _L($str, ...$sprintfArgs) {
  172.         static $translation_array = array();
  173.         static $translation_loaded = null;
  174.  
  175.         $str = trim($str);
  176.  
  177.         if (!class_exists('OIDplus')) {
  178.                 return my_vsprintf($str, $sprintfArgs);
  179.         }
  180.  
  181.         $lang = OIDplus::getCurrentLang();
  182.         $ta = OIDplus::getTranslationArray($lang);
  183.         $res = (isset($ta[$lang]) && isset($ta[$lang][$str])) ? $ta[$lang][$str] : $str;
  184.  
  185.         $res = str_replace('###', OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''), $res);
  186.  
  187.         $res = my_vsprintf($res, $sprintfArgs);
  188.  
  189.         return $res;
  190. }
  191.  
  192. function _CheckParamExists($params, $key) {
  193.         if (!isset($params[$key])) throw new OIDplusException(_L('Parameter %1 is missing', $key));
  194. }
  195.  
  196. function extractHtmlContents($cont) {
  197.         // make sure the program works even if the user provided HTML is not UTF-8
  198.         $cont = iconv(mb_detect_encoding($cont, mb_detect_order(), true), 'UTF-8//IGNORE', $cont);
  199.         $bom = pack('H*','EFBBBF');
  200.         $cont = preg_replace("/^$bom/", '', $cont);
  201.  
  202.         $out_js = '';
  203.         $m = array();
  204.         preg_match_all('@<script[^>]*>(.+)</script>@ismU', $cont, $m);
  205.         foreach ($m[1] as $x) {
  206.                 $out_js = $x . "\n\n";
  207.         }
  208.  
  209.         $out_css = '';
  210.         $m = array();
  211.         preg_match_all('@<style[^>]*>(.+)</style>@ismU', $cont, $m);
  212.         foreach ($m[1] as $x) {
  213.                 $out_css = $x . "\n\n";
  214.         }
  215.  
  216.         $out_html = $cont;
  217.         $out_html = preg_replace('@^(.+)<body[^>]*>@isU', '', $out_html);
  218.         $out_html = preg_replace('@</body>.+$@isU', '', $out_html);
  219.         $out_html = preg_replace('@<title>.+</title>@isU', '', $out_html);
  220.         $out_html = preg_replace('@<h1>.+</h1>@isU', '', $out_html, 1);
  221.         $out_html = preg_replace('@<script[^>]*>(.+)</script>@ismU', '', $out_html);
  222.         $out_html = preg_replace('@<style[^>]*>(.+)</style>@ismU', '', $out_html);
  223.  
  224.         return array($out_html, $out_js, $out_css);
  225. }
  226.  
  227. function sha3_512($password, $raw_output=false) {
  228.         if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
  229.                 return hash('sha3-512', $password, $raw_output);
  230.         } else {
  231.                 return bb\Sha3\Sha3::hash($password, 512, $raw_output);
  232.         }
  233. }
  234.  
  235. function get_svn_revision($dir='') {
  236.         if (!empty($dir)) $dir .= '/';
  237.  
  238.         // Try to get the version via SQLite3
  239.         if (class_exists('SQLite3')) {
  240.                 try {
  241.                         $db = new SQLite3($dir.'.svn/wc.db');
  242.                         $results = $db->query('SELECT MIN(revision) AS rev FROM NODES_BASE');
  243.                         while ($row = $results->fetchArray()) {
  244.                                 return ($cachedVersion = $row['rev']);
  245.                         }
  246.                         $db->close();
  247.                         $db = null;
  248.                 } catch (Exception $e) {
  249.                 }
  250.         }
  251.         if (class_exists('PDO')) {
  252.                 try {
  253.                         $pdo = new PDO('sqlite:'.$dir.'.svn/wc.db');
  254.                         $res = $pdo->query('SELECT MIN(revision) AS rev FROM NODES_BASE');
  255.                         $row = $res->fetch();
  256.                         if ($row !== false) {
  257.                                 return ($cachedVersion = $row['rev']);
  258.                         }
  259.                         $pdo = null;
  260.                 } catch (Exception $e) {
  261.                 }
  262.         }
  263.  
  264.         // Try to find out the SVN version using the shell
  265.         // We don't prioritize this method, because a failed shell access will flood the apache error log with STDERR messages
  266.         $output = @shell_exec('svnversion '.escapeshellarg($dir).' 2>&1');
  267.         $match = array();
  268.         if (preg_match('/\d+/', $output, $match)) {
  269.                 return ($cachedVersion = $match[0]);
  270.         }
  271.  
  272.         $output = @shell_exec('svn info '.escapeshellarg($dir).' 2>&1');
  273.         if (preg_match('/Revision:\s*(\d+)/m', $output, $match)) { // do not translate
  274.                 return ($cachedVersion = $match[1]);
  275.         }
  276.  
  277.         return false;
  278. }
  279.  
  280. function get_gitsvn_revision($dir='') {
  281.         try {
  282.                 // requires danielmarschall/git_utils.inc.php
  283.                 $commit_msg = git_get_latest_commit_message($dir.'/.git');
  284.         } catch (Exception $e) {
  285.                 // Try command-line
  286.                 $ec = -1;
  287.                 $out = array();
  288.                 if (!empty($dir)) {
  289.                         @exec('cd '.escapeshellarg($dir).' && git log', $out, $ec);
  290.                 } else {
  291.                         @exec('git log', $out, $ec);
  292.                 }
  293.                 if ($ec == 0) {
  294.                         $commit_msg = implode("\n", $out);
  295.                 } else {
  296.                         return false;
  297.                 }
  298.         }
  299.  
  300.         $m = array();
  301.         if (preg_match('%git-svn-id: (.+)@(\\d+) %ismU', $commit_msg, $m)) {
  302.                 return $m[2];
  303.         } else {
  304.                 return false;
  305.         }
  306. }
  307.  
  308. if (!function_exists('str_ends_with')) {
  309.         // PHP 7.x compatibility
  310.         function str_ends_with($haystack, $needle) {
  311.                 $length = strlen($needle);
  312.                 return $length > 0 ? substr($haystack, -$length) === $needle : true;
  313.         }
  314. }
  315.  
  316.  
  317. if (!function_exists('str_starts_with')) {
  318.         // PHP 7.x compatibility
  319.         function str_starts_with($haystack, $needle) {
  320.                 return strpos($haystack, $needle) === 0;
  321.         }
  322. }
  323.  
  324. function rec_is_dir($dir) {
  325.         $dirs = glob($dir);
  326.         foreach ($dirs as $dir) {
  327.                 if (is_dir($dir)) return true;
  328.         }
  329.         return false;
  330. }
  331.  
  332. function isInternetExplorer() {
  333.         // see also includes/oidplus_base.js
  334.         $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  335.         return ((strpos($ua,'MSIE ') !== false) || (strpos($ua,'Trident/') !== false));
  336. }
  337.  
  338. function url_get_contents($url) {
  339.         if (function_exists('curl_init')) {
  340.                 $ch = curl_init();
  341.                 if (ini_get('curl.cainfo') == '') curl_setopt($ch, CURLOPT_CAINFO, OIDplus::localpath() . 'vendor/cacert.pem');
  342.                 curl_setopt($ch, CURLOPT_URL, $url);
  343.                 curl_setopt($ch, CURLOPT_POST, 0);
  344.                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  345.                 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  346.                 curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  347.                 if (!($res = @curl_exec($ch))) return false;
  348.                 curl_close($ch);
  349.         } else {
  350.                 $res = @file_get_contents($url);
  351.                 if ($res === false) return false;
  352.         }
  353.         return $res;
  354. }
  355.