string.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: string.php 8138 2009-04-09 13:15:43Z the_undefined $ */
00003 /**
00004  * String handling methods.
00005  *
00006  *
00007  * PHP versions 4 and 5
00008  *
00009  * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
00010  * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00011  *
00012  * Licensed under The MIT License
00013  * Redistributions of files must retain the above copyright notice.
00014  *
00015  * @filesource
00016  * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00017  * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00018  * @package       cake
00019  * @subpackage    cake.cake.libs
00020  * @since         CakePHP(tm) v 1.2.0.5551
00021  * @version       $Revision: 8138 $
00022  * @modifiedby    $LastChangedBy: the_undefined $
00023  * @lastmodified  $Date: 2009-04-09 09:15:43 -0400 (Thu, 09 Apr 2009) $
00024  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
00025  */
00026 /**
00027  * String handling methods.
00028  *
00029  *
00030  * @package       cake
00031  * @subpackage    cake.cake.libs
00032  */
00033 class String extends Object {
00034 /**
00035  * Gets a reference to the String object instance
00036  *
00037  * @return object String instance
00038  * @access public
00039  * @static
00040  */
00041     function &getInstance() {
00042         static $instance = array();
00043 
00044         if (!$instance) {
00045             $instance[0] =& new String();
00046         }
00047         return $instance[0];
00048     }
00049 /**
00050  * Generate a random UUID
00051  *
00052  * @see http://www.ietf.org/rfc/rfc4122.txt
00053  * @return RFC 4122 UUID
00054  * @static
00055  */
00056     function uuid() {
00057         $node = env('SERVER_ADDR');
00058         $pid = null;
00059 
00060         if (strpos($node, ':') !== false) {
00061             if (substr_count($node, '::')) {
00062                 $node = str_replace('::', str_repeat(':0000', 8 - substr_count($node, ':')) . ':', $node);
00063             }
00064             $node = explode(':', $node) ;
00065             $ipv6 = '' ;
00066 
00067             foreach ($node as $id) {
00068                 $ipv6 .= str_pad(base_convert($id, 16, 2), 16, 0, STR_PAD_LEFT);
00069             }
00070             $node =  base_convert($ipv6, 2, 10);
00071 
00072             if (strlen($node) < 38) {
00073                 $node = null;
00074             } else {
00075                 $node = crc32($node);
00076             }
00077         } elseif (empty($node)) {
00078             $host = env('HOSTNAME');
00079 
00080             if (empty($host)) {
00081                 $host = env('HOST');
00082             }
00083 
00084             if (!empty($host)) {
00085                 $ip = gethostbyname($host);
00086 
00087                 if ($ip === $host) {
00088                     $node = crc32($host);
00089                 } else {
00090                     $node = ip2long($ip);
00091                 }
00092             }
00093         } elseif ($node !== '127.0.0.1') {
00094             $node = ip2long($node);
00095         } else {
00096             $node = null;
00097         }
00098 
00099         if (empty($node)) {
00100             $node = crc32(Configure::read('Security.salt'));
00101         }
00102 
00103         if (function_exists('zend_thread_id')) {
00104             $pid = zend_thread_id();
00105         } else {
00106             $pid = getmypid();
00107         }
00108 
00109         if (!$pid || $pid > 65535) {
00110             $pid = mt_rand(0, 0xfff) | 0x4000;
00111         }
00112 
00113         list($timeMid, $timeLow) = explode(' ', microtime());
00114         $uuid = sprintf("%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff,
00115                     mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node);
00116 
00117         return $uuid;
00118     }
00119 /**
00120  * Tokenizes a string using $separator, ignoring any instance of $separator that appears between $leftBound
00121  * and $rightBound
00122  *
00123  * @param string $data The data to tokenize
00124  * @param string $separator The token to split the data on
00125  * @return array
00126  * @access public
00127  * @static
00128  */
00129     function tokenize($data, $separator = ',', $leftBound = '(', $rightBound = ')') {
00130         if (empty($data) || is_array($data)) {
00131             return $data;
00132         }
00133 
00134         $depth = 0;
00135         $offset = 0;
00136         $buffer = '';
00137         $results = array();
00138         $length = strlen($data);
00139         $open = false;
00140 
00141         while ($offset <= $length) {
00142             $tmpOffset = -1;
00143             $offsets = array(strpos($data, $separator, $offset), strpos($data, $leftBound, $offset), strpos($data, $rightBound, $offset));
00144             for ($i = 0; $i < 3; $i++) {
00145                 if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) {
00146                     $tmpOffset = $offsets[$i];
00147                 }
00148             }
00149             if ($tmpOffset !== -1) {
00150                 $buffer .= substr($data, $offset, ($tmpOffset - $offset));
00151                 if ($data{$tmpOffset} == $separator && $depth == 0) {
00152                     $results[] = $buffer;
00153                     $buffer = '';
00154                 } else {
00155                     $buffer .= $data{$tmpOffset};
00156                 }
00157                 if ($leftBound != $rightBound) {
00158                     if ($data{$tmpOffset} == $leftBound) {
00159                         $depth++;
00160                     }
00161                     if ($data{$tmpOffset} == $rightBound) {
00162                         $depth--;
00163                     }
00164                 } else {
00165                     if ($data{$tmpOffset} == $leftBound) {
00166                         if (!$open) {
00167                             $depth++;
00168                             $open = true;
00169                         } else {
00170                             $depth--;
00171                             $open = false;
00172                         }
00173                     }
00174                 }
00175                 $offset = ++$tmpOffset;
00176             } else {
00177                 $results[] = $buffer . substr($data, $offset);
00178                 $offset = $length + 1;
00179             }
00180         }
00181         if (empty($results) && !empty($buffer)) {
00182             $results[] = $buffer;
00183         }
00184 
00185         if (!empty($results)) {
00186             $data = array_map('trim', $results);
00187         } else {
00188             $data = array();
00189         }
00190         return $data;
00191     }
00192 /**
00193  * Replaces variable placeholders inside a $str with any given $data. Each key in the $data array corresponds to a variable
00194  * placeholder name in $str. Example:
00195  *
00196  * Sample: String::insert('My name is :name and I am :age years old.', array('name' => 'Bob', '65'));
00197  * Returns: My name is Bob and I am 65 years old.
00198  *
00199  * Available $options are:
00200  *  before: The character or string in front of the name of the variable placeholder (Defaults to ':')
00201  *  after: The character or string after the name of the variable placeholder (Defaults to null)
00202  *  escape: The character or string used to escape the before character / string (Defaults to '\')
00203  *  format: A regex to use for matching variable placeholders. Default is: '/(?<!\\)\:%s/' (Overwrites before, after, breaks escape / clean)
00204  *  clean: A boolean or array with instructions for String::cleanInsert
00205  *
00206  * @param string $str A string containing variable placeholders
00207  * @param string $data A key => val array where each key stands for a placeholder variable name to be replaced with val
00208  * @param string $options An array of options, see description above
00209  * @return string
00210  * @access public
00211  * @static
00212  */
00213     function insert($str, $data, $options = array()) {
00214         $defaults = array(
00215             'before' => ':', 'after' => null, 'escape' => '\\', 'format' => null, 'clean' => false
00216         );
00217         $options += $defaults;
00218         $format = $options['format'];
00219 
00220         if (!isset($format)) {
00221             $format = sprintf(
00222                 '/(?<!%s)%s%%s%s/',
00223                 preg_quote($options['escape'], '/'),
00224                 str_replace('%', '%%', preg_quote($options['before'], '/')),
00225                 str_replace('%', '%%', preg_quote($options['after'], '/'))
00226             );
00227         }
00228         if (!is_array($data)) {
00229             $data = array($data);
00230         }
00231 
00232         if (array_keys($data) === array_keys(array_values($data))) {
00233             $offset = 0;
00234             while (($pos = strpos($str, '?', $offset)) !== false) {
00235                 $val = array_shift($data);
00236                 $offset = $pos + strlen($val);
00237                 $str = substr_replace($str, $val, $pos, 1);
00238             }
00239         } else {
00240             asort($data);
00241 
00242             $hashKeys = array_map('md5', array_keys($data));
00243             $tempData = array_combine(array_keys($data), array_values($hashKeys));
00244             foreach ($tempData as $key => $hashVal) {
00245                 $key = sprintf($format, preg_quote($key, '/'));
00246                 $str = preg_replace($key, $hashVal, $str);
00247             }
00248             $dataReplacements = array_combine($hashKeys, array_values($data));
00249             foreach ($dataReplacements as $tmpHash => $data) {
00250                 $str = str_replace($tmpHash, $data, $str);
00251             }
00252         }
00253 
00254         if (!isset($options['format']) && isset($options['before'])) {
00255             $str = str_replace($options['escape'].$options['before'], $options['before'], $str);
00256         }
00257         if (!$options['clean']) {
00258             return $str;
00259         }
00260         return String::cleanInsert($str, $options);
00261     }
00262 /**
00263  * Cleans up a Set::insert formated string with given $options depending on the 'clean' key in $options. The default method used is
00264  * text but html is also available. The goal of this function is to replace all whitespace and uneeded markup around placeholders
00265  * that did not get replaced by Set::insert.
00266  *
00267  * @param string $str
00268  * @param string $options
00269  * @return string
00270  * @access public
00271  * @static
00272  */
00273     function cleanInsert($str, $options) {
00274         $clean = $options['clean'];
00275         if (!$clean) {
00276             return $str;
00277         }
00278         if ($clean === true) {
00279             $clean = array('method' => 'text');
00280         }
00281         if (!is_array($clean)) {
00282             $clean = array('method' => $options['clean']);
00283         }
00284         switch ($clean['method']) {
00285             case 'html':
00286                 $clean = array_merge(array(
00287                     'word' => '[\w,.]+',
00288                     'andText' => true,
00289                     'replacement' => '',
00290                 ), $clean);
00291                 $kleenex = sprintf(
00292                     '/[\s]*[a-z]+=(")(%s%s%s[\s]*)+\\1/i',
00293                     preg_quote($options['before'], '/'),
00294                     $clean['word'],
00295                     preg_quote($options['after'], '/')
00296                 );
00297                 $str = preg_replace($kleenex, $clean['replacement'], $str);
00298                 if ($clean['andText']) {
00299                     $options['clean'] = array('method' => 'text');
00300                     $str = String::cleanInsert($str, $options);
00301                 }
00302                 break;
00303             case 'text':
00304                 $clean = array_merge(array(
00305                     'word' => '[\w,.]+',
00306                     'gap' => '[\s]*(?:(?:and|or)[\s]*)?',
00307                     'replacement' => '',
00308                 ), $clean);
00309 
00310                 $kleenex = sprintf(
00311                     '/(%s%s%s%s|%s%s%s%s)/',
00312                     preg_quote($options['before'], '/'),
00313                     $clean['word'],
00314                     preg_quote($options['after'], '/'),
00315                     $clean['gap'],
00316                     $clean['gap'],
00317                     preg_quote($options['before'], '/'),
00318                     $clean['word'],
00319                     preg_quote($options['after'], '/')
00320                 );
00321                 $str = preg_replace($kleenex, $clean['replacement'], $str);
00322                 break;
00323         }
00324         return $str;
00325     }
00326 }
00327 ?>

Generated on Sun Nov 22 00:30:54 2009 for CakePHP 1.2.x.x (v1.2.4.8284) by doxygen 1.4.7