PageRenderTime 41ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/str.php

http://github.com/fuel/core
PHP | 653 lines | 324 code | 70 blank | 259 comment | 13 complexity | fe671762937f05b0d71e9eff85cace0a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP 5.4+ framework.
  4. *
  5. * @package Fuel
  6. * @version 1.9-dev
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2019 Fuel Development Team
  10. * @link https://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * String handling with encoding support
  15. *
  16. * PHP needs to be compiled with --enable-mbstring
  17. * or a fallback without encoding support is used
  18. */
  19. class Str
  20. {
  21. /**
  22. * Truncates a string to the given length. It will optionally preserve
  23. * HTML tags if $is_html is set to true.
  24. *
  25. * @param string $string the string to truncate
  26. * @param int $limit the number of characters to truncate too
  27. * @param string $continuation the string to use to denote it was truncated
  28. * @param bool $is_html whether the string has HTML
  29. * @return string the truncated string
  30. */
  31. public static function truncate($string, $limit, $continuation = '...', $is_html = false)
  32. {
  33. static $self_closing_tags = array(
  34. 'area', 'base', 'br', 'col', 'command', 'embed'
  35. , 'hr', 'img', 'input', 'keygen', 'link', 'meta'
  36. , 'param', 'source', 'track', 'wbr'
  37. );
  38. $offset = 0;
  39. $tags = array();
  40. if ($is_html)
  41. {
  42. // Handle special characters.
  43. preg_match_all('/&[a-z]+;/i', strip_tags($string), $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  44. // fix preg_match_all broken multibyte support
  45. if (MBSTRING and strlen($string !== mb_strlen($string)))
  46. {
  47. $correction = 0;
  48. foreach ($matches as $index => $match)
  49. {
  50. $matches[$index][0][1] -= $correction;
  51. $correction += (strlen($match[0][0]) - mb_strlen($match[0][0]));
  52. }
  53. }
  54. foreach ($matches as $match)
  55. {
  56. if ($match[0][1] >= $limit)
  57. {
  58. break;
  59. }
  60. $limit += (static::length($match[0][0]) - 1);
  61. }
  62. // Handle all the html tags.
  63. preg_match_all('/<[^>]+>([^<]*)/', $string, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  64. // fix preg_match_all broken multibyte support
  65. if (MBSTRING and strlen($string !== mb_strlen($string)))
  66. {
  67. $correction = 0;
  68. foreach ($matches as $index => $match)
  69. {
  70. $matches[$index][0][1] -= $correction;
  71. $matches[$index][1][1] -= $correction;
  72. $correction += (strlen($match[0][0]) - mb_strlen($match[0][0]));
  73. }
  74. }
  75. foreach ($matches as $match)
  76. {
  77. if($match[0][1] - $offset >= $limit)
  78. {
  79. break;
  80. }
  81. $tag = static::sub(strtok($match[0][0], " \t\n\r\0\x0B>"), 1);
  82. if ($tag[0] != '/')
  83. {
  84. if ( ! in_array($tag, $self_closing_tags))
  85. {
  86. $tags[] = $tag;
  87. }
  88. }
  89. elseif (end($tags) == static::sub($tag, 1))
  90. {
  91. array_pop($tags);
  92. }
  93. $offset += $match[1][1] - $match[0][1];
  94. }
  95. }
  96. $new_string = static::sub($string, 0, $limit = min(static::length($string), $limit + $offset));
  97. $new_string .= (static::length($string) > $limit ? $continuation : '');
  98. $new_string .= (count($tags = array_reverse($tags)) ? '</'.implode('></', $tags).'>' : '');
  99. return $new_string;
  100. }
  101. /**
  102. * Add's _1 to a string or increment the ending number to allow _2, _3, etc
  103. *
  104. * @param string $str required
  105. * @param int $first number that is used to mean first
  106. * @param string $separator separtor between the name and the number
  107. * @return string
  108. */
  109. public static function increment($str, $first = 1, $separator = '_')
  110. {
  111. preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);
  112. return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;
  113. }
  114. /**
  115. * Checks whether a string has a precific beginning.
  116. *
  117. * @param string $str string to check
  118. * @param string $start beginning to check for
  119. * @param boolean $ignore_case whether to ignore the case
  120. * @return boolean whether a string starts with a specified beginning
  121. */
  122. public static function starts_with($str, $start, $ignore_case = false)
  123. {
  124. return (bool) preg_match('/^'.preg_quote($start, '/').'/m'.($ignore_case ? 'i' : ''), $str);
  125. }
  126. /**
  127. * Checks whether a string has a precific ending.
  128. *
  129. * @param string $str string to check
  130. * @param string $end ending to check for
  131. * @param boolean $ignore_case whether to ignore the case
  132. * @return boolean whether a string ends with a specified ending
  133. */
  134. public static function ends_with($str, $end, $ignore_case = false)
  135. {
  136. return (bool) preg_match('/'.preg_quote($end, '/').'$/m'.($ignore_case ? 'i' : ''), $str);
  137. }
  138. /**
  139. * Creates a random string of characters
  140. *
  141. * @param string $type the type of string
  142. * @param int $length the number of characters
  143. * @return string the random string
  144. */
  145. public static function random($type = 'alnum', $length = 16)
  146. {
  147. switch($type)
  148. {
  149. case 'basic':
  150. return mt_rand();
  151. break;
  152. default:
  153. case 'alnum':
  154. case 'numeric':
  155. case 'nozero':
  156. case 'alpha':
  157. case 'distinct':
  158. case 'hexdec':
  159. switch ($type)
  160. {
  161. case 'alpha':
  162. $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  163. break;
  164. default:
  165. case 'alnum':
  166. $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  167. break;
  168. case 'numeric':
  169. $pool = '0123456789';
  170. break;
  171. case 'nozero':
  172. $pool = '123456789';
  173. break;
  174. case 'distinct':
  175. $pool = '2345679ACDEFHJKLMNPRSTUVWXYZ';
  176. break;
  177. case 'hexdec':
  178. $pool = '0123456789abcdef';
  179. break;
  180. }
  181. $str = '';
  182. for ($i=0; $i < $length; $i++)
  183. {
  184. $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1);
  185. }
  186. return $str;
  187. break;
  188. case 'unique':
  189. return md5(uniqid(mt_rand()));
  190. break;
  191. case 'sha1' :
  192. return sha1(uniqid(mt_rand(), true));
  193. break;
  194. case 'uuid':
  195. $pool = array('8', '9', 'a', 'b');
  196. return sprintf('%s-%s-4%s-%s%s-%s',
  197. static::random('hexdec', 8),
  198. static::random('hexdec', 4),
  199. static::random('hexdec', 3),
  200. $pool[array_rand($pool)],
  201. static::random('hexdec', 3),
  202. static::random('hexdec', 12));
  203. break;
  204. }
  205. }
  206. /**
  207. * Returns a closure that will alternate between the args which to return.
  208. * If you call the closure with false as the arg it will return the value without
  209. * alternating the next time.
  210. *
  211. * @return Closure
  212. */
  213. public static function alternator()
  214. {
  215. // the args are the values to alternate
  216. $args = func_get_args();
  217. return function ($next = true) use ($args)
  218. {
  219. static $i = 0;
  220. return $args[($next ? $i++ : $i) % count($args)];
  221. };
  222. }
  223. /**
  224. * Parse the params from a string using strtr()
  225. *
  226. * @param string $string string to parse
  227. * @param array $array params to str_replace
  228. * @return string
  229. */
  230. public static function tr($string, $array = array())
  231. {
  232. if (is_string($string))
  233. {
  234. $tr_arr = array();
  235. foreach ($array as $from => $to)
  236. {
  237. substr($from, 0, 1) !== ':' and $from = ':'.$from;
  238. $tr_arr[$from] = $to;
  239. }
  240. unset($array);
  241. return strtr($string, $tr_arr);
  242. }
  243. else
  244. {
  245. return $string;
  246. }
  247. }
  248. /**
  249. * Check if a string is json encoded
  250. *
  251. * @param string $string string to check
  252. * @return bool
  253. */
  254. public static function is_json($string)
  255. {
  256. json_decode($string);
  257. return json_last_error() === JSON_ERROR_NONE;
  258. }
  259. /**
  260. * Check if a string is a valid XML
  261. *
  262. * @param string $string string to check
  263. * @return bool
  264. * @throws \FuelException
  265. */
  266. public static function is_xml($string)
  267. {
  268. if ( ! defined('LIBXML_COMPACT'))
  269. {
  270. throw new \FuelException('libxml is required to use Str::is_xml()');
  271. }
  272. $internal_errors = libxml_use_internal_errors();
  273. libxml_use_internal_errors(true);
  274. $result = simplexml_load_string($string) !== false;
  275. libxml_use_internal_errors($internal_errors);
  276. return $result;
  277. }
  278. /**
  279. * Check if a string is serialized
  280. *
  281. * @param string $string string to check
  282. * @return bool
  283. */
  284. public static function is_serialized($string)
  285. {
  286. $array = @unserialize($string);
  287. return ! ($array === false and $string !== 'b:0;');
  288. }
  289. /**
  290. * Check if a string is html
  291. *
  292. * @param string $string string to check
  293. * @return bool
  294. */
  295. public static function is_html($string)
  296. {
  297. return strlen(strip_tags($string)) < strlen($string);
  298. }
  299. // multibyte functions
  300. /**
  301. * strpos — Find the position of the first occurrence of a substring in a string
  302. *
  303. * @param string $str The string being measured for length.
  304. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  305. *
  306. * @return int The length of the string on success, and 0 if the string is empty.
  307. */
  308. public static function strlen($str, $encoding = null)
  309. {
  310. $encoding or $encoding = \Fuel::$encoding;
  311. return (MBSTRING and $encoding)
  312. ? mb_strlen($str, $encoding)
  313. : strlen($str);
  314. }
  315. /**
  316. * strpos — Find position of first occurrence of string in a string
  317. *
  318. * @param string $haystack The string being checked
  319. * @param mixed $needle The string to find in haystack
  320. * @param int $offset The search offset
  321. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  322. *
  323. * @return mixed Returns the position of where the needle exists relative to the beginning
  324. * of the haystack string (independent of offset). Also note that string
  325. * positions start at 0, and not 1.
  326. * Returns FALSE if the needle was not found.
  327. */
  328. public static function strpos($haystack, $needle, $offset = 0, $encoding = null)
  329. {
  330. $encoding or $encoding = \Fuel::$encoding;
  331. return (MBSTRING and $encoding)
  332. ? mb_strpos($haystack, $needle, $offset, $encoding)
  333. : strpos($haystack, $needle, $offset);
  334. }
  335. /**
  336. * strrpos — Find position of last occurrence of a string in a string
  337. *
  338. * @param string $haystack The string being checked
  339. * @param mixed $needle The string to find in haystack
  340. * @param int $offset The search offset
  341. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  342. *
  343. * @return mixed Returns the numeric position of the last occurrence of needle in the
  344. * haystack string. If needle is not found, it returns FALSE.
  345. */
  346. public static function strrpos($haystack, $needle, $offset = 0, $encoding = null)
  347. {
  348. $encoding or $encoding = \Fuel::$encoding;
  349. return (MBSTRING and $encoding)
  350. ? mb_strrpos($haystack, $needle, $offset, $encoding)
  351. : strrpos($haystack, $needle, $offset);
  352. }
  353. /*
  354. * substr — Get part of string
  355. *
  356. * @param string $str The string to extract the substring from
  357. * @param int $start If start is non-negative, the returned string will start at the start'th
  358. * position in str, counting from zero. If start is negative, the returned
  359. * string will start at the start'th character from the end of str.
  360. * @param int $length Maximum number of characters to use from str. If omitted or NULL is passed,
  361. * extract all characters to the end of the string.
  362. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  363. *
  364. * @return mixed Returns the extracted part of string; or FALSE on failure, or an empty string.
  365. */
  366. public static function substr($str, $start, $length = null, $encoding = null)
  367. {
  368. $encoding or $encoding = \Fuel::$encoding;
  369. // substr functions don't parse null correctly if the string is multibyte
  370. $length = is_null($length)
  371. ? (MBSTRING ? mb_strlen($str, $encoding)
  372. : strlen($str)) - $start : $length;
  373. return (MBSTRING and $encoding)
  374. ? mb_substr($str, $start, $length, $encoding)
  375. : substr($str, $start, $length);
  376. }
  377. /**
  378. * strtolower — Make a string lowercase
  379. *
  380. * @param string $str The string to convert to lowercase
  381. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  382. *
  383. * @return string The lowercased string
  384. */
  385. public static function strtolower($str, $encoding = null)
  386. {
  387. $encoding or $encoding = \Fuel::$encoding;
  388. return (MBSTRING and $encoding)
  389. ? mb_strtolower($str, $encoding)
  390. : strtolower($str);
  391. }
  392. /**
  393. * strtoupper — Make a string uppercase
  394. *
  395. * @param string $str The string to convert to uppercase
  396. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  397. *
  398. * @return string The uppercased string
  399. */
  400. public static function strtoupper($str, $encoding = null)
  401. {
  402. $encoding or $encoding = \Fuel::$encoding;
  403. return (MBSTRING and $encoding)
  404. ? mb_strtoupper($str, $encoding)
  405. : strtoupper($str);
  406. }
  407. /**
  408. * stripos — Find the position of the first occurrence of a case-insensitive substring in a string
  409. *
  410. * @param string $haystack The string from which to get the position of the last occurrence of needle
  411. * @param mixed $needle The string to find in haystack
  412. * @param int $offset The search offset
  413. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  414. *
  415. * @return mixed Returns the position of where the needle exists relative to the beginning
  416. * of the haystack string (independent of offset). Also note that string
  417. * positions start at 0, and not 1.
  418. * Returns FALSE if the needle was not found.
  419. */
  420. public static function stripos($haystack, $needle, $offset = 0, $encoding = null)
  421. {
  422. $encoding or $encoding = \Fuel::$encoding;
  423. return (MBSTRING and $encoding)
  424. ? mb_stripos($haystack, $needle, $offset, $encoding)
  425. : stripos($haystack, $needle, $offset);
  426. }
  427. /**
  428. * strripos — Finds position of last occurrence of a string within another, case insensitive
  429. *
  430. * @param string $haystack The string from which to get the position of the last occurrence of needle
  431. * @param mixed $needle The string to find in haystack
  432. * @param int $offset The search offset
  433. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  434. *
  435. * @return mixed Returns the numeric position of the last occurrence of needle in the
  436. * haystack string. If needle is not found, it returns FALSE.
  437. */
  438. public static function strripos($haystack, $needle, $offset = 0, $encoding = null)
  439. {
  440. $encoding or $encoding = \Fuel::$encoding;
  441. return (MBSTRING and $encoding)
  442. ? mb_strripos($haystack, $needle, $offset, $encoding)
  443. : strripos($haystack, $needle, $offset);
  444. }
  445. /**
  446. * strstr — Finds first occurrence of a string within another
  447. *
  448. * @param string $haystack The string from which to get the position of the last occurrence of needle
  449. * @param mixed $needle The string to find in haystack
  450. * @param int $before_needle Determines which portion of haystack this function returns
  451. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  452. *
  453. * @return mixed The portion of haystack, or FALSE if needle is not found
  454. */
  455. public static function strstr($haystack, $needle, $before_needle = false, $encoding = null)
  456. {
  457. $encoding or $encoding = \Fuel::$encoding;
  458. return (MBSTRING and $encoding)
  459. ? mb_strstr($haystack, $needle, $before_needle, $encoding)
  460. : strstr($haystack, $needle, $before_needle);
  461. }
  462. /**
  463. * stristr — Finds first occurrence of a string within another, case-insensitive
  464. *
  465. * @param string $haystack The string from which to get the position of the last occurrence of needle
  466. * @param mixed $needle The string to find in haystack
  467. * @param int $before_needle Determines which portion of haystack this function returns
  468. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  469. *
  470. * @return mixed The portion of haystack, or FALSE if needle is not found
  471. */
  472. public static function stristr($haystack, $needle, $before_needle = false, $encoding = null)
  473. {
  474. $encoding or $encoding = \Fuel::$encoding;
  475. return (MBSTRING and $encoding)
  476. ? mb_stristr($haystack, $needle, $before_needle, $encoding)
  477. : stristr($haystack, $needle, $before_needle);
  478. }
  479. /**
  480. * strrchr — Finds the last occurrence of a character in a string within another
  481. *
  482. * @param string $haystack The string from which to get the last occurrence of needle
  483. * @param mixed $needle The string to find in haystack
  484. * @param int $part Determines which portion of haystack this function returns
  485. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  486. *
  487. * @return mixed The portion of haystack, or FALSE if needle is not found
  488. */
  489. public static function strrchr($haystack, $needle, $before_needle = false, $encoding = null)
  490. {
  491. $encoding or $encoding = \Fuel::$encoding;
  492. return (MBSTRING and $encoding)
  493. ? mb_strrchr($haystack, $needle, $part, $encoding)
  494. : strrchr($haystack, $needle, $part);
  495. }
  496. /**
  497. * substr_count — Count the number of substring occurrences
  498. *
  499. * @param string $haystack The string from which to get the position of the last occurrence of needle
  500. * @param mixed $needle The string to find in haystack
  501. * @param int $offset The search offset
  502. * @param string $encoding Defaults to the setting in the config, which defaults to UTF-8
  503. *
  504. * @return int The number of occurences found
  505. */
  506. public static function substr_count($haystack, $needle, $offset = 0, $encoding = null)
  507. {
  508. $encoding or $encoding = \Fuel::$encoding;
  509. return (MBSTRING and $encoding)
  510. ? mb_substr_count($haystack, $needle, $offset, $encoding)
  511. : substr_count($haystack, $needle, $offset);
  512. }
  513. /**
  514. * lcfirst
  515. *
  516. * Does not strtoupper first
  517. *
  518. * @param string $str required
  519. * @param string $encoding default UTF-8
  520. * @return string
  521. */
  522. public static function lcfirst($str, $encoding = null)
  523. {
  524. $encoding or $encoding = \Fuel::$encoding;
  525. return (MBSTRING and $encoding)
  526. ? mb_strtolower(mb_substr($str, 0, 1, $encoding), $encoding).
  527. mb_substr($str, 1, mb_strlen($str, $encoding), $encoding)
  528. : lcfirst($str);
  529. }
  530. /**
  531. * ucfirst
  532. *
  533. * Does not strtolower first
  534. *
  535. * @param string $str required
  536. * @param string $encoding default UTF-8
  537. * @return string
  538. */
  539. public static function ucfirst($str, $encoding = null)
  540. {
  541. $encoding or $encoding = \Fuel::$encoding;
  542. return (MBSTRING and $encoding)
  543. ? mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding).
  544. mb_substr($str, 1, mb_strlen($str, $encoding), $encoding)
  545. : ucfirst($str);
  546. }
  547. /**
  548. * ucwords
  549. *
  550. * First strtolower then ucwords
  551. *
  552. * ucwords normally doesn't strtolower first
  553. * but MB_CASE_TITLE does, so ucwords now too
  554. *
  555. * @param string $str required
  556. * @param string $encoding default UTF-8
  557. * @return string
  558. */
  559. public static function ucwords($str, $encoding = null)
  560. {
  561. $encoding or $encoding = \Fuel::$encoding;
  562. return (MBSTRING and $encoding)
  563. ? mb_convert_case($str, MB_CASE_TITLE, $encoding)
  564. : ucwords(strtolower($str));
  565. }
  566. // deprecated methods
  567. public static function length($str, $encoding = null)
  568. {
  569. return static::strlen($str, $encoding);
  570. }
  571. public static function sub($str, $start, $length = null, $encoding = null)
  572. {
  573. return static::substr($str, $start, $length, $encoding);
  574. }
  575. public static function lower($str, $encoding = null)
  576. {
  577. return static::strtolower($str, $encoding);
  578. }
  579. public static function upper($str, $encoding = null)
  580. {
  581. return static::strtoupper($str, $encoding);
  582. }
  583. }