<?php /** * String handling methods. * * * PHP versions 4 and 5 * * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org) * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * @filesource * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org) * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project * @package cake * @subpackage cake.cake.libs * @since CakePHP(tm) v 1.2.0.5551 * @version $Revision$ * @modifiedby $LastChangedBy$ * @lastmodified $Date$ * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ /** * String handling methods. * * * @package cake * @subpackage cake.cake.libs */ class String { /** * Gets a reference to the String object instance * * @return object String instance * @access public * @static */ function &getInstance() { static $instance = array(); if (!$instance) { //next string was this: //$instance[0] =& new String(); //but at new versions of Yii we have got an CErrorEvent error for this line (I think it was from PHP 5.3, but can't check new code for the older PHP versions :( ) $instance[0] = new String(); } return $instance[0]; } /** * Generate a random UUID * * @see http://www.ietf.org/rfc/rfc4122.txt * @return RFC 4122 UUID * @static */ function uuid() { $node = env('SERVER_ADDR'); $pid = null; if (strpos($node, ':') !== false) { if (substr_count($node, '::')) { $node = str_replace('::', str_repeat(':0000', 8 - substr_count($node, ':')) . ':', $node); } $node = explode(':', $node) ; $ipv6 = '' ; foreach ($node as $id) { $ipv6 .= str_pad(base_convert($id, 16, 2), 16, 0, STR_PAD_LEFT); } $node = base_convert($ipv6, 2, 10); if (strlen($node) < 38) { $node = null; } else { $node = crc32($node); } } elseif (empty($node)) { $host = env('HOSTNAME'); if (empty($host)) { $host = env('HOST'); } if (!empty($host)) { $ip = gethostbyname($host); if ($ip === $host) { $node = crc32($host); } else { $node = ip2long($ip); } } } elseif ($node !== '127.0.0.1') { $node = ip2long($node); } else { $node = null; } if (empty($node)) { $node = crc32(Configure::read('Security.salt')); } if (function_exists('zend_thread_id')) { $pid = zend_thread_id(); } else { $pid = getmypid(); } if (!$pid || $pid > 65535) { $pid = mt_rand(0, 0xfff) | 0x4000; } list($timeMid, $timeLow) = explode(' ', microtime()); $uuid = sprintf("%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff, mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node); return $uuid; } /** * Tokenizes a string using $separator, ignoring any instance of $separator that appears between $leftBound * and $rightBound * * @param string $data The data to tokenize * @param string $separator The token to split the data on * @return array * @access public * @static */ function tokenize($data, $separator = ',', $leftBound = '(', $rightBound = ')') { if (empty($data) || is_array($data)) { return $data; } $depth = 0; $offset = 0; $buffer = ''; $results = array(); $length = strlen($data); $open = false; while ($offset <= $length) { $tmpOffset = -1; $offsets = array(strpos($data, $separator, $offset), strpos($data, $leftBound, $offset), strpos($data, $rightBound, $offset)); for ($i = 0; $i < 3; $i++) { if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) { $tmpOffset = $offsets[$i]; } } if ($tmpOffset !== -1) { $buffer .= substr($data, $offset, ($tmpOffset - $offset)); if ($data{$tmpOffset} == $separator && $depth == 0) { $results[] = $buffer; $buffer = ''; } else { $buffer .= $data{$tmpOffset}; } if ($leftBound != $rightBound) { if ($data{$tmpOffset} == $leftBound) { $depth++; } if ($data{$tmpOffset} == $rightBound) { $depth--; } } else { if ($data{$tmpOffset} == $leftBound) { if (!$open) { $depth++; $open = true; } else { $depth--; $open = false; } } } $offset = ++$tmpOffset; } else { $results[] = $buffer . substr($data, $offset); $offset = $length + 1; } } if (empty($results) && !empty($buffer)) { $results[] = $buffer; } if (!empty($results)) { $data = array_map('trim', $results); } else { $data = array(); } return $data; } /** * Replaces variable placeholders inside a $str with any given $data. Each key in the $data array corresponds to a variable * placeholder name in $str. Example: * * Sample: String::insert('My name is :name and I am :age years old.', array('name' => 'Bob', '65')); * Returns: My name is Bob and I am 65 years old. * * Available $options are: * before: The character or string in front of the name of the variable placeholder (Defaults to ':') * after: The character or string after the name of the variable placeholder (Defaults to null) * escape: The character or string used to escape the before character / string (Defaults to '\') * format: A regex to use for matching variable placeholders. Default is: '/(?<!\\)\:%s/' (Overwrites before, after, breaks escape / clean) * clean: A boolean or array with instructions for String::cleanInsert * * @param string $str A string containing variable placeholders * @param string $data A key => val array where each key stands for a placeholder variable name to be replaced with val * @param string $options An array of options, see description above * @return string * @access public * @static */ function insert($str, $data, $options = array()) { $defaults = array( 'before' => ':', 'after' => null, 'escape' => '\\', 'format' => null, 'clean' => false ); $options += $defaults; $format = $options['format']; if (!isset($format)) { $format = sprintf( '/(?<!%s)%s%%s%s/', preg_quote($options['escape'], '/'), str_replace('%', '%%', preg_quote($options['before'], '/')), str_replace('%', '%%', preg_quote($options['after'], '/')) ); } if (!is_array($data)) { $data = array($data); } if (array_keys($data) === array_keys(array_values($data))) { $offset = 0; while (($pos = strpos($str, '?', $offset)) !== false) { $val = array_shift($data); $offset = $pos + strlen($val); $str = substr_replace($str, $val, $pos, 1); } } else { $hashKeys = array_map('md5', array_keys($data)); $tempData = array_combine(array_keys($data), array_values($hashKeys)); foreach ($tempData as $key => $hashVal) { $key = sprintf($format, preg_quote($key, '/')); $str = preg_replace($key, $hashVal, $str); } $dataReplacements = array_combine($hashKeys, array_values($data)); foreach ($dataReplacements as $tmpHash => $data) { $str = str_replace($tmpHash, $data, $str); } } if (!isset($options['format']) && isset($options['before'])) { $str = str_replace($options['escape'].$options['before'], $options['before'], $str); } if (!$options['clean']) { return $str; } return String::cleanInsert($str, $options); } /** * Cleans up a Set::insert formated string with given $options depending on the 'clean' key in $options. The default method used is * text but html is also available. The goal of this function is to replace all whitespace and uneeded markup around placeholders * that did not get replaced by Set::insert. * * @param string $str * @param string $options * @return string * @access public * @static */ function cleanInsert($str, $options) { $clean = $options['clean']; if (!$clean) { return $str; } if ($clean === true) { $clean = array('method' => 'text'); } if (!is_array($clean)) { $clean = array('method' => $options['clean']); } switch ($clean['method']) { case 'html': $clean = array_merge(array( 'word' => '[\w,.]+', 'andText' => true, 'replacement' => '', ), $clean); $kleenex = sprintf( '/[\s]*[a-z]+=(")(%s%s%s[\s]*)+\\1/i', preg_quote($options['before'], '/'), $clean['word'], preg_quote($options['after'], '/') ); $str = preg_replace($kleenex, $clean['replacement'], $str); if ($clean['andText']) { $options['clean'] = array('method' => 'text'); $str = String::cleanInsert($str, $options); } break; case 'text': $clean = array_merge(array( 'word' => '[\w,.]+', 'gap' => '[\s]*(?:(?:and|or)[\s]*)?', 'replacement' => '', ), $clean); $kleenex = sprintf( '/(%s%s%s%s|%s%s%s%s)/', preg_quote($options['before'], '/'), $clean['word'], preg_quote($options['after'], '/'), $clean['gap'], $clean['gap'], preg_quote($options['before'], '/'), $clean['word'], preg_quote($options['after'], '/') ); $str = preg_replace($kleenex, $clean['replacement'], $str); break; } return $str; } }