Subversion Repositories php_utils

Rev

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

  1. <?php
  2.  
  3. /*
  4.  * XML Encoding Utilities
  5.  * Copyright 2011-2021 Daniel Marschall, ViaThinkSoft
  6.  * Version 1.8 (2021-11-24)
  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. // http://www.viathinksoft.de/?page=codelib&showid=89
  22.  
  23. // Unicode-proof htmlentities.
  24. // Returns 'normal' chars as chars and weirdos as numeric html entites.
  25. // Source: http://www.php.net/manual/en/function.htmlentities.php#107985 ; modified
  26. // Modified by Daniel Marschall, ViaThinkSoft
  27. function htmlentities_numeric($str, $allow_html=false, $encode_linebreaks=false) {
  28.         // Convert $str to UTF-8 if it is not already
  29.         if (mb_detect_encoding($str, "auto", true) != 'UTF-8') {
  30. #               $str = mb_convert_encoding($str, 'UTF-8', 'Windows-1252');
  31. #               $str = mb_convert_encoding($str, 'UTF-8', 'auto');
  32.                 $str = mb_convert_encoding($str, 'UTF-8');
  33.         }
  34.  
  35.         // get rid of existing entities else double-escape
  36.         // DM 24.08.2016 Removed because of OIDplus 1.0 XML export
  37.         //$str = html_entity_decode(stripslashes($str),ENT_QUOTES,'UTF-8');
  38.  
  39.         $ar = preg_split('/(?<!^)(?!$)/u', $str);  // return array of every multi-byte character
  40.         $str2 = '';
  41.         foreach ($ar as $c) {
  42.                 $o = ord($c);
  43.                 if (
  44.                         (strlen($c) > 1)      || /* multi-byte [unicode] */
  45.                         ($o < 32 || $o > 126) || /* <- control / latin weirdos -> */
  46.                         ($o > 33 && $o < 40)  || /* quotes + ampersand */
  47.                         ($o > 59 && $o < 63)     /* html */
  48.                 ) {
  49.                         // convert to numeric entity
  50.                         $c = mb_encode_numericentity($c, array(0x0, 0xffff, 0, 0xffff), 'UTF-8');
  51.  
  52.                         if ($allow_html) {
  53.                                 if ($c == '&#60;') $c = '<';
  54.                                 if ($c == '&#62;') $c = '>';
  55.                                 if ($c == '&#61;') $c = '=';
  56.                                 if ($c == '&#34;') $c = '"';
  57.                                 if ($c == '&#39;') $c = '\'';
  58.                                 if ($c == '&#38;') $c = '&'; // DM 24.08.2016 Re-added because OIDplus 1.0 XML export
  59.                         }
  60.  
  61.                         if (!$encode_linebreaks) {
  62.                                 if ($allow_html) {
  63.                                         if ($c == "&#10;") $c = "<br />";
  64.                                         if ($c == "&#13;") $c = "<br />";
  65.                                 } else {
  66.                                         if ($c == "&#10;") $c = "\n";
  67.                                         if ($c == "&#13;") $c = "\r";
  68.                                 }
  69.                         }
  70.                 }
  71.                 $str2 .= $c;
  72.         }
  73.         return $str2;
  74. }
  75.  
  76. function ordUTF8($c, $index = 0, &$bytes = null) {
  77.         // http://de.php.net/manual/en/function.ord.php#78032
  78.  
  79.         $len = strlen($c);
  80.         $bytes = 0;
  81.  
  82.         if ($index >= $len) {
  83.                 return false;
  84.         }
  85.  
  86.         $h = ord($c[$index]);
  87.  
  88.         if ($h <= 0x7F) {
  89.                 $bytes = 1;
  90.                 return $h;
  91.         } else if ($h < 0xC2) {
  92.                 return false;
  93.         } else if ($h <= 0xDF && $index < $len - 1) {
  94.                 $bytes = 2;
  95.                 return ($h & 0x1F) <<  6 | (ord($c[$index + 1]) & 0x3F);
  96.         } else if ($h <= 0xEF && $index < $len - 2) {
  97.                 $bytes = 3;
  98.                 return ($h & 0x0F) << 12 | (ord($c[$index + 1]) & 0x3F) << 6
  99.                         | (ord($c[$index + 2]) & 0x3F);
  100.         } else if ($h <= 0xF4 && $index < $len - 3) {
  101.                 $bytes = 4;
  102.                 return ($h & 0x0F) << 18 | (ord($c[$index + 1]) & 0x3F) << 12
  103.                         | (ord($c[$index + 2]) & 0x3F) << 6
  104.                         | (ord($c[$index + 3]) & 0x3F);
  105.         } else {
  106.                 return false;
  107.         }
  108. }
  109.  
  110. function utf16_to_utf8($str) {
  111.         // http://betamode.de/2008/09/08/php-utf-16-zu-utf-8-konvertieren/
  112.         // http://www.moddular.org/log/utf16-to-utf8
  113.  
  114.         $c0 = ord($str[0]);
  115.         $c1 = ord($str[1]);
  116.         if ($c0 == 0xFE && $c1 == 0xFF) {
  117.                 $be = true;
  118.         } else if ($c0 == 0xFF && $c1 == 0xFE) {
  119.                 $be = false;
  120.         } else {
  121.                 return $str;
  122.         }
  123.         $str = substr($str, 2);
  124.         $len = strlen($str);
  125.         $dec = '';
  126.         for ($i = 0; $i < $len; $i += 2) {
  127.                 $c = ($be) ? ord($str[$i]) << 8 | ord($str[$i + 1]) :
  128.                         ord($str[$i + 1]) << 8 | ord($str[$i]);
  129.                 if ($c >= 0x0001 && $c <= 0x007F) {
  130.                         $dec .= chr($c);
  131.                 } else if ($c > 0x07FF) {
  132.                         $dec .= chr(0xE0 | (($c >> 12) & 0x0F));
  133.                         $dec .= chr(0x80 | (($c >> 6) & 0x3F));
  134.                         $dec .= chr(0x80 | (($c >> 0) & 0x3F));
  135.                 } else {
  136.                         $dec .= chr(0xC0 | (($c >> 6) & 0x1F));
  137.                         $dec .= chr(0x80 | (($c >> 0) & 0x3F));
  138.                 }
  139.         }
  140.         return $dec;
  141. }
  142.  
  143. function html_named_to_numeric_entities($str) {
  144.         $str = mb_convert_encoding($str, 'UTF-8');
  145.         return mb_htmlentities(decodeNamedEntities($str));
  146. }
  147.  
  148. if (!function_exists('decodeNamedEntities')) {
  149.         function decodeNamedEntities($string) {
  150.                 // https://stackoverflow.com/questions/20406599/how-to-encode-for-entity-igrave-not-defined-error-in-xml-feed
  151.                 static $entities = NULL;
  152.                 if (NULL === $entities) {
  153.                         $entities = array_flip(
  154.                                 array_diff(
  155.                                         get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8'),
  156.                                         get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_XML1, 'UTF-8')
  157.                                 )
  158.                         );
  159.                 }
  160.                 return str_replace(array_keys($entities), $entities, $string);
  161.         }
  162. }
  163.  
  164. if (!function_exists('mb_convert_encoding')) {
  165.         // https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
  166.         function mb_convert_encoding($str, $to_encoding, $from_encoding = NULL) {
  167.                 return iconv(($from_encoding === NULL) ? mb_internal_encoding() : $from_encoding, $to_encoding, $str);
  168.         }
  169. }
  170.  
  171. if (!function_exists('mb_ord')) {
  172.         // https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
  173.         function mb_ord($char, $encoding = 'UTF-8') {
  174.                 if ($encoding === 'UCS-4BE') {
  175.                         list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char);
  176.                         return $ord;
  177.                 } else {
  178.                         return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE');
  179.                 }
  180.         }
  181. }
  182.  
  183. if (!function_exists('mb_htmlentities')) {
  184.         // https://riptutorial.com/php/example/15633/converting-unicode-characters-to-their-numeric-value-and-or-html-entities-using-php
  185.         // modified
  186.         function mb_htmlentities($string, $hex = true, $encoding = 'UTF-8') {
  187.                 return preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) use ($hex, $encoding) {
  188.                         $ord = (strtoupper($encoding) == 'UTF-8') ? ordUTF8($match[0]) : mb_ord($match[0]);
  189.                         return sprintf($hex ? '&#x%X;' : '&#%d;', $ord);
  190.                 }, $string);
  191.         }
  192. }
  193.