I18N_Arabic
[ class tree: I18N_Arabic ] [ index: I18N_Arabic ] [ all elements ]

Source for file Glyphs.php

Documentation is available at Glyphs.php

  1. <?php
  2. /**
  3.  * ----------------------------------------------------------------------
  4.  *  
  5.  * Copyright (c) 2006-2013 Khaled Al-Sham'aa.
  6.  *  
  7.  * http://www.ar-php.org
  8.  *  
  9.  * PHP Version 5
  10.  *  
  11.  * ----------------------------------------------------------------------
  12.  *  
  13.  * LICENSE
  14.  *
  15.  * This program is open source product; you can redistribute it and/or
  16.  * modify it under the terms of the GNU Lesser General Public License (LGPL)
  17.  * as published by the Free Software Foundation; either version 3
  18.  * of the License, or (at your option) any later version.
  19.  *  
  20.  * This program is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  * GNU Lesser General Public License for more details.
  24.  *  
  25.  * You should have received a copy of the GNU Lesser General Public License
  26.  * along with this program.  If not, see <http://www.gnu.org/licenses/lgpl.txt>.
  27.  *  
  28.  * ----------------------------------------------------------------------
  29.  *  
  30.  * Class Name: Arabic Glyphs is a simple class to render Arabic text
  31.  *  
  32.  * Filename:   Glyphs.php
  33.  *  
  34.  * Original    Author(s): Khaled Al-Sham'aa <khaled@ar-php.org>
  35.  *  
  36.  * Purpose:    This class takes Arabic text (encoded in Windows-1256 character
  37.  *             set) as input and performs Arabic glyph joining on it and outputs
  38.  *             a UTF-8 hexadecimals stream that is no longer logically arranged
  39.  *             but in a visual order which gives readable results when formatted
  40.  *             with a simple Unicode rendering just like GD and UFPDF libraries
  41.  *             that does not handle basic connecting glyphs of Arabic language
  42.  *             yet but simply outputs all stand alone glyphs in left-to-right
  43.  *             order.
  44.  *              
  45.  * ----------------------------------------------------------------------
  46.  *  
  47.  * Arabic Glyphs is class to render Arabic text
  48.  *
  49.  * PHP class to render Arabic text by performs Arabic glyph joining on it,
  50.  * then output a UTF-8 hexadecimals stream gives readable results on PHP
  51.  * libraries supports UTF-8.
  52.  *
  53.  * Example:
  54.  * <code>
  55.  *   include('./I18N/Arabic.php');
  56.  *   $obj = new I18N_Arabic('Glyphs');
  57.  *
  58.  *   $text = $obj->utf8Glyphs($text);
  59.  *      
  60.  *   imagettftext($im, 20, 0, 200, 100, $black, $font, $text);
  61.  * </code>
  62.  *
  63.  * @category  I18N
  64.  * @package   I18N_Arabic
  65.  * @author    Khaled Al-Sham'aa <khaled@ar-php.org>
  66.  * @copyright 2006-2013 Khaled Al-Sham'aa
  67.  *    
  68.  * @license   LGPL <http://www.gnu.org/licenses/lgpl.txt>
  69.  * @link      http://www.ar-php.org
  70.  */
  71.  
  72. // New in PHP V5.3: Namespaces
  73. // namespace I18N\Arabic;
  74. // 
  75. // $obj = new I18N\Arabic\Glyphs();
  76. // 
  77. // use I18N\Arabic;
  78. // $obj = new Arabic\Glyphs();
  79. //
  80. // use I18N\Arabic\Glyphs as Glyphs;
  81. // $obj = new Glyphs();
  82.  
  83. /**
  84.  * This PHP class render Arabic text by performs Arabic glyph joining on it
  85.  *  
  86.  * @category  I18N
  87.  * @package   I18N_Arabic
  88.  * @author    Khaled Al-Sham'aa <khaled@ar-php.org>
  89.  * @copyright 2006-2013 Khaled Al-Sham'aa
  90.  *    
  91.  * @license   LGPL <http://www.gnu.org/licenses/lgpl.txt>
  92.  * @link      http://www.ar-php.org
  93.  */ 
  94. {
  95.     private $_glyphs   null;
  96.     private $_hex      null;
  97.     private $_prevLink null;
  98.     private $_nextLink null;
  99.     private $_vowel    null;
  100.  
  101.     /**
  102.      * Loads initialize values
  103.      *
  104.      * @ignore
  105.      */         
  106.     public function __construct()
  107.     {
  108.         $this->_prevLink '،؟؛ـئبتثجحخسشصضطظعغفقكلمنهي';
  109.         $this->_nextLink 'ـآأؤإائبةتثجحخدذرزسشصضطظعغفقكلمنهوىي';
  110.         $this->_vowel    'ًٌٍَُِّْ';
  111.  
  112.         /*
  113.          $this->_glyphs['ً']  = array('FE70','FE71');
  114.          $this->_glyphs['ٌ']  = array('FE72','FE72');
  115.          $this->_glyphs['ٍ']  = array('FE74','FE74');
  116.          $this->_glyphs['َ']  = array('FE76','FE77');
  117.          $this->_glyphs['ُ']  = array('FE78','FE79');
  118.          $this->_glyphs['ِ']  = array('FE7A','FE7B');
  119.          $this->_glyphs['ّ']  = array('FE7C','FE7D');
  120.          $this->_glyphs['ْ']  = array('FE7E','FE7E');
  121.          */
  122.          
  123.         $this->_glyphs 'ًٌٍَُِّْٰ';
  124.         $this->_hex    '064B064B064B064B064C064C064C064C064D064D064D064D064E064E';
  125.         $this->_hex   .= '064E064E064F064F064F064F06500650065006500651065106510651';
  126.         $this->_hex   .= '06520652065206520670067006700670';
  127.  
  128.         $this->_glyphs .= 'ءآأؤإئاب';
  129.         $this->_hex    .= 'FE80FE80FE80FE80FE81FE82FE81FE82FE83FE84FE83FE84FE85FE86';
  130.         $this->_hex    .= 'FE85FE86FE87FE88FE87FE88FE89FE8AFE8BFE8CFE8DFE8EFE8DFE8E';
  131.         $this->_hex    .= 'FE8FFE90FE91FE92';
  132.  
  133.         $this->_glyphs .= 'ةتثجحخدذ';
  134.         $this->_hex    .= 'FE93FE94FE93FE94FE95FE96FE97FE98FE99FE9AFE9BFE9CFE9DFE9E';
  135.         $this->_hex    .= 'FE9FFEA0FEA1FEA2FEA3FEA4FEA5FEA6FEA7FEA8FEA9FEAAFEA9FEAA';
  136.         $this->_hex    .= 'FEABFEACFEABFEAC';
  137.  
  138.         $this->_glyphs .= 'رزسشصضطظ';
  139.         $this->_hex    .= 'FEADFEAEFEADFEAEFEAFFEB0FEAFFEB0FEB1FEB2FEB3FEB4FEB5FEB6';
  140.         $this->_hex    .= 'FEB7FEB8FEB9FEBAFEBBFEBCFEBDFEBEFEBFFEC0FEC1FEC2FEC3FEC4';
  141.         $this->_hex    .= 'FEC5FEC6FEC7FEC8';
  142.  
  143.         $this->_glyphs .= 'عغفقكلمن';
  144.         $this->_hex    .= 'FEC9FECAFECBFECCFECDFECEFECFFED0FED1FED2FED3FED4FED5FED6';
  145.         $this->_hex    .= 'FED7FED8FED9FEDAFEDBFEDCFEDDFEDEFEDFFEE0FEE1FEE2FEE3FEE4';
  146.         $this->_hex    .= 'FEE5FEE6FEE7FEE8';
  147.  
  148.         $this->_glyphs .= 'هوىيـ،؟؛';
  149.         $this->_hex    .= 'FEE9FEEAFEEBFEECFEEDFEEEFEEDFEEEFEEFFEF0FEEFFEF0FEF1FEF2';
  150.         $this->_hex    .= 'FEF3FEF40640064006400640060C060C060C060C061F061F061F061F';
  151.         $this->_hex    .= '061B061B061B061B';
  152.  
  153.         // Support the extra 4 Persian letters (p), (ch), (zh) and (g)
  154.         // This needs value in getGlyphs function to be 52 instead of 48
  155.         // $this->_glyphs .= chr(129).chr(141).chr(142).chr(144);
  156.         // $this->_hex    .= 'FB56FB57FB58FB59FB7AFB7BFB7CFB7DFB8AFB8BFB8AFB8BFB92';
  157.         // $this->_hex    .= 'FB93FB94FB95';
  158.         //
  159.         // $this->_prevLink .= chr(129).chr(141).chr(142).chr(144);
  160.         // $this->_nextLink .= chr(129).chr(141).chr(142).chr(144);
  161.         //
  162.         // Example:     $text = 'نمونة قلم: لاگچ ژافپ';
  163.         // Email Yossi Beck <yosbeck@gmail.com> ask him to save that example
  164.         // string using ANSI encoding in Notepad
  165.         $this->_glyphs .= '';
  166.         $this->_hex    .= '';
  167.         
  168.         $this->_glyphs .= 'لآلألإلا';
  169.         $this->_hex    .= 'FEF5FEF6FEF5FEF6FEF7FEF8FEF7FEF8FEF9FEFAFEF9FEFAFEFBFEFC';
  170.         $this->_hex    .= 'FEFBFEFC';
  171.     }
  172.     
  173.     /**
  174.      * Get glyphs
  175.      * 
  176.      * @param string  $char Char
  177.      * @param integer $type Type
  178.      * 
  179.      * @return string 
  180.      */                                  
  181.     protected function getGlyphs($char$type)
  182.     {
  183.  
  184.         $pos mb_strpos($this->_glyphs$char);
  185.         
  186.         if ($pos 49{
  187.             $pos ($pos-49)/49;
  188.         }
  189.         
  190.         $pos $pos*16 $type*4;
  191.         
  192.         return substr($this->_hex$pos4);
  193.     }
  194.     
  195.     /**
  196.      * Convert Arabic Windows-1256 charset string into glyph joining in UTF-8
  197.      * hexadecimals stream
  198.      *      
  199.      * @param string $str Arabic string in Windows-1256 charset
  200.      *      
  201.      * @return string Arabic glyph joining in UTF-8 hexadecimals stream
  202.      * @author Khaled Al-Sham'aa <khaled@ar-php.org>
  203.      */
  204.     protected function preConvert($str)
  205.     {
  206.         $crntChar null;
  207.         $prevChar null;
  208.         $nextChar null;
  209.         $output   '';
  210.         
  211.         $_temp mb_strlen($str);
  212.  
  213.         for ($i 0$i $_temp$i++{
  214.             $chars[mb_substr($str$i1);
  215.         }
  216.  
  217.         $max count($chars);
  218.  
  219.         for ($i $max 1$i >= 0$i--{
  220.             $crntChar $chars[$i];
  221.             $prevChar ' ';
  222.             
  223.             if ($i 0{
  224.                 $prevChar $chars[$i 1];
  225.             }
  226.             
  227.             if ($prevChar && mb_strpos($this->_vowel$prevChar!== false{
  228.                 $prevChar $chars[$i 2];
  229.                 if ($prevChar && mb_strpos($this->_vowel$prevChar!== false{
  230.                     $prevChar $chars[$i 3];
  231.                 }
  232.             }
  233.             
  234.             $Reversed    false;
  235.             $flip_arr    ')]>}';
  236.             $ReversedChr '([<{';
  237.             
  238.             if ($crntChar && mb_strpos($flip_arr$crntChar!== false{
  239.                 $crntChar $ReversedChr[mb_strpos($flip_arr$crntChar)];
  240.                 $Reversed true;
  241.             else {
  242.                 $Reversed false;
  243.             }
  244.             
  245.             if ($crntChar && !$Reversed 
  246.                 && (mb_strpos($ReversedChr$crntChar!== false)
  247.             {
  248.                 $crntChar $flip_arr[mb_strpos($ReversedChr$crntChar)];
  249.             }
  250.             
  251.             if (ord($crntChar128{
  252.                 $output  .= $crntChar;
  253.                 $nextChar $crntChar;
  254.                 continue;
  255.             }
  256.             
  257.             if ($crntChar == 'ل' && isset($chars[$i 1]
  258.                 && (mb_strpos('آأإا'$chars[$i 1]!== false)
  259.             {
  260.                 continue;
  261.             }
  262.             
  263.             if ($crntChar && mb_strpos($this->_vowel$crntChar!== false{
  264.                 if ((mb_strpos($this->_nextLink$chars[$i 1]!== false
  265.                     && (mb_strpos($this->_prevLink$prevChar!== false)
  266.                 {
  267.                     $output .= '&#x' $this->getGlyphs($crntChar1';';
  268.                 else {
  269.                     $output .= '&#x' $this->getGlyphs($crntChar0';';
  270.                 }
  271.                 continue;
  272.             }
  273.             
  274.             $form 0;
  275.             
  276.             if (($prevChar == 'لا' || $prevChar == 'لآ' || $prevChar == 'لأ' 
  277.                 || $prevChar == 'لإ' || $prevChar == 'ل'
  278.                 && (mb_strpos('آأإا'$crntChar!== false)
  279.             {
  280.                 if (mb_strpos($this->_prevLink$chars[$i 2]!== false{
  281.                     $form++;
  282.                 }
  283.                 
  284.                 if (mb_strpos($this->_vowel$chars[$i 1])) {
  285.                     $output .= '&#x';
  286.                     $output .= $this->getGlyphs($crntChar$form).';';
  287.                 else {
  288.                     $output .= '&#x';
  289.                     $output .= $this->getGlyphs($prevChar.$crntChar$form).';';
  290.                 }
  291.                 $nextChar $prevChar;
  292.                 continue;
  293.             }
  294.             
  295.             if ($prevChar && mb_strpos($this->_prevLink$prevChar!== false{
  296.                 $form++;
  297.             }
  298.             
  299.             if ($nextChar && mb_strpos($this->_nextLink$nextChar!== false{
  300.                 $form += 2;
  301.             }
  302.             
  303.             $output  .= '&#x' $this->getGlyphs($crntChar$form';';
  304.             $nextChar $crntChar;
  305.         }
  306.         
  307.         // from Arabic Presentation Forms-B, Range: FE70-FEFF, 
  308.         // file "UFE70.pdf" (in reversed order)
  309.         // into Arabic Presentation Forms-A, Range: FB50-FDFF, file "UFB50.pdf"
  310.         // Example: $output = str_replace('&#xFEA0;&#xFEDF;', '&#xFCC9;', $output);
  311.         // Lam Jeem
  312.  
  313.         $output $this->decodeEntities($output$exclude array('&'));
  314.         return $output;
  315.     }
  316.     
  317.     /**
  318.      * Regression analysis calculate roughly the max number of character fit in
  319.      * one A4 page line for a given font size.
  320.      *      
  321.      * @param integer $font Font size
  322.      *      
  323.      * @return integer Maximum number of characters per line
  324.      * @author Khaled Al-Sham'aa <khaled@ar-php.org>
  325.      */
  326.     public function a4MaxChars($font)
  327.     {
  328.         $x 381.6 31.57 $font 1.182 pow($font20.02052 
  329.              pow($font30.0001342 pow($font4);
  330.         return floor($x 2);
  331.     }
  332.     
  333.     /**
  334.      * Calculate the lines number of given Arabic text and font size that will
  335.      * fit in A4 page size
  336.      *      
  337.      * @param string  $str  Arabic string you would like to split it into lines
  338.      * @param integer $font Font size
  339.      *                    
  340.      * @return integer Number of lines for a given Arabic string in A4 page size
  341.      * @author Khaled Al-Sham'aa <khaled@ar-php.org>
  342.      */
  343.     public function a4Lines($str$font)
  344.     {
  345.         $str str_replace(array("\r\n""\n""\r")"\n"$str);
  346.         
  347.         $lines     0;
  348.         $chars     0;
  349.         $words     explode(' '$str);
  350.         $w_count   count($words);
  351.         $max_chars $this->a4MaxChars($font);
  352.         
  353.         for ($i 0$i $w_count$i++{
  354.             $w_len mb_strlen($words[$i]1;
  355.             
  356.             if ($chars $w_len $max_chars{
  357.                 if (mb_strpos($words[$i]"\n"!== false{
  358.                     $words_nl explode("\n"$words[$i]);
  359.                     
  360.                     $nl_num count($words_nl1;
  361.                     for ($j 1$j $nl_num$j++{
  362.                         $lines++;
  363.                     }
  364.                     
  365.                     $chars mb_strlen($words_nl[$nl_num]1;
  366.                 else {
  367.                     $chars += $w_len;
  368.                 }
  369.             else {
  370.                 $lines++;
  371.                 $chars $w_len;
  372.             }
  373.         }
  374.         $lines++;
  375.         
  376.         return $lines;
  377.     }
  378.     
  379.     /**
  380.      * Convert Arabic Windows-1256 charset string into glyph joining in UTF-8
  381.      * hexadecimals stream (take care of whole the document including English
  382.      * sections as well as numbers and arcs etc...)
  383.      *                    
  384.      * @param string  $str       Arabic string in Windows-1256 charset
  385.      * @param integer $max_chars Max number of chars you can fit in one line
  386.      * @param boolean $hindo     If true use Hindo digits else use Arabic digits
  387.      *                    
  388.      * @return string Arabic glyph joining in UTF-8 hexadecimals stream (take
  389.      *                 care of whole document including English sections as well
  390.      *                 as numbers and arcs etc...)
  391.      * @author Khaled Al-Sham'aa <khaled@ar-php.org>
  392.      */
  393.     public function utf8Glyphs($str$max_chars 50$hindo true)
  394.     {
  395.         $str str_replace(array("\r\n""\n""\r")" \n "$str);
  396.         $str str_replace("\t""        "$str);
  397.         
  398.         $lines   array();
  399.         $words   explode(' '$str);
  400.         $w_count count($words);
  401.         $c_chars 0;
  402.         $c_words array();
  403.         
  404.         $english  array();
  405.         $en_index = -1;
  406.         
  407.         $en_words array();
  408.         $en_stack array();
  409.  
  410.         for ($i 0$i $w_count$i++{
  411.             $pattern  '/^(\n?)';
  412.             $pattern .= '[a-z\d\\/\@\#\$\%\^\&\*\(\)\_\~\"\'\[\]\{\}\;\,\|\-\.\:!]*';
  413.             $pattern .= '([\.\:\+\=\-\!،؟]?)$/i';
  414.             
  415.             if (preg_match($pattern$words[$i]$matches)) {
  416.                 if ($matches[1]{
  417.                     $words[$imb_substr($words[$i]1).$matches[1];
  418.                 }
  419.                 if ($matches[2]{
  420.                     $words[$i$matches[2].mb_substr($words[$i]0-1);
  421.                 }
  422.                 $words[$istrrev($words[$i]);
  423.                 array_push($english$words[$i]);
  424.                 if ($en_index == -1{
  425.                     $en_index $i;
  426.                 }
  427.                 $en_words[true;
  428.             elseif ($en_index != -1{
  429.                 $en_count count($english);
  430.                 
  431.                 for ($j 0$j $en_count$j++{
  432.                     $words[$en_index $j$english[$en_count $j];
  433.                 }
  434.                 
  435.                 $en_index = -1;
  436.                 $english  array();
  437.                 
  438.                 $en_words[false;
  439.             else {
  440.                 $en_words[false;
  441.             }
  442.         }
  443.  
  444.         if ($en_index != -1{
  445.             $en_count count($english);
  446.             
  447.             for ($j 0$j $en_count$j++{
  448.                 $words[$en_index $j$english[$en_count $j];
  449.             }
  450.         }
  451.  
  452.         // need more work to fix lines starts by English words
  453.         if ($en_start{
  454.             $last true;
  455.             $from 0;
  456.             
  457.             foreach ($en_words as $key => $value{
  458.                 if ($last !== $value{
  459.                     $to $key 1;
  460.                     array_push($en_stackarray($from$to));
  461.                     $from $key;
  462.                 }
  463.                 $last $value;
  464.             }
  465.             
  466.             array_push($en_stackarray($from$key));
  467.             
  468.             $new_words array();
  469.             
  470.             while (list($from$toarray_pop($en_stack)) {
  471.                 for ($i $from$i <= $to$i++{
  472.                     $new_words[$words[$i];
  473.                 }
  474.             }
  475.             
  476.             $words $new_words;
  477.         }
  478.  
  479.         for ($i 0$i $w_count$i++{
  480.             $w_len mb_strlen($words[$i]1;
  481.             
  482.             if ($c_chars $w_len $max_chars{
  483.                 if (mb_strpos($words[$i]"\n"!== false{
  484.                     $words_nl explode("\n"$words[$i]);
  485.                     
  486.                     array_push($c_words$words_nl[0]);
  487.                     array_push($linesimplode(' '$c_words));
  488.                     
  489.                     $nl_num count($words_nl1;
  490.                     for ($j 1$j $nl_num$j++{
  491.                         array_push($lines$words_nl[$j]);
  492.                     }
  493.                     
  494.                     $c_words array($words_nl[$nl_num]);
  495.                     $c_chars mb_strlen($words_nl[$nl_num]1;
  496.                 else {
  497.                     array_push($c_words$words[$i]);
  498.                     $c_chars += $w_len;
  499.                 }
  500.             else {
  501.                 array_push($linesimplode(' '$c_words));
  502.                 $c_words array($words[$i]);
  503.                 $c_chars $w_len;
  504.             }
  505.         }
  506.         array_push($linesimplode(' '$c_words));
  507.         
  508.         $maxLine count($lines);
  509.         $output  '';
  510.         
  511.         for ($j $maxLine 1$j >= 0$j--{
  512.             $output .= $lines[$j"\n";
  513.         }
  514.         
  515.         $output rtrim($output);
  516.         
  517.         $output $this->preConvert($output);
  518.         if ($hindo{
  519.             $nums   array(
  520.                 '0''1''2''3''4'
  521.                 '5''6''7''8''9'
  522.             );
  523.             $arNums array(
  524.                 '٠''١''٢''٣''٤',
  525.                 '٥''٦''٧''٨''٩'
  526.             );
  527.             
  528.             foreach ($nums as $k => $v{
  529.                 $p_nums[$k'/'.$v.'/ui';
  530.             }
  531.             $output preg_replace($p_nums$arNums$output);
  532.             
  533.             foreach ($arNums as $k => $v{
  534.                 $p_arNums[$k'/([a-z-\d]+)'.$v.'/ui';
  535.             }
  536.             foreach ($nums as $k => $v{
  537.                 $r_nums[$k'${1}'.$v;
  538.             }
  539.             $output preg_replace($p_arNums$r_nums$output);
  540.             
  541.             foreach ($arNums as $k => $v{
  542.                 $p_arNums[$k'/'.$v.'([a-z-\d]+)/ui';
  543.             }
  544.             foreach ($nums as $k => $v{
  545.                 $r_nums[$k$v.'${1}';
  546.             }
  547.             $output preg_replace($p_arNums$r_nums$output);
  548.         }
  549.  
  550.         return $output;
  551.     }
  552.     
  553.     /**
  554.      * Decode all HTML entities (including numerical ones) to regular UTF-8 bytes.
  555.      * Double-escaped entities will only be decoded once
  556.      * ("&amp;lt;" becomes "&lt;", not "<").
  557.      *                   
  558.      * @param string $text    The text to decode entities in.
  559.      * @param array  $exclude An array of characters which should not be decoded.
  560.      *                         For example, array('<', '&', '"'). This affects
  561.      *                         both named and numerical entities.
  562.      *                        
  563.      * @return string 
  564.      */
  565.     protected function decodeEntities($text$exclude array())
  566.     {
  567.         static $table;
  568.         
  569.         // We store named entities in a table for quick processing.
  570.         if (!isset($table)) {
  571.             // Get all named HTML entities.
  572.             $table array_flip(get_html_translation_table(HTML_ENTITIES));
  573.             
  574.             // PHP gives us ISO-8859-1 data, we need UTF-8.
  575.             $table array_map('utf8_encode'$table);
  576.             
  577.             // Add apostrophe (XML)
  578.             $table['&apos;'"'";
  579.         }
  580.         $newtable array_diff($table$exclude);
  581.         
  582.         // Use a regexp to select all entities in one pass, to avoid decoding 
  583.         // double-escaped entities twice.
  584.         //return preg_replace('/&(#x?)?([A-Za-z0-9]+);/e', 
  585.         //                    '$this->decodeEntities2("$1", "$2", "$0", $newtable, 
  586.         //                                             $exclude)', $text);
  587.  
  588.         $pieces explode('&'$text);
  589.         $text   array_shift($pieces);
  590.         foreach ($pieces as $piece{
  591.             if ($piece[0== '#'{
  592.                 if ($piece[1== 'x'{
  593.                     $one '#x';
  594.                 else {
  595.                     $one '#';
  596.                 }
  597.             else {
  598.                 $one '';
  599.             }
  600.             $end   mb_strpos($piece';');
  601.             $start mb_strlen($one);
  602.             
  603.             $two   mb_substr($piece$start$end $start);
  604.             $zero  '&'.$one.$two.';';
  605.             $text .= $this->decodeEntities2($one$two$zero$newtable$exclude).
  606.                      mb_substr($piece$end+1);
  607.         }
  608.         return $text;
  609.     }
  610.     
  611.     /**
  612.      * Helper function for decodeEntities
  613.      * 
  614.      * @param string $prefix    Prefix
  615.      * @param string $codepoint Codepoint
  616.      * @param string $original  Original
  617.      * @param array  &$table    Store named entities in a table
  618.      * @param array  &$exclude  An array of characters which should not be decoded
  619.      * 
  620.      * @return string 
  621.      */
  622.     protected function decodeEntities2(
  623.         $prefix$codepoint$original&$table&$exclude
  624.     {
  625.         // Named entity
  626.         if (!$prefix{
  627.             if (isset($table[$original])) {
  628.                 return $table[$original];
  629.             else {
  630.                 return $original;
  631.             }
  632.         }
  633.         
  634.         // Hexadecimal numerical entity
  635.         if ($prefix == '#x'{
  636.             $codepoint base_convert($codepoint1610);
  637.         }
  638.         
  639.         // Encode codepoint as UTF-8 bytes
  640.         if ($codepoint 0x80{
  641.             $str chr($codepoint);
  642.         elseif ($codepoint 0x800{
  643.             $str chr(0xC0 ($codepoint >> 6)) 
  644.                    chr(0x80 ($codepoint 0x3F));
  645.         elseif ($codepoint 0x10000{
  646.             $str chr(0xE0 ($codepoint >> 12)) 
  647.                    chr(0x80 (($codepoint >> 60x3F)) 
  648.                    chr(0x80 ($codepoint 0x3F));
  649.         elseif ($codepoint 0x200000{
  650.             $str chr(0xF0 ($codepoint >> 18)) 
  651.                    chr(0x80 (($codepoint >> 120x3F)) 
  652.                    chr(0x80 (($codepoint >> 60x3F)) 
  653.                    chr(0x80 ($codepoint 0x3F));
  654.         }
  655.         
  656.         // Check for excluded characters
  657.         if (in_array($str$exclude)) {
  658.             return $original;
  659.         else {
  660.             return $str;
  661.         }
  662.     }
  663. }

Documentation generated on Mon, 14 Jan 2013 17:48:48 +0100 by phpDocumentor 1.4.0