[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/lib/ -> textlib.class.php (source)

   1  <?php  // $Id: textlib.class.php,v 1.25 2007/10/10 05:25:15 nicolasconnault Exp $
   2  
   3  ///////////////////////////////////////////////////////////////////////////
   4  //                                                                       //
   5  // NOTICE OF COPYRIGHT                                                   //
   6  //                                                                       //
   7  // Moodle - Modular Object-Oriented Dynamic Learning Environment         //
   8  //          http://moodle.com                                            //
   9  //                                                                       //
  10  // Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
  11  //           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
  12  //                                                                       //
  13  // This program is free software; you can redistribute it and/or modify  //
  14  // it under the terms of the GNU General Public License as published by  //
  15  // the Free Software Foundation; either version 2 of the License, or     //
  16  // (at your option) any later version.                                   //
  17  //                                                                       //
  18  // This program is distributed in the hope that it will be useful,       //
  19  // but WITHOUT ANY WARRANTY; without even the implied warranty of        //
  20  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
  21  // GNU General Public License for more details:                          //
  22  //                                                                       //
  23  //          http://www.gnu.org/copyleft/gpl.html                         //
  24  //                                                                       //
  25  ///////////////////////////////////////////////////////////////////////////
  26  
  27  /// Required files
  28      require_once($CFG->libdir.'/typo3/class.t3lib_cs.php');
  29      require_once($CFG->libdir.'/typo3/class.t3lib_div.php');
  30  
  31  /// If ICONV is available, lets Typo3 library use it for convert
  32      if (extension_loaded('iconv')) {
  33          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'iconv';
  34      /// Else if mbstring is available, lets Typo3 library use it
  35      } else if (extension_loaded('mbstring')) {
  36          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'mbstring';
  37      /// Else if recode is available, lets Typo3 library use it
  38      } else if (extension_loaded('recode')) {
  39          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'recode';
  40      } else {
  41          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = '';
  42      }
  43  
  44  /// If mbstring is available, lets Typo3 library use it for functions
  45      if (extension_loaded('mbstring')) {
  46          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_utils'] = 'mbstring';
  47      } else {
  48          $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_utils'] = '';
  49      }
  50  
  51  /// And this directory must exist to allow Typo to cache conversion
  52  /// tables when using internal functions
  53      make_upload_directory('temp/typo3temp/cs');
  54  
  55  /// Default mask for Typo
  56      $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = $CFG->directorypermissions;
  57  
  58  /// This full path constants must be defined too, transforming backslashes
  59  /// to forward slashed beacuse Typo3 requires it.
  60      define ('PATH_t3lib', str_replace('\\','/',$CFG->libdir.'/typo3/'));
  61      define ('PATH_typo3', str_replace('\\','/',$CFG->libdir.'/typo3/'));
  62      define ('PATH_site', str_replace('\\','/',$CFG->dataroot.'/temp/'));
  63      define ('TYPO3_OS', stristr(PHP_OS,'win')&&!stristr(PHP_OS,'darwin')?'WIN':'');
  64  
  65  
  66  /// As we implement the singleton pattern to use this class (only one instance
  67  /// is shared globally), we need this helper function
  68  
  69  /// IMPORTANT Note: Typo3 libraries always expect lowercase charsets to use 100%
  70  ///                 its capabilities so, don't forget to make the conversion
  71  ///                 from every wrapper function!
  72  
  73  function textlib_get_instance() {
  74      static $instance;
  75      if (!is_object($instance)) {
  76          $instance = new textlib();
  77      }
  78      return $instance;
  79  }
  80  
  81  /**
  82   * This class is used to manipulate strings under Moodle 1.6 an later. As
  83   * utf-8 text become mandatory a pool of safe functions under this encoding
  84   * become necessary. The name of the methods is exactly the
  85   * same than their PHP originals.
  86   *
  87   * A big part of this class acts as a wrapper over the Typo3 charset library,
  88   * really a cool group of utilities to handle texts and encoding conversion.
  89   *
  90   * Take a look to its own copyright and license details.
  91   */
  92  class textlib {
  93  
  94      var $typo3cs;
  95  
  96      /**
  97       * Standard constructor of the class. All it does is to instantiate
  98       * a new t3lib_cs object to have all their functions ready.
  99       *
 100       * Instead of istantiating a lot of objects of this class everytime
 101       * some of their functions is going to be used, you can invoke the:
 102       * textlib_get_instance() function, avoiding the creation of them
 103       * (following the singleton pattern)
 104       */
 105      function textlib() {
 106          /// Instantiate a conversor object some of the methods in typo3
 107          /// reference to $this and cannot be executed in a static context
 108          $this->typo3cs = new t3lib_cs();
 109      }
 110  
 111      /**
 112       * Converts the text between different encodings. It will use iconv, mbstring
 113       * or internal (typo3) methods to try such conversion. Returns false if fails.
 114       */
 115      function convert($text, $fromCS, $toCS='utf-8') {
 116      /// Normalize charsets
 117          $fromCS = $this->typo3cs->parse_charset($fromCS);
 118          $toCS   = $this->typo3cs->parse_charset($toCS);
 119      /// Avoid some notices from Typo3 code
 120          $oldlevel = error_reporting(E_PARSE);
 121      /// Call Typo3 conv() function. It will do all the work
 122          $result = $this->typo3cs->conv($text, $fromCS, $toCS);
 123      /// Restore original debug level
 124          error_reporting($oldlevel);
 125          return $result;
 126      }
 127  
 128      /**
 129       * Multibyte safe substr() function, uses mbstring if available.
 130       */
 131      function substr($text, $start, $len=null, $charset='utf-8') {
 132      /// Normalize charset
 133          $charset = $this->typo3cs->parse_charset($charset);
 134      /// Avoid some notices from Typo3 code
 135          $oldlevel = error_reporting(E_PARSE);
 136      /// Call Typo3 substr() function. It will do all the work
 137          $result = $this->typo3cs->substr($charset,$text,$start,$len);
 138      /// Restore original debug level
 139          error_reporting($oldlevel);
 140          return $result;
 141      }
 142  
 143      /**
 144       * Multibyte safe strlen() function, uses mbstring if available.
 145       */
 146      function strlen($text, $charset='utf-8') {
 147      /// Normalize charset
 148          $charset = $this->typo3cs->parse_charset($charset);
 149      /// Avoid some notices from Typo3 code
 150          $oldlevel = error_reporting(E_PARSE);
 151      /// Call Typo3 strlen() function. It will do all the work
 152          $result = $this->typo3cs->strlen($charset,$text);
 153      /// Restore original debug level
 154          error_reporting($oldlevel);
 155          return $result;
 156      }
 157  
 158      /**
 159       * Multibyte safe strtolower() function, uses mbstring if available.
 160       */
 161      function strtolower($text, $charset='utf-8') {
 162      /// Normalize charset
 163          $charset = $this->typo3cs->parse_charset($charset);
 164      /// Avoid some notices from Typo3 code
 165          $oldlevel = error_reporting(E_PARSE);
 166      /// Call Typo3 conv_case() function. It will do all the work
 167          $result = $this->typo3cs->conv_case($charset,$text,'toLower');
 168      /// Restore original debug level
 169          error_reporting($oldlevel);
 170          return $result;
 171      }
 172  
 173      /**
 174       * Multibyte safe strtoupper() function, uses mbstring if available.
 175       */
 176      function strtoupper($text, $charset='utf-8') {
 177      /// Normalize charset
 178          $charset = $this->typo3cs->parse_charset($charset);
 179      /// Avoid some notices from Typo3 code
 180          $oldlevel = error_reporting(E_PARSE);
 181      /// Call Typo3 conv_case() function. It will do all the work
 182          $result = $this->typo3cs->conv_case($charset,$text,'toUpper');
 183      /// Restore original debug level
 184          error_reporting($oldlevel);
 185          return $result;
 186      }
 187  
 188      /**
 189       * UTF-8 ONLY safe strpos() function, uses mbstring if available.
 190       */
 191      function strpos($haystack,$needle,$offset=0) {
 192      /// Call Typo3 utf8_strpos() function. It will do all the work
 193          return $this->typo3cs->utf8_strpos($haystack,$needle,$offset);
 194      }
 195  
 196      /**
 197       * UTF-8 ONLY safe strrpos() function, uses mbstring if available.
 198       */
 199      function strrpos($haystack,$needle) {
 200      /// Call Typo3 utf8_strrpos() function. It will do all the work
 201          return $this->typo3cs->utf8_strrpos($haystack,$needle);
 202      }
 203  
 204      /**
 205       * Try to convert upper unicode characters to plain ascii,
 206       * the returned string may cantain unconverted unicode characters.
 207       */
 208      function specialtoascii($text,$charset='utf-8') {
 209      /// Normalize charset
 210          $charset = $this->typo3cs->parse_charset($charset);
 211      /// Avoid some notices from Typo3 code
 212          $oldlevel = error_reporting(E_PARSE);
 213          $result = $this->typo3cs->specCharsToASCII($charset,$text);
 214      /// Restore original debug level
 215          error_reporting($oldlevel);
 216          return $result;
 217      }
 218  
 219      /**
 220       * Generate a correct base64 encoded header to be used in MIME mail messages.
 221       * This function seems to be 100% compliant with RFC1342. Credits go to:
 222       * paravoid (http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283).
 223       */
 224      function encode_mimeheader($text, $charset='utf-8') {
 225          if (empty($text)) {
 226              return (string)$text;
 227          }
 228      /// Normalize charset
 229          $charset = $this->typo3cs->parse_charset($charset);
 230      /// If the text is pure ASCII, we don't need to encode it
 231          if ($this->convert($text, $charset, 'ascii') == $text) {
 232              return $text;
 233          }
 234      /// Although RFC says that line feed should be \r\n, it seems that
 235      /// some mailers double convert \r, so we are going to use \n alone
 236          $linefeed="\n";
 237      /// Define start and end of every chunk
 238          $start = "=?$charset?B?";
 239          $end = "?=";
 240      /// Acumulate results
 241          $encoded = '';
 242      /// Max line length is 75 (including start and end)
 243          $length = 75 - strlen($start) - strlen($end);
 244      /// Multi-byte ratio
 245          $multilength = $this->strlen($text, $charset);
 246      /// Detect if strlen and friends supported
 247          if ($multilength === false) {
 248              if ($charset == 'GB18030' or $charset == 'gb18030') {
 249                  while (strlen($text)) {
 250                      // try to encode first 22 chars - we expect most chars are two bytes long
 251                      if (preg_match('/^(([\x00-\x7f])|([\x81-\xfe][\x40-\x7e])|([\x81-\xfe][\x80-\xfe])|([\x81-\xfe][\x30-\x39]..)){1,22}/m', $text, $matches)) {
 252                          $chunk = $matches[0];
 253                          $encchunk = base64_encode($chunk);
 254                          if (strlen($encchunk) > $length) {
 255                              // find first 11 chars - each char in 4 bytes - worst case scenario
 256                              preg_match('/^(([\x00-\x7f])|([\x81-\xfe][\x40-\x7e])|([\x81-\xfe][\x80-\xfe])|([\x81-\xfe][\x30-\x39]..)){1,11}/m', $text, $matches);
 257                              $chunk = $matches[0];
 258                              $encchunk = base64_encode($chunk);
 259                          }
 260                          $text = substr($text, strlen($chunk));
 261                          $encoded .= ' '.$start.$encchunk.$end.$linefeed;
 262                      } else {
 263                          break;
 264                      }
 265                  }
 266                  $encoded = trim($encoded);
 267                  return $encoded;
 268              } else {
 269                  return false;
 270              }
 271          }
 272          $ratio = $multilength / strlen($text);
 273      /// Base64 ratio
 274          $magic = $avglength = floor(3 * $length * $ratio / 4);
 275      /// basic infinite loop protection
 276          $maxiterations = strlen($text)*2;
 277          $iteration = 0;
 278      /// Iterate over the string in magic chunks
 279          for ($i=0; $i <= $multilength; $i+=$magic) {
 280              if ($iteration++ > $maxiterations) {
 281                  return false; // probably infinite loop
 282              }
 283              $magic = $avglength;
 284              $offset = 0;
 285          /// Ensure the chunk fits in length, reduding magic if necessary
 286              do {
 287                  $magic -= $offset;
 288                  $chunk = $this->substr($text, $i, $magic, $charset);
 289                  $chunk = base64_encode($chunk);
 290                  $offset++;
 291              } while (strlen($chunk) > $length);
 292          /// This chunk doen't break any multi-byte char. Use it.
 293              if ($chunk)
 294                  $encoded .= ' '.$start.$chunk.$end.$linefeed;
 295          }
 296      /// Strip the first space and the last linefeed
 297          $encoded = substr($encoded, 1, -strlen($linefeed));
 298  
 299          return $encoded;
 300      }
 301  
 302      /**
 303       * Converts all the numeric entities &#nnnn; or &#xnnn; to UTF-8
 304       * Original from laurynas dot butkus at gmail at:
 305       * http://php.net/manual/en/function.html-entity-decode.php#75153
 306       * with some custom mods to provide more functionality
 307       *
 308       * @param    string    $str      input string
 309       * @param    boolean   $htmlent  convert also html entities (defaults to true)
 310       *
 311       * NOTE: we could have used typo3 entities_to_utf8() here
 312       *       but the direct alternative used runs 400% quicker
 313       *       and uses 0.5Mb less memory, so, let's use it
 314       *       (tested agains 10^6 conversions)
 315       */
 316      function entities_to_utf8($str, $htmlent=true) {
 317  
 318          static $trans_tbl; /// Going to use static translit table
 319  
 320      /// Replace numeric entities
 321          $result = preg_replace('~&#x([0-9a-f]+);~ei', 'textlib::code2utf8(hexdec("\\1"))', $str);
 322          $result = preg_replace('~&#([0-9]+);~e', 'textlib::code2utf8(\\1)', $result);
 323  
 324      /// Replace literal entities (if desired)
 325          if ($htmlent) {
 326          /// Generate/create $trans_tbl
 327              if (!isset($trans_tbl)) {
 328                  $trans_tbl = array();
 329                  foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) {
 330                      $trans_tbl[$key] = utf8_encode($val);
 331                  }
 332              }
 333              $result = strtr($result, $trans_tbl);
 334          }
 335      /// Return utf8-ised string
 336          return $result;
 337      }
 338  
 339      /**
 340       * Converts all Unicode chars > 127 to numeric entities &#nnnn; or &#xnnn;.
 341       *
 342       * @param    string         input string
 343       * @param    boolean        output decadic only number entities
 344       * @param    boolean        remove all nonumeric entities
 345       * @return   string         converted string
 346       */
 347      function utf8_to_entities($str, $dec=false, $nonnum=false) {
 348      /// Avoid some notices from Typo3 code
 349          $oldlevel = error_reporting(E_PARSE);
 350          if ($nonnum) {
 351              $str = $this->typo3cs->entities_to_utf8($str, true);
 352          }
 353          $result = $this->typo3cs->utf8_to_entities($str);
 354          if ($dec) {
 355              $result = preg_replace('/&#x([0-9a-f]+);/ie', "'&#'.hexdec('$1').';'", $result);
 356          }
 357      /// Restore original debug level
 358          error_reporting($oldlevel);
 359          return $result;
 360      }
 361  
 362      /**
 363       * Removes the BOM from unicode string - see http://unicode.org/faq/utf_bom.html
 364       */
 365      function trim_utf8_bom($str) {
 366          $bom = "\xef\xbb\xbf";
 367          if (strpos($str, $bom) === 0) {
 368              return substr($str, strlen($bom));
 369          }
 370          return $str;
 371      }
 372  
 373      /**
 374       * Returns encoding options for select boxes, utf-8 and platform encoding first
 375       * @return array encodings
 376       */
 377      function get_encodings() {
 378          $encodings = array();
 379          $encodings['UTF-8'] = 'UTF-8';
 380          $winenc = strtoupper(get_string('localewincharset'));
 381          if ($winenc != '') {
 382              $encodings[$winenc] = $winenc;
 383          }
 384          $nixenc = strtoupper(get_string('oldcharset'));
 385          $encodings[$nixenc] = $nixenc;
 386  
 387          foreach ($this->typo3cs->synonyms as $enc) {
 388              $enc = strtoupper($enc);
 389              $encodings[$enc] = $enc;
 390          }
 391          return $encodings;
 392      }
 393  
 394      /**
 395       * Returns the utf8 string corresponding to the unicode value
 396       * (from php.net, courtesy - romans@void.lv)
 397       *
 398       * @param  int    $num one unicode value
 399       * @return string the UTF-8 char corresponding to the unicode value
 400       */
 401      function code2utf8($num) {
 402          if ($num < 128) {
 403              return chr($num);
 404          }
 405          if ($num < 2048) {
 406              return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
 407          }
 408          if ($num < 65536) {
 409              return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
 410          }
 411          if ($num < 2097152) {
 412              return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
 413          }
 414          return '';
 415      }
 416  
 417      /**
 418       * Makes first letter of each word capital - words must be separated by spaces.
 419       * Use with care, this function does not work properly in many locales!!!
 420       * @param string $text
 421       * @return string
 422       */
 423      function strtotitle($text) {
 424          if (empty($text)) {
 425              return $text;
 426          }
 427  
 428          if (function_exists('mb_convert_case')) {
 429              return mb_convert_case($text, MB_CASE_TITLE,"UTF-8");
 430          }
 431  
 432          $text = $this->strtolower($text);
 433          $words = explode(' ', $text);
 434          foreach ($words as $i=>$word) {
 435              $length = $this->strlen($word);
 436              if (!$length) {
 437                  continue;
 438  
 439              } else if ($length == 1) {
 440                  $words[$i] = $this->strtoupper($word);
 441  
 442              } else {
 443                  $letter = $this->substr($word, 0, 1);
 444                  $letter = $this->strtoupper($letter);
 445                  $rest   = $this->substr($word, 1);
 446                  $words[$i] = $letter.$rest;
 447              }
 448          }
 449          return implode(' ', $words);
 450      }
 451  }
 452  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7