PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/Utility/String.php

https://bitbucket.org/udeshika/fake_twitter
PHP | 353 lines | 275 code | 18 blank | 60 comment | 44 complexity | 4656298dc0ae5a31285a0c325ba1bfbb MD5 | raw file
  1. <?php
  2. /**
  3. * String handling methods.
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package Cake.Utility
  16. * @since CakePHP(tm) v 1.2.0.5551
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. /**
  20. * String handling methods.
  21. *
  22. *
  23. * @package Cake.Utility
  24. */
  25. class String {
  26. /**
  27. * Generate a random UUID
  28. *
  29. * @see http://www.ietf.org/rfc/rfc4122.txt
  30. * @return RFC 4122 UUID
  31. */
  32. public static function uuid() {
  33. $node = env('SERVER_ADDR');
  34. if (strpos($node, ':') !== false) {
  35. if (substr_count($node, '::')) {
  36. $node = str_replace(
  37. '::', str_repeat(':0000', 8 - substr_count($node, ':')) . ':', $node
  38. );
  39. }
  40. $node = explode(':', $node) ;
  41. $ipv6 = '' ;
  42. foreach ($node as $id) {
  43. $ipv6 .= str_pad(base_convert($id, 16, 2), 16, 0, STR_PAD_LEFT);
  44. }
  45. $node = base_convert($ipv6, 2, 10);
  46. if (strlen($node) < 38) {
  47. $node = null;
  48. } else {
  49. $node = crc32($node);
  50. }
  51. } elseif (empty($node)) {
  52. $host = env('HOSTNAME');
  53. if (empty($host)) {
  54. $host = env('HOST');
  55. }
  56. if (!empty($host)) {
  57. $ip = gethostbyname($host);
  58. if ($ip === $host) {
  59. $node = crc32($host);
  60. } else {
  61. $node = ip2long($ip);
  62. }
  63. }
  64. } elseif ($node !== '127.0.0.1') {
  65. $node = ip2long($node);
  66. } else {
  67. $node = null;
  68. }
  69. if (empty($node)) {
  70. $node = crc32(Configure::read('Security.salt'));
  71. }
  72. if (function_exists('zend_thread_id')) {
  73. $pid = zend_thread_id();
  74. } else {
  75. $pid = getmypid();
  76. }
  77. if (!$pid || $pid > 65535) {
  78. $pid = mt_rand(0, 0xfff) | 0x4000;
  79. }
  80. list($timeMid, $timeLow) = explode(' ', microtime());
  81. $uuid = sprintf(
  82. "%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff,
  83. mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node
  84. );
  85. return $uuid;
  86. }
  87. /**
  88. * Tokenizes a string using $separator, ignoring any instance of $separator that appears between
  89. * $leftBound and $rightBound
  90. *
  91. * @param string $data The data to tokenize
  92. * @param string $separator The token to split the data on.
  93. * @param string $leftBound The left boundary to ignore separators in.
  94. * @param string $rightBound The right boundary to ignore separators in.
  95. * @return array Array of tokens in $data.
  96. */
  97. public static function tokenize($data, $separator = ',', $leftBound = '(', $rightBound = ')') {
  98. if (empty($data) || is_array($data)) {
  99. return $data;
  100. }
  101. $depth = 0;
  102. $offset = 0;
  103. $buffer = '';
  104. $results = array();
  105. $length = strlen($data);
  106. $open = false;
  107. while ($offset <= $length) {
  108. $tmpOffset = -1;
  109. $offsets = array(
  110. strpos($data, $separator, $offset),
  111. strpos($data, $leftBound, $offset),
  112. strpos($data, $rightBound, $offset)
  113. );
  114. for ($i = 0; $i < 3; $i++) {
  115. if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) {
  116. $tmpOffset = $offsets[$i];
  117. }
  118. }
  119. if ($tmpOffset !== -1) {
  120. $buffer .= substr($data, $offset, ($tmpOffset - $offset));
  121. if ($data{$tmpOffset} == $separator && $depth == 0) {
  122. $results[] = $buffer;
  123. $buffer = '';
  124. } else {
  125. $buffer .= $data{$tmpOffset};
  126. }
  127. if ($leftBound != $rightBound) {
  128. if ($data{$tmpOffset} == $leftBound) {
  129. $depth++;
  130. }
  131. if ($data{$tmpOffset} == $rightBound) {
  132. $depth--;
  133. }
  134. } else {
  135. if ($data{$tmpOffset} == $leftBound) {
  136. if (!$open) {
  137. $depth++;
  138. $open = true;
  139. } else {
  140. $depth--;
  141. $open = false;
  142. }
  143. }
  144. }
  145. $offset = ++$tmpOffset;
  146. } else {
  147. $results[] = $buffer . substr($data, $offset);
  148. $offset = $length + 1;
  149. }
  150. }
  151. if (empty($results) && !empty($buffer)) {
  152. $results[] = $buffer;
  153. }
  154. if (!empty($results)) {
  155. $data = array_map('trim', $results);
  156. } else {
  157. $data = array();
  158. }
  159. return $data;
  160. }
  161. /**
  162. * Replaces variable placeholders inside a $str with any given $data. Each key in the $data array
  163. * corresponds to a variable placeholder name in $str.
  164. * Example: `String::insert(':name is :age years old.', array('name' => 'Bob', '65'));`
  165. * Returns: Bob is 65 years old.
  166. *
  167. * Available $options are:
  168. *
  169. * - before: The character or string in front of the name of the variable placeholder (Defaults to `:`)
  170. * - after: The character or string after the name of the variable placeholder (Defaults to null)
  171. * - escape: The character or string used to escape the before character / string (Defaults to `\`)
  172. * - format: A regex to use for matching variable placeholders. Default is: `/(?<!\\)\:%s/`
  173. * (Overwrites before, after, breaks escape / clean)
  174. * - clean: A boolean or array with instructions for String::cleanInsert
  175. *
  176. * @param string $str A string containing variable placeholders
  177. * @param string $data A key => val array where each key stands for a placeholder variable name
  178. * to be replaced with val
  179. * @param string $options An array of options, see description above
  180. * @return string
  181. */
  182. public static function insert($str, $data, $options = array()) {
  183. $defaults = array(
  184. 'before' => ':', 'after' => null, 'escape' => '\\', 'format' => null, 'clean' => false
  185. );
  186. $options += $defaults;
  187. $format = $options['format'];
  188. $data = (array)$data;
  189. if (empty($data)) {
  190. return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
  191. }
  192. if (!isset($format)) {
  193. $format = sprintf(
  194. '/(?<!%s)%s%%s%s/',
  195. preg_quote($options['escape'], '/'),
  196. str_replace('%', '%%', preg_quote($options['before'], '/')),
  197. str_replace('%', '%%', preg_quote($options['after'], '/'))
  198. );
  199. }
  200. if (strpos($str, '?') !== false && is_numeric(key($data))) {
  201. $offset = 0;
  202. while (($pos = strpos($str, '?', $offset)) !== false) {
  203. $val = array_shift($data);
  204. $offset = $pos + strlen($val);
  205. $str = substr_replace($str, $val, $pos, 1);
  206. }
  207. return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
  208. } else {
  209. asort($data);
  210. $hashKeys = array();
  211. foreach ($data as $key => $value) {
  212. $hashKeys[] = crc32($key);
  213. }
  214. $tempData = array_combine(array_keys($data), array_values($hashKeys));
  215. krsort($tempData);
  216. foreach ($tempData as $key => $hashVal) {
  217. $key = sprintf($format, preg_quote($key, '/'));
  218. $str = preg_replace($key, $hashVal, $str);
  219. }
  220. $dataReplacements = array_combine($hashKeys, array_values($data));
  221. foreach ($dataReplacements as $tmpHash => $tmpValue) {
  222. $tmpValue = (is_array($tmpValue)) ? '' : $tmpValue;
  223. $str = str_replace($tmpHash, $tmpValue, $str);
  224. }
  225. }
  226. if (!isset($options['format']) && isset($options['before'])) {
  227. $str = str_replace($options['escape'] . $options['before'], $options['before'], $str);
  228. }
  229. return ($options['clean']) ? String::cleanInsert($str, $options) : $str;
  230. }
  231. /**
  232. * Cleans up a String::insert() formatted string with given $options depending on the 'clean' key in
  233. * $options. The default method used is text but html is also available. The goal of this function
  234. * is to replace all whitespace and unneeded markup around placeholders that did not get replaced
  235. * by String::insert().
  236. *
  237. * @param string $str
  238. * @param string $options
  239. * @return string
  240. * @see String::insert()
  241. */
  242. public static function cleanInsert($str, $options) {
  243. $clean = $options['clean'];
  244. if (!$clean) {
  245. return $str;
  246. }
  247. if ($clean === true) {
  248. $clean = array('method' => 'text');
  249. }
  250. if (!is_array($clean)) {
  251. $clean = array('method' => $options['clean']);
  252. }
  253. switch ($clean['method']) {
  254. case 'html':
  255. $clean = array_merge(array(
  256. 'word' => '[\w,.]+',
  257. 'andText' => true,
  258. 'replacement' => '',
  259. ), $clean);
  260. $kleenex = sprintf(
  261. '/[\s]*[a-z]+=(")(%s%s%s[\s]*)+\\1/i',
  262. preg_quote($options['before'], '/'),
  263. $clean['word'],
  264. preg_quote($options['after'], '/')
  265. );
  266. $str = preg_replace($kleenex, $clean['replacement'], $str);
  267. if ($clean['andText']) {
  268. $options['clean'] = array('method' => 'text');
  269. $str = String::cleanInsert($str, $options);
  270. }
  271. break;
  272. case 'text':
  273. $clean = array_merge(array(
  274. 'word' => '[\w,.]+',
  275. 'gap' => '[\s]*(?:(?:and|or)[\s]*)?',
  276. 'replacement' => '',
  277. ), $clean);
  278. $kleenex = sprintf(
  279. '/(%s%s%s%s|%s%s%s%s)/',
  280. preg_quote($options['before'], '/'),
  281. $clean['word'],
  282. preg_quote($options['after'], '/'),
  283. $clean['gap'],
  284. $clean['gap'],
  285. preg_quote($options['before'], '/'),
  286. $clean['word'],
  287. preg_quote($options['after'], '/')
  288. );
  289. $str = preg_replace($kleenex, $clean['replacement'], $str);
  290. break;
  291. }
  292. return $str;
  293. }
  294. /**
  295. * Wraps text to a specific width, can optionally wrap at word breaks.
  296. *
  297. * ### Options
  298. *
  299. * - `width` The width to wrap to. Defaults to 72
  300. * - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
  301. * - `indent` String to indent with. Defaults to null.
  302. * - `indentAt` 0 based index to start indenting at. Defaults to 0.
  303. *
  304. * @param string $text Text the text to format.
  305. * @param mixed $options Array of options to use, or an integer to wrap the text to.
  306. * @return string Formatted text.
  307. */
  308. public static function wrap($text, $options = array()) {
  309. if (is_numeric($options)) {
  310. $options = array('width' => $options);
  311. }
  312. $options += array('width' => 72, 'wordWrap' => true, 'indent' => null, 'indentAt' => 0);
  313. if ($options['wordWrap']) {
  314. $wrapped = wordwrap($text, $options['width'], "\n");
  315. } else {
  316. $wrapped = trim(chunk_split($text, $options['width'] - 1, "\n"));
  317. }
  318. if (!empty($options['indent'])) {
  319. $chunks = explode("\n", $wrapped);
  320. for ($i = $options['indentAt'], $len = count($chunks); $i < $len; $i++) {
  321. $chunks[$i] = $options['indent'] . $chunks[$i];
  322. }
  323. $wrapped = implode("\n", $chunks);
  324. }
  325. return $wrapped;
  326. }
  327. }