[ Index ]
 

Code source de SPIP 1.9.2c

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/ecrire/inc/ -> charsets.php (source)

   1  <?php
   2  
   3  /***************************************************************************\
   4   *  SPIP, Systeme de publication pour l'internet                           *
   5   *                                                                         *
   6   *  Copyright (c) 2001-2007                                                *
   7   *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
   8   *                                                                         *
   9   *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  10   *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
  11  \***************************************************************************/
  12  
  13  
  14  //
  15  if (!defined("_ECRIRE_INC_VERSION")) return;
  16  
  17  
  18  /*
  19   * charsets supportes en natif : voir les tables dans ecrire/charsets/
  20   * les autres charsets sont supportes via mbstring()
  21   */
  22  
  23  // http://doc.spip.org/@load_charset
  24  function load_charset ($charset = 'AUTO', $langue_site = 'AUTO') {
  25      if ($charset == 'AUTO')
  26          $charset = $GLOBALS['meta']['charset'];
  27      $charset = trim(strtolower($charset));
  28      if (isset($GLOBALS['CHARSET'][$charset]))
  29          return $charset;
  30  
  31      if ($langue_site == 'AUTO')
  32          $langue_site = $GLOBALS['meta']['langue_site'];
  33  
  34      if ($charset == 'utf-8') {
  35          $GLOBALS['CHARSET'][$charset] = array();
  36          return $charset;
  37      }
  38      
  39      // Quelques synonymes
  40      if ($charset == '') $charset = 'iso-8859-1';
  41      else if ($charset == 'windows-1250') $charset = 'cp1250';
  42      else if ($charset == 'windows-1251') $charset = 'cp1251';
  43      else if ($charset == 'windows-1256') $charset = 'cp1256';
  44  
  45      if (include_spip('charsets/'.$charset)) {
  46          return $charset;
  47      } else {
  48          spip_log("Erreur: pas de fichier de conversion 'charsets/$charset'");
  49          $GLOBALS['CHARSET'][$charset] = array();
  50          return false;
  51      }
  52  }
  53  
  54  //
  55  // Verifier qu'on peut utiliser mb_string
  56  //
  57  // http://doc.spip.org/@init_mb_string
  58  function init_mb_string() {
  59      static $mb;
  60  
  61      // verifier que tout est present (fonctions mb_string pour php >= 4.0.6)
  62      // et que le charset interne est connu de mb_string
  63      if (!$mb) {
  64          if (function_exists('mb_internal_encoding')
  65          AND function_exists('mb_detect_order')
  66          AND function_exists('mb_substr')
  67          AND function_exists('mb_strlen')
  68          AND function_exists('mb_encode_mimeheader')
  69          AND function_exists('mb_encode_numericentity')
  70          AND function_exists('mb_decode_numericentity')
  71          AND mb_detect_order($GLOBALS['meta']['charset'])
  72          ) {
  73              mb_internal_encoding('utf-8');
  74              $mb = 1;
  75          } else
  76              $mb = -1;
  77      }
  78  
  79      return ($mb == 1);
  80  }
  81  
  82  // Detecter les versions buggees d'iconv
  83  // http://doc.spip.org/@test_iconv
  84  function test_iconv() {
  85      static $iconv_ok;
  86  
  87      if (!$iconv_ok) {
  88          if (!function_exists('iconv'))
  89              $iconv_ok = -1;
  90          else {
  91              if (utf_32_to_unicode(@iconv('utf-8', 'utf-32', 'chaine de test')) == 'chaine de test')
  92                  $iconv_ok = 1;
  93              else
  94                  $iconv_ok = -1;
  95          }
  96      }
  97      return ($iconv_ok == 1);
  98  }
  99  
 100  // Test de fonctionnement du support UTF-8 dans PCRE
 101  // (contournement bug Debian Woody)
 102  // http://doc.spip.org/@test_pcre_unicode
 103  function test_pcre_unicode() {
 104      static $pcre_ok = 0;
 105  
 106      if (!$pcre_ok) {
 107          $s = " ".chr(195).chr(169)."t".chr(195).chr(169)." ";
 108          if (preg_match(',\W\w\w\w\W,uS', $s)) $pcre_ok = 1;
 109          else $pcre_ok = -1;
 110      }
 111      return $pcre_ok == 1;
 112  }
 113  
 114  // Plages alphanumeriques (incomplet...)
 115  // http://doc.spip.org/@pcre_lettres_unicode
 116  function pcre_lettres_unicode() {
 117      static $plage_unicode;
 118  
 119      if (!$plage_unicode) {
 120          if (test_pcre_unicode()) {
 121              // cf. http://www.unicode.org/charts/
 122              $plage_unicode = '\w' // iso-latin
 123                  . '\x{100}-\x{24f}' // europeen etendu
 124                  . '\x{300}-\x{1cff}' // des tas de trucs
 125              ;
 126          }
 127          else {
 128              // fallback a trois sous
 129              $plage_unicode = '\w';
 130          }
 131      }
 132      return $plage_unicode;
 133  }
 134  
 135  // Plage ponctuation de 0x2000 a 0x206F
 136  // (i.e. de 226-128-128 a 226-129-176)
 137  // http://doc.spip.org/@plage_punct_unicode
 138  function plage_punct_unicode() {
 139      return '\xE2(\x80[\x80-\xBF]|\x81[\x80-\xAF])';
 140  }
 141  
 142  // corriger caracteres non-conformes : 128-159
 143  // cf. charsets/iso-8859-1.php (qu'on recopie ici pour aller plus vite)
 144  // http://doc.spip.org/@corriger_caracteres_windows
 145  function corriger_caracteres_windows($texte, $charset='AUTO') {
 146      static $trans;
 147  
 148      if ($charset=='AUTO') $charset = $GLOBALS['meta']['charset'];
 149      if ($charset == 'utf-8') {
 150          $p = chr(194);
 151      } else if ($charset == 'iso-8859-1') {
 152          $p = '';
 153      } else
 154          return $texte;
 155  
 156      if (!isset($trans[$charset])) {
 157          $trans[$charset] = array(
 158              $p.chr(128) => "&#8364;",
 159              $p.chr(129) => ' ', # pas affecte
 160              $p.chr(130) => "&#8218;",
 161              $p.chr(131) => "&#402;",
 162              $p.chr(132) => "&#8222;",
 163              $p.chr(133) => "&#8230;",
 164              $p.chr(134) => "&#8224;",
 165              $p.chr(135) => "&#8225;",
 166              $p.chr(136) => "&#710;",
 167              $p.chr(137) => "&#8240;",
 168              $p.chr(138) => "&#352;",
 169              $p.chr(139) => "&#8249;",
 170              $p.chr(140) => "&#338;",
 171              $p.chr(141) => ' ', # pas affecte
 172              $p.chr(142) => "&#381;",
 173              $p.chr(143) => ' ', # pas affecte
 174              $p.chr(144) => ' ', # pas affecte
 175              $p.chr(145) => "&#8216;",
 176              $p.chr(146) => "&#8217;",
 177              $p.chr(147) => "&#8220;",
 178              $p.chr(148) => "&#8221;",
 179              $p.chr(149) => "&#8226;",
 180              $p.chr(150) => "&#8211;",
 181              $p.chr(151) => "&#8212;",
 182              $p.chr(152) => "&#732;",
 183              $p.chr(153) => "&#8482;", 
 184              $p.chr(154) => "&#353;",
 185              $p.chr(155) => "&#8250;",
 186              $p.chr(156) => "&#339;",
 187              $p.chr(157) => ' ', # pas affecte
 188              $p.chr(158) => "&#382;",
 189              $p.chr(159) => "&#376;",
 190          );
 191      }
 192      return strtr($texte, $trans[$charset]);
 193  }
 194  
 195  
 196  //
 197  // Transformer les &eacute; en &#123;
 198  // $secure = true pour *ne pas convertir* les caracteres malins &lt; &amp; etc.
 199  //
 200  // http://doc.spip.org/@html2unicode
 201  function html2unicode($texte, $secure=false) {
 202      if (strpos($texte,'&') === false) return $texte;
 203      static $trans;
 204      if (!$trans) {
 205          global $CHARSET;
 206          load_charset('html');
 207          foreach ($CHARSET['html'] as $key => $val) {
 208              $trans["&$key;"] = $val;
 209          }
 210      }
 211  
 212      if ($secure)
 213          return strtr($texte, $trans);
 214      else
 215          return strtr(strtr($texte, $trans),
 216              array('&amp;'=>'&', '&quot;'=>'"', '&lt;'=>'<', '&gt;'=>'>')
 217          );
 218  }
 219  
 220  //
 221  // Transformer les &eacute; en &#123;
 222  //
 223  // http://doc.spip.org/@mathml2unicode
 224  function mathml2unicode($texte) {
 225      static $trans;
 226      if (!$trans) {
 227          global $CHARSET;
 228          load_charset('mathml');
 229          
 230          foreach ($CHARSET['mathml'] as $key => $val)
 231              $trans["&$key;"] = $val;
 232      }
 233  
 234      return strtr($texte, $trans);
 235  }
 236  
 237  
 238  //
 239  // Transforme une chaine en entites unicode &#129;
 240  //
 241  // Note: l'argument $forcer est obsolete : il visait a ne pas
 242  // convertir les accents iso-8859-1
 243  // http://doc.spip.org/@charset2unicode
 244  function charset2unicode($texte, $charset='AUTO' /* $forcer: obsolete*/) {
 245      static $trans;
 246  
 247      if ($charset == 'AUTO')
 248          $charset = $GLOBALS['meta']['charset'];
 249  
 250      if ($charset == '') $charset = 'iso-8859-1';
 251      $charset = strtolower($charset);
 252  
 253      switch ($charset) {
 254      case 'utf-8':
 255          return utf_8_to_unicode($texte);
 256  
 257      case 'iso-8859-1':
 258          $texte = corriger_caracteres_windows($texte, 'iso-8859-1');
 259          // pas de break; ici, on suit sur default:
 260  
 261      default:
 262          // mbstring presente ?
 263          if (init_mb_string()) {
 264              if ($order = mb_detect_order() # mb_string connait-il $charset?
 265              AND mb_detect_order($charset)) {
 266                  $s = mb_convert_encoding($texte, 'utf-8', $charset);
 267                  if ($s && $s != $texte) return utf_8_to_unicode($s);
 268              }
 269              mb_detect_order($order); # remettre comme precedemment
 270          }
 271  
 272          // Sinon, peut-etre connaissons-nous ce charset ?
 273          if (!isset($trans[$charset])) {
 274              global $CHARSET;
 275              if ($cset = load_charset($charset)
 276              AND is_array($CHARSET[$cset]))
 277                  foreach ($CHARSET[$cset] as $key => $val) {
 278                      $trans[$charset][chr($key)] = '&#'.$val.';';
 279              }
 280          }
 281          if (count($trans[$charset]))
 282              return strtr($texte, $trans[$charset]);
 283  
 284          // Sinon demander a iconv (malgre le fait qu'il coupe quand un
 285          // caractere n'appartient pas au charset, mais c'est un probleme
 286          // surtout en utf-8, gere ci-dessus)
 287          if (test_iconv()) {
 288              $s = iconv($charset, 'utf-32le', $texte);
 289              if ($s) return utf_32_to_unicode($s);
 290          }
 291  
 292          // Au pire ne rien faire
 293          spip_log("erreur charset '$charset' non supporte");
 294          return $texte;
 295      }
 296  }
 297  
 298  //
 299  // Transforme les entites unicode &#129; dans le charset specifie
 300  // Attention on ne transforme pas les entites < &#128; car si elles
 301  // ont ete encodees ainsi c'est a dessein
 302  // http://doc.spip.org/@unicode2charset
 303  function unicode2charset($texte, $charset='AUTO') {
 304      static $CHARSET_REVERSE;
 305      static $trans = array();
 306      
 307      if ($charset == 'AUTO')
 308          $charset = $GLOBALS['meta']['charset'];
 309  
 310      switch($charset) {
 311      case 'utf-8':
 312          return unicode_to_utf_8($texte);
 313          break;
 314  
 315      default:
 316          $charset = load_charset($charset);
 317  
 318          if (!is_array($CHARSET_REVERSE[$charset])) {
 319              $CHARSET_REVERSE[$charset] = array_flip($GLOBALS['CHARSET'][$charset]);
 320          }
 321  
 322          if (!isset($trans[$charset])){
 323              $trans[$charset]=array();
 324              $t = &$trans[$charset];
 325              for($e=128;$e<255;$e++){
 326                  $h = dechex($e);
 327                  if ($s = isset($CHARSET_REVERSE[$charset][$e])){
 328                      $s = $CHARSET_REVERSE[$charset][$e];
 329                      $t['&#'.$e.';'] = $t['&#0'.$e.';'] = $t['&#00'.$e.';'] = chr($s);
 330                      $t['&#x'.$h.';'] = $t['&#x0'.$h.';'] = $t['&#x00'.$h.';'] = chr($s);
 331                  }
 332                  else{
 333                      $t['&#'.$e.';'] = $t['&#0'.$e.';'] = $t['&#00'.$e.';'] = chr($e);
 334                      $t['&#x'.$h.';'] = $t['&#x0'.$h.';'] = $t['&#x00'.$h.';'] = chr($e);
 335                  }
 336              }
 337          }
 338          $texte = strtr($texte, $trans[$charset]);
 339          return $texte;
 340      }
 341  }
 342  
 343  
 344  // Importer un texte depuis un charset externe vers le charset du site
 345  // (les caracteres non resolus sont transformes en &#123;)
 346  // http://doc.spip.org/@importer_charset
 347  function importer_charset($texte, $charset = 'AUTO') {
 348      return unicode2charset(charset2unicode($texte, $charset));
 349  }
 350  
 351  // UTF-8
 352  // http://doc.spip.org/@utf_8_to_unicode
 353  function utf_8_to_unicode($source) {
 354  
 355      // mb_string : methode rapide
 356      if (init_mb_string()) {
 357          $convmap = array(0x7F, 0xFFFFFF, 0x0, 0xFFFFFF);
 358          return mb_encode_numericentity($source, $convmap, 'UTF-8');
 359      }
 360  
 361      // Sinon methode pas a pas
 362      static $decrement;
 363      static $shift;
 364  
 365      // Cf. php.net, par Ronen. Adapte pour compatibilite < php4
 366      if (!is_array($decrement)) {
 367          // array used to figure what number to decrement from character order value
 368          // according to number of characters used to map unicode to ascii by utf-8
 369          $decrement[4] = 240;
 370          $decrement[3] = 224;
 371          $decrement[2] = 192;
 372          $decrement[1] = 0;
 373          // the number of bits to shift each charNum by
 374          $shift[1][0] = 0;
 375          $shift[2][0] = 6;
 376          $shift[2][1] = 0;
 377          $shift[3][0] = 12;
 378          $shift[3][1] = 6;
 379          $shift[3][2] = 0;
 380          $shift[4][0] = 18;
 381          $shift[4][1] = 12;
 382          $shift[4][2] = 6;
 383          $shift[4][3] = 0;
 384      }
 385  
 386      $pos = 0;
 387      $len = strlen ($source);
 388      $encodedString = '';
 389      while ($pos < $len) {
 390          $char = '';
 391          $ischar = false;
 392          $asciiPos = ord (substr ($source, $pos, 1));
 393          if (($asciiPos >= 240) && ($asciiPos <= 255)) {
 394              // 4 chars representing one unicode character
 395              $thisLetter = substr ($source, $pos, 4);
 396              $pos += 4;
 397          }
 398          else if (($asciiPos >= 224) && ($asciiPos <= 239)) {
 399              // 3 chars representing one unicode character
 400              $thisLetter = substr ($source, $pos, 3);
 401              $pos += 3;
 402          }
 403          else if (($asciiPos >= 192) && ($asciiPos <= 223)) {
 404              // 2 chars representing one unicode character
 405              $thisLetter = substr ($source, $pos, 2);
 406              $pos += 2;
 407          }
 408          else {
 409              // 1 char (lower ascii)
 410              $thisLetter = substr ($source, $pos, 1);
 411              $pos += 1;
 412              $char = $thisLetter;
 413              $ischar = true;
 414          }
 415  
 416          if ($ischar)
 417              $encodedString .= $char;
 418          else {    // process the string representing the letter to a unicode entity
 419              $thisLen = strlen ($thisLetter);
 420              $thisPos = 0;
 421              $decimalCode = 0;
 422              while ($thisPos < $thisLen) {
 423                  $thisCharOrd = ord (substr ($thisLetter, $thisPos, 1));
 424                  if ($thisPos == 0) {
 425                      $charNum = intval ($thisCharOrd - $decrement[$thisLen]);
 426                      $decimalCode += ($charNum << $shift[$thisLen][$thisPos]);
 427                  } else {
 428                      $charNum = intval ($thisCharOrd - 128);
 429                      $decimalCode += ($charNum << $shift[$thisLen][$thisPos]);
 430                  }
 431                  $thisPos++;
 432              }
 433              $encodedLetter = "&#". ereg_replace('^0+', '', $decimalCode) . ';';
 434              $encodedString .= $encodedLetter;
 435          }
 436      }
 437      return $encodedString;
 438  }
 439  
 440  // UTF-32 ne sert plus que si on passe par iconv, c'est-a-dire quand
 441  // mb_string est absente ou ne connait pas notre charset
 442  // mais on l'optimise quand meme par mb_string
 443  // => tout ca sera osolete quand on sera surs d'avoir mb_string
 444  // http://doc.spip.org/@utf_32_to_unicode
 445  function utf_32_to_unicode($source) {
 446  
 447      // mb_string : methode rapide
 448      if (init_mb_string()) {
 449          $convmap = array(0x7F, 0xFFFFFF, 0x0, 0xFFFFFF);
 450          $source = mb_encode_numericentity($source, $convmap, 'UTF-32LE');
 451          return str_replace(chr(0), '', $source);
 452      }
 453  
 454      // Sinon methode lente
 455      $texte = '';
 456      while ($source) {
 457          $words = unpack("V*", substr($source, 0, 1024));
 458          $source = substr($source, 1024);
 459          foreach ($words as $word) {
 460              if ($word < 128)
 461                  $texte .= chr($word);
 462              // ignorer le BOM - http://www.unicode.org/faq/utf_bom.html
 463              else if ($word != 65279)
 464                  $texte .= '&#'.$word.';';
 465          }
 466      }
 467      return $texte;
 468  
 469  }
 470  
 471  // Ce bloc provient de php.net, auteur Ronen
 472  // http://doc.spip.org/@caractere_utf_8
 473  function caractere_utf_8($num) {
 474      if($num<128)
 475          return chr($num);
 476      if($num<2048)
 477          return chr(($num>>6)+192).chr(($num&63)+128);
 478      if($num<65536)
 479          return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
 480      if($num<1114112)
 481          return chr($num>>18+240).chr((($num>>12)&63)+128).chr(($num>>6)&63+128). chr($num&63+128);
 482      return '';
 483  }
 484  
 485  // http://doc.spip.org/@unicode_to_utf_8
 486  function unicode_to_utf_8($texte) {
 487  
 488      // 1. Entites &#128; et suivantes
 489      $vu = array();
 490      if (preg_match_all(',&#0*([1-9][0-9][0-9]+);,S',
 491      $texte, $regs, PREG_SET_ORDER))
 492      foreach ($regs as $reg) {
 493          if ($reg[1]>127 AND !isset($vu[$reg[0]]))
 494              $vu[$reg[0]] = caractere_utf_8($reg[1]);
 495      }
 496      $texte = str_replace(array_keys($vu), $vu, $texte);
 497  
 498      // 2. Entites > &#xFF;
 499      $vu = array();
 500      if (preg_match_all(',&#x0*([1-9a-f][0-9a-f][0-9a-f]+);,iS',
 501      $texte, $regs, PREG_SET_ORDER))
 502      foreach ($regs as $reg) {
 503          if (!isset($vu[$reg[0]]))
 504              $vu[$reg[0]] = caractere_utf_8(hexdec($reg[1]));
 505      }
 506      return str_replace(array_keys($vu), $vu, $texte);
 507  
 508  }
 509  
 510  // convertit les &#264; en \u0108
 511  // http://doc.spip.org/@unicode_to_javascript
 512  function unicode_to_javascript($texte) {
 513      $vu = array();
 514      while (preg_match(',&#0*([0-9]+);,S', $texte, $regs) AND !isset($vu[$regs[1]])) {
 515          $num = $regs[1];
 516          $vu[$num] = true;
 517          $s = '\u'.sprintf("%04x", $num);
 518          $texte = str_replace($regs[0], $s, $texte);
 519      }
 520      return $texte;
 521  }
 522  
 523  // convertit les %uxxxx (envoyes par javascript)
 524  // http://doc.spip.org/@javascript_to_unicode
 525  function javascript_to_unicode ($texte) {
 526      while (ereg("%u([0-9A-F][0-9A-F][0-9A-F][0-9A-F])", $texte, $regs))
 527          $texte = str_replace($regs[0],"&#".hexdec($regs[1]).";", $texte);
 528      return $texte;
 529  }
 530  // convertit les %E9 (envoyes par le browser) en chaine du charset du site (binaire)
 531  // http://doc.spip.org/@javascript_to_binary
 532  function javascript_to_binary ($texte) {
 533      while (ereg("%([0-9A-F][0-9A-F])", $texte, $regs))
 534          $texte = str_replace($regs[0],chr(hexdec($regs[1])), $texte);
 535      return $texte;
 536  }
 537  
 538  
 539  //
 540  // Translitteration charset => ascii (pour l'indexation)
 541  // Attention les caracteres non reconnus sont renvoyes en utf-8
 542  //
 543  // http://doc.spip.org/@translitteration
 544  function translitteration($texte, $charset='AUTO', $complexe='') {
 545      static $trans;
 546      if ($charset == 'AUTO')
 547          $charset = $GLOBALS['meta']['charset'];
 548  
 549      $table_translit ='translit'.$complexe;
 550  
 551      // 0. Supprimer les caracteres illegaux
 552      include_spip('inc/filtres');
 553      $texte = corriger_caracteres($texte);
 554  
 555      // 1. Passer le charset et les &eacute en utf-8
 556      $texte = unicode_to_utf_8(html2unicode(charset2unicode($texte, $charset, true)));
 557  
 558      // 2. Translitterer grace a la table predefinie
 559      if (!$trans[$complexe]) {
 560          global $CHARSET;
 561          load_charset($table_translit);
 562          foreach ($CHARSET[$table_translit] as $key => $val)
 563              $trans[$complexe][caractere_utf_8($key)] = $val;
 564      }
 565  
 566      return strtr($texte, $trans[$complexe]);
 567  }
 568  
 569  // &agrave; est retourne sous la forme "a`" et pas "a"
 570  // mais si $chiffre=true, on retourne "a8" (vietnamien)
 571  // http://doc.spip.org/@translitteration_complexe
 572  function translitteration_complexe($texte, $chiffres=false) {
 573      $texte = translitteration($texte,'AUTO','complexe');
 574  
 575      if ($chiffres) {
 576          $texte = preg_replace("/[aeiuoyd]['`?~.^+(-]{1,2}/eS",
 577              "translitteration_chiffree('\\0')", $texte);
 578      }
 579      
 580      return $texte;
 581  }
 582  // http://doc.spip.org/@translitteration_chiffree
 583  function translitteration_chiffree($car) {
 584      return strtr($car, "'`?~.^+(-", "123456789");
 585  }
 586  
 587  
 588  // Reconnaitre le BOM utf-8 (0xEFBBBF)
 589  // http://doc.spip.org/@bom_utf8
 590  function bom_utf8($texte) {
 591      return (substr($texte, 0,3) == chr(0xEF).chr(0xBB).chr(0xBF));
 592  }
 593  // Verifie qu'un document est en utf-8 valide
 594  // http://us2.php.net/manual/fr/function.mb-detect-encoding.php#50087
 595  // http://w3.org/International/questions/qa-forms-utf-8.html
 596  // note: preg_replace permet de contourner un "stack overflow" sur PCRE
 597  // http://doc.spip.org/@is_utf8
 598  function is_utf8($string) {
 599      return !strlen(
 600      preg_replace(
 601        ',[\x09\x0A\x0D\x20-\x7E]'            # ASCII
 602      . '|[\xC2-\xDF][\x80-\xBF]'             # non-overlong 2-byte
 603      . '|\xE0[\xA0-\xBF][\x80-\xBF]'         # excluding overlongs
 604      . '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'  # straight 3-byte
 605      . '|\xED[\x80-\x9F][\x80-\xBF]'         # excluding surrogates
 606      . '|\xF0[\x90-\xBF][\x80-\xBF]{2}'      # planes 1-3
 607      . '|[\xF1-\xF3][\x80-\xBF]{3}'          # planes 4-15
 608      . '|\xF4[\x80-\x8F][\x80-\xBF]{2}'      # plane 16
 609      . ',sS',
 610      '', $string));
 611  }
 612  // http://doc.spip.org/@is_ascii
 613  function is_ascii($string) {
 614      return !strlen(
 615      preg_replace(
 616      ',[\x09\x0A\x0D\x20-\x7E],sS',
 617      '', $string));
 618  }
 619  
 620  // Transcode une page (attrapee sur le web, ou un squelette) en essayant
 621  // par tous les moyens de deviner son charset (y compris headers HTTP)
 622  // http://doc.spip.org/@transcoder_page
 623  function transcoder_page($texte, $headers='') {
 624  
 625      // Si tout est < 128 pas la peine d'aller plus loin
 626      if (is_ascii($texte)) {
 627          #spip_log('charset: ascii');
 628          return $texte;
 629      }
 630  
 631      // Reconnaitre le BOM utf-8 (0xEFBBBF)
 632      if (bom_utf8($texte)) {
 633          $charset = 'utf-8';
 634          $texte = substr($texte,3);
 635      }
 636  
 637      // charset precise par le contenu (xml)
 638      else if (preg_match(
 639      ',<[?]xml[^>]*encoding[^>]*=[^>]*([-_a-z0-9]+?),UimsS', $texte, $regs))
 640          $charset = trim(strtolower($regs[1]));
 641      // charset precise par le contenu (html)
 642      else if (preg_match(
 643      ',<(meta|html|body)[^>]*charset[^>]*=[^>]*([-_a-z0-9]+?),UimsS',
 644      $texte, $regs)
 645      # eviter #CHARSET des squelettes
 646      AND (($tmp = trim(strtolower($regs[2]))) != 'charset'))
 647          $charset = $tmp;
 648      // charset de la reponse http
 649      else if (preg_match(',charset=([-_a-z0-9]+),i', $headers, $regs))
 650          $charset = trim(strtolower($regs[1]));
 651  
 652      // normaliser les noms du shif-jis japonais
 653      if (preg_match(',^(x|shift)[_-]s?jis$,i', $charset))
 654          $charset = 'shift-jis';
 655  
 656      if ($charset) {
 657          spip_log("charset: $charset");
 658      } else {
 659          // valeur par defaut
 660          if (is_utf8($texte))
 661              $charset = 'utf-8';
 662          else
 663              $charset = 'iso-8859-1';
 664          spip_log("charset probable: $charset");
 665      }
 666  
 667      return importer_charset($texte, $charset);
 668  }
 669  
 670  
 671  //
 672  // Gerer les outils mb_string
 673  //
 674  // http://doc.spip.org/@spip_substr
 675  function spip_substr($c, $start=0, $length = NULL) {
 676      // Si ce n'est pas utf-8, utiliser substr
 677      if ($GLOBALS['meta']['charset'] != 'utf-8') {
 678          if ($length)
 679              return substr($c, $start, $length);
 680          else
 681              substr($c, $start);
 682      }
 683  
 684      // Si utf-8, voir si on dispose de mb_string
 685      if (init_mb_string()) {
 686          if ($length)
 687              return mb_substr($c, $start, $length);
 688          else
 689              return mb_substr($c, $start);
 690      }
 691  
 692      // Version manuelle (cf. ci-dessous)
 693      return spip_substr_manuelle($c, $start, $length);
 694  }
 695  
 696  // version manuelle de substr utf8, pour php vieux et/ou mal installe
 697  // http://doc.spip.org/@spip_substr_manuelle
 698  function spip_substr_manuelle($c, $start, $length = NULL) {
 699  
 700      // Cas pathologique
 701      if ($length === 0)
 702          return '';
 703  
 704      // S'il y a un demarrage, on se positionne
 705      if ($start > 0)
 706          $c = substr($c, strlen(spip_substr_manuelle($c, 0, $start)));
 707      elseif ($start < 0)
 708          return spip_substr_manuelle($c, spip_strlen($c)+$start, $length);
 709  
 710      if (!$length)
 711          return $c;
 712  
 713      if ($length > 0) {
 714          // on prend n fois la longueur desiree, pour etre surs d'avoir tout
 715          // (un caractere utf-8 prenant au maximum n bytes)
 716          $n = 0; while (preg_match(',[\x80-\xBF]{'.(++$n).'},', $c));
 717          $c = substr($c, 0, $n*$length);
 718          // puis, tant qu'on est trop long, on coupe...
 719          while (($l = spip_strlen($c)) > $length)
 720              $c = substr($c, 0, $length - $l);
 721          return $c;
 722      }
 723  
 724      // $length < 0
 725      return spip_substr_manuelle($c, 0, spip_strlen($c)+$length);
 726  }
 727  
 728  // http://doc.spip.org/@spip_strlen
 729  function spip_strlen($c) {
 730      // Si ce n'est pas utf-8, utiliser strlen
 731      if ($GLOBALS['meta']['charset'] != 'utf-8')
 732          return strlen($c);
 733  
 734      // Sinon, utiliser mb_strlen() si disponible
 735      if (init_mb_string())
 736          return mb_strlen($c);
 737  
 738      // Methode manuelle : on supprime les bytes 10......,
 739      // on compte donc les ascii (0.......) et les demarrages
 740      // de caracteres utf-8 (11......)
 741      return strlen(preg_replace(',[\x80-\xBF],S', '', $c));
 742  }
 743  
 744  // Initialisation
 745  $GLOBALS['CHARSET'] = Array();
 746  
 747  ?>


Généré le : Wed Nov 21 10:20:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics