PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/app/classes/util.php

https://github.com/schwarzmedia/bolt
PHP | 2106 lines | 1121 code | 201 blank | 784 comment | 300 complexity | b4828945cf5df6f8abe562e60da86959 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * util.php
  4. *
  5. * util.php is a library of helper functions for common tasks such as
  6. * formatting bytes as a string or displaying a date in terms of how long ago
  7. * it was in human readable terms (E.g. 4 minutes ago). The library is entirely
  8. * contained within a single file and hosts no dependencies. The library is
  9. * designed to avoid any possible conflicts.
  10. *
  11. * @author Brandon Wamboldt
  12. * @link http://github.com/brandonwamboldt/utilphp/ Official Documentation
  13. * @version 1.0.003
  14. */
  15. if ( ! class_exists( 'util' ) ) {
  16. class util
  17. {
  18. /**
  19. * A constant representing the number of seconds in a minute, for
  20. * making code more verbose
  21. *
  22. * @since 1.0.000
  23. * @var int
  24. */
  25. const SECONDS_IN_A_MINUTE = 60;
  26. /**
  27. * A constant representing the number of seconds in an hour, for making
  28. * code more verbose
  29. *
  30. * @since 1.0.000
  31. * @var int
  32. */
  33. const SECONDS_IN_A_HOUR = 3600;
  34. const SECONDS_IN_AN_HOUR = 3600;
  35. /**
  36. * A constant representing the number of seconds in a day, for making
  37. * code more verbose
  38. *
  39. * @since 1.0.000
  40. * @var int
  41. */
  42. const SECONDS_IN_A_DAY = 86400;
  43. /**
  44. * A constant representing the number of seconds in a week, for making
  45. * code more verbose
  46. *
  47. * @since 1.0.000
  48. * @var int
  49. */
  50. const SECONDS_IN_A_WEEK = 604800;
  51. /**
  52. * A constant representing the number of seconds in a month (30 days),
  53. * for making code more verbose
  54. *
  55. * @since 1.0.000
  56. * @var int
  57. */
  58. const SECONDS_IN_A_MONTH = 2592000;
  59. /**
  60. * A constant representing the number of seconds in a year (365 days),
  61. * for making code more verbose
  62. *
  63. * @since 1.0.000
  64. * @var int
  65. */
  66. const SECONDS_IN_A_YEAR = 31536000;
  67. /**
  68. * A collapse icon, using in the dump_var function to allow collapsing
  69. * an array or object
  70. *
  71. * @access public
  72. * @since 1.0.000
  73. * @static
  74. * @var string
  75. */
  76. public static $icon_collapse = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNzFDNDQyNEMyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNzFDNDQyM0MyQzkxMUUxOTU4MEM4M0UxRDA0MUVGNSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NDlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MjlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuF4AWkAAAA2UExURU9t2DBStczM/1h16DNmzHiW7iNFrypMvrnD52yJ4ezs7Onp6ejo6P///+Tk5GSG7D9h5SRGq0Q2K74AAAA/SURBVHjaLMhZDsAgDANRY3ZISnP/y1ZWeV+jAeuRSky6cKL4ryDdSggP8UC7r6GvR1YHxjazPQDmVzI/AQYAnFQDdVSJ80EAAAAASUVORK5CYII=';
  77. /**
  78. * A collapse icon, using in the dump_var function to allow collapsing
  79. * an array or object
  80. *
  81. * @access public
  82. * @since 1.0.000
  83. * @static
  84. * @var string
  85. */
  86. public static $icon_expand = 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAMAAADXT/YiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFQzZERTJDNEMyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFQzZERTJDM0MyQzkxMUUxODRCQzgyRUNDMzZEQkZFQiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MzlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3MTlFRjQ2NkM5QzJFMTExOTA0MzkwRkI0M0ZCODY4RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkmDvWIAAABIUExURU9t2MzM/3iW7ubm59/f5urq85mZzOvr6////9ra38zMzObm5rfB8FZz5myJ4SNFrypMvjBStTNmzOvr+mSG7OXl8T9h5SRGq/OfqCEAAABKSURBVHjaFMlbEoAwCEPRULXF2jdW9r9T4czcyUdA4XWB0IgdNSybxU9amMzHzDlPKKu7Fd1e6+wY195jW0ARYZECxPq5Gn8BBgCr0gQmxpjKAwAAAABJRU5ErkJggg==';
  87. /**
  88. * Retrieve a value from the $_POST array, or return a given default if
  89. * the index isn't set
  90. *
  91. * The first n parameters represent the fields to retrieve, being a
  92. * single index or an array of indexes to access multi-level arrays.
  93. *
  94. * Calling the function as util::post_var( ['tags', '1412'] ) is
  95. * identical to using $_POST['tags']['1412'].
  96. *
  97. * @param string $fields The name of the field to retrieve
  98. * @param mixed $default A default value to return if the
  99. * requested variable isn't set
  100. * @return mixed
  101. *
  102. * @see array_get()
  103. *
  104. * @access public
  105. * @since 1.0.000
  106. * @static
  107. */
  108. public static function post_var( $fields, $default = NULL )
  109. {
  110. return self::array_get( $_POST, $fields, $default );
  111. }
  112. /**
  113. * Retrieve a value from the $_GET array, or return a given default if
  114. * the index isn't set
  115. *
  116. * The first n parameters represent the fields to retrieve, being a
  117. * single index or an array of indexes to access multi-level arrays.
  118. *
  119. * Calling the function as util::get_var( ['tags', '1412'] ) is
  120. * identical to using $_GET['tags']['1412'].
  121. *
  122. * @param string $fields The name of the field to retrieve
  123. * @param mixed $default A default value to return if the
  124. * requested variable isn't set
  125. * @return mixed
  126. *
  127. * @see array_get()
  128. *
  129. * @access public
  130. * @since 1.0.000
  131. * @static
  132. */
  133. public static function get_var( $fields, $default = NULL )
  134. {
  135. return self::array_get( $_GET, $fields, $default );
  136. }
  137. /**
  138. * Retrieve a value from the $_GET or the $_POST array, or return a
  139. * given default if the index isn't set. You may expect this function
  140. * to check the $_REQUEST variable, but the desired behavior is often
  141. * to check $_GET or $_POST. To avoid screwing stuff up if $_COOKIE is
  142. * set, and to avoid relying on the user to set the request_order
  143. * option, we just make that assumption for them.
  144. *
  145. * The first n parameters represent the fields to retrieve, being a
  146. * single index or an array of indexes to access multi-level arrays.
  147. *
  148. * Calling the function as util::request_var( ['tags', '1412'] ) is
  149. * identical to using $_REQUEST['tags']['1412'].
  150. *
  151. * @param string $fields The name of the field to retrieve
  152. * @param mixed $default A default value to return if the requested variable isn't set
  153. * @return mixed
  154. *
  155. * @see array_get()
  156. *
  157. * @access public
  158. * @since 1.0.000
  159. * @static
  160. */
  161. public static function request_var( $fields, $default = NULL )
  162. {
  163. if ( strstr( ini_get( 'request_order' ), 'GP' ) ) {
  164. return self::array_get( array_merge( $_POST, $_GET ), $fields, $default );
  165. } else {
  166. return self::array_get( array_merge( $_GET, $_POST ), $fields, $default );
  167. }
  168. }
  169. /**
  170. * Retrieve a value from the $_SESSION array, or return a given default
  171. * if the index isn't set
  172. *
  173. * The first n parameters represent the fields to retrieve, being a
  174. * single index or an array of indexes to access multi-level arrays.
  175. *
  176. * Calling the function as util::session_var( ['tags', '1412'] ) is
  177. * identical to using $_SESSION['tags']['1412'].
  178. *
  179. * @param string $fields The name of the field to retrieve
  180. * @param mixed $default A default value to return if the
  181. * requested variable isn't set
  182. * @return mixed
  183. *
  184. * @see array_get()
  185. *
  186. * @access public
  187. * @since 1.0.000
  188. * @static
  189. */
  190. public static function session_var( $fields, $default = NULL )
  191. {
  192. return self::array_get( $_SESSION, $fields, $default );
  193. }
  194. /**
  195. * Retrieve a value from the $_COOKIE array, or return a given default
  196. * if the index isn't set
  197. *
  198. * The first n parameters represent the fields to retrieve, being a
  199. * single index or an array of indexes to access multi-level arrays.
  200. *
  201. * Calling the function as util::cookie_var( ['tags', '1412'] ) is
  202. * identical to using $_COOKIE['tags']['1412'].
  203. *
  204. * @param string $fields The name of the field to retrieve
  205. * @param mixed $default A default value to return if the
  206. * requested variable isn't set
  207. * @return mixed
  208. *
  209. * @see array_get()
  210. *
  211. * @access public
  212. * @since 1.0.000
  213. * @static
  214. */
  215. public static function cookie_var( $fields, $default = NULL )
  216. {
  217. return self::array_get( $_COOKIE, $fields, $default );
  218. }
  219. /**
  220. * Access an array index, retrieving the value stored there if it
  221. * exists or a default if it does not. This function allows you to
  222. * concisely access an index which may or may not exist without
  223. * raising a warning
  224. *
  225. * @param array $array
  226. * @param $fields
  227. * @param mixed $default Default value to return if the key is not
  228. * present in the array
  229. * @internal param array $var Array to access
  230. * @internal param string $field Index to access in the array
  231. * @return mixed
  232. *
  233. * @access public
  234. * @since 1.0.000
  235. * @static
  236. */
  237. public static function array_get( array $array, $fields, $default = NULL )
  238. {
  239. if ( ! is_array( $array ) ) {
  240. return $default;
  241. } else if ( ! is_array( $fields ) ) {
  242. if ( isset( $array[$fields] ) ) {
  243. return $array[$fields];
  244. } else {
  245. return $default;
  246. }
  247. } else {
  248. foreach ( $fields as $field ) {
  249. $found_it = false;
  250. if ( ! is_array( $array ) ) {
  251. break;
  252. }
  253. foreach ( $array as $key => $value ) {
  254. if ( $key == $field ) {
  255. $found_it = true;
  256. $array = $value;
  257. break;
  258. }
  259. }
  260. }
  261. if ( $found_it ) {
  262. return $array;
  263. } else {
  264. return $default;
  265. }
  266. }
  267. }
  268. /**
  269. * Display a variable's contents using nice HTML formatting and will
  270. * properly display the value of booleans as true or false
  271. *
  272. * @param mixed $var The variable to dump
  273. * @param bool $return
  274. * @return string
  275. *
  276. * @see var_dump_plain()
  277. *
  278. * @access public
  279. * @since 1.0.000
  280. * @static
  281. */
  282. public static function var_dump( $var, $return = false )
  283. {
  284. $html = '<pre style="margin-bottom: 18px;' .
  285. 'background: #f7f7f9;' .
  286. 'border: 1px solid #e1e1e8;' .
  287. 'padding: 8px;' .
  288. 'border-radius: 4px;' .
  289. '-moz-border-radius: 4px;' .
  290. '-webkit-border radius: 4px;' .
  291. 'display: block;' .
  292. 'font-size: 12.05px;' .
  293. 'white-space: pre-wrap;' .
  294. 'word-wrap: break-word;' .
  295. 'color: #333;' .
  296. 'text-align: left;' .
  297. 'font-family: Menlo,Monaco,Consolas,\'Courier New\',monospace;">';
  298. $html .= self::var_dump_plain( $var, true );
  299. $html .= '</pre>';
  300. if ( ! $return ) {
  301. echo $html;
  302. } else {
  303. return $html;
  304. }
  305. }
  306. /**
  307. * Display a variable's contents using nice HTML formatting (Without
  308. * the <pre> tag) and will properly display the values of variables
  309. * like booleans and resources. Supports collapsable arrays and objects
  310. * as well.
  311. *
  312. * @param mixed $var The variable to dump
  313. * @param bool $traversedeeper
  314. * @return string
  315. *
  316. * @access public
  317. * @since 1.0.000
  318. * @static
  319. */
  320. public static function var_dump_plain( $var, $traversedeeper = false )
  321. {
  322. // Don't traverse into Closures or Silex / Symfony objects..
  323. if (is_object($var)) {
  324. list($root) = explode("\\", get_class($var));
  325. // echo "[ " .$root . " - " .get_class($var)." ]";
  326. if ( !$traversedeeper && ( (get_class($var) == "Bolt\\Application") || in_array($root, array('Closure', 'Silex', 'Symfony')) || substr($root, 0, 5)=="Twig_" )) {
  327. $html = '<span style="color:#588bff;">object</span>(' . get_class( $var ) . ') ';
  328. // echo "[return]\n";
  329. return $html;
  330. }
  331. // echo "[stay]\n";
  332. }
  333. $html = '';
  334. if ( is_bool( $var ) ) {
  335. $html .= '<span style="color:#588bff;">boo</span><span style="color:#999;">(</span><strong>' . ( ( $var ) ? 'true' : 'false' ) . '</strong><span style="color:#999;">)</span>';
  336. } else if ( is_int( $var ) ) {
  337. $html .= '<span style="color:#588bff;">int</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
  338. } else if ( is_float( $var ) ) {
  339. $html .= '<span style="color:#588bff;">flo</span><span style="color:#999;">(</span><strong>' . $var . '</strong><span style="color:#999;">)</span>';
  340. } else if ( is_string( $var ) ) {
  341. $html .= '<span style="color:#588bff;">str</span><span style="color:#999;">(</span>' . strlen( $var ) . '<span style="color:#999;">)</span> <strong>"' . self::htmlentities( $var ) . '"</strong>';
  342. } else if ( is_null( $var ) ) {
  343. $html .= '<strong>NULL</strong>';
  344. } else if ( is_resource( $var ) ) {
  345. $html .= '<span style="color:#588bff;">res</span>("' . get_resource_type( $var ) . '") <strong>"' . $var . '"</strong>';
  346. } else if ( is_array( $var ) ) {
  347. $uuid = uniqid('include-php-',true);
  348. $html .= '<span style="color:#588bff;">arr</span>(' . count( $var ) . ')';
  349. if ( ! empty( $var ) ) {
  350. $html .= ' <img id="' . $uuid . '" data-collapse="data:image/png;base64,' . self::$icon_collapse . '" style="position:relative;left:-5px;top:-1px;cursor:pointer;width:9px!important;height:9px!important;" src="data:image/png;base64,' . self::$icon_expand . '" /> <span id="' . $uuid . '-collapsable" style="display: none;">[<br />';
  351. $indent = 4;
  352. $longest_key = 0;
  353. foreach( $var as $key => $value ) {
  354. if ( is_string( $key ) ) {
  355. $longest_key = max( $longest_key, strlen( $key ) + 2 );
  356. } else {
  357. $longest_key = max( $longest_key, strlen( $key ) );
  358. }
  359. }
  360. foreach ( $var as $key => $value ) {
  361. if ( is_numeric( $key ) ) {
  362. $html .= str_repeat( ' ', $indent ) . str_pad( $key, $longest_key, '_');
  363. } else {
  364. $html .= str_repeat( ' ', $indent ) . str_pad( '"' . self::htmlentities( $key ) . '"', $longest_key, ' ' );
  365. }
  366. $html .= ' => ';
  367. $value = explode( '<br />', self::var_dump_plain( $value ) );
  368. foreach ( $value as $line => $val ) {
  369. if ( $line != 0 ) {
  370. $value[$line] = str_repeat( ' ', $indent * 2 ) . $val;
  371. }
  372. }
  373. $html .= implode( '<br />', $value ) . '<br />';
  374. }
  375. $html .= ']</span>';
  376. $html .= preg_replace( '/ +/', ' ', '<script type="text/javascript">(function() {
  377. var img = document.getElementById("' . $uuid . '");
  378. img.onclick = function() {
  379. if ( document.getElementById("' . $uuid . '-collapsable").style.display == "none" ) {
  380. document.getElementById("' . $uuid . '-collapsable").style.display = "inline";
  381. img.setAttribute( "data-expand", img.getAttribute("src") );
  382. img.src = img.getAttribute("data-collapse");
  383. var previousSibling = document.getElementById("' . $uuid . '-collapsable").previousSibling;
  384. } else {
  385. document.getElementById("' . $uuid . '-collapsable").style.display = "none";
  386. img.src = img.getAttribute("data-expand");
  387. var previousSibling = document.getElementById("' . $uuid . '-collapsable").previousSibling;
  388. }
  389. };
  390. })();
  391. </script>' );
  392. }
  393. } else if ( is_object( $var ) ) {
  394. $uuid = uniqid('include-php-',true);
  395. $html .= '<span style="color:#588bff;">object</span>(' . get_class( $var ) . ') <img id="' . $uuid . '" data-collapse="data:image/png;base64,' . self::$icon_collapse . '" style="position:relative;left:-5px;top:-1px;cursor:pointer;width:9px!important;height:9px!important;" src="data:image/png;base64,' . self::$icon_expand . '" /> <span id="' . $uuid . '-collapsable" style="display: none;">[<br />';
  396. $original = $var;
  397. $var = (array) $var;
  398. $indent = 4;
  399. $longest_key = 0;
  400. foreach( $var as $key => $value ) {
  401. if ( substr( $key, 0, 2 ) == "\0*" ) {
  402. unset( $var[$key] );
  403. $key = 'protected:' . substr( $key, 2 );
  404. $var[$key] = $value;
  405. } else if ( substr( $key, 0, 1 ) == "\0" ) {
  406. unset( $var[$key] );
  407. $key = 'private:' . substr( $key, 1, strpos( substr( $key, 1 ), "\0" ) ) . ':' . substr( $key, strpos( substr( $key, 1 ), "\0" ) + 1 );
  408. $var[$key] = $value;
  409. }
  410. if ( is_string( $key ) ) {
  411. $longest_key = max( $longest_key, strlen( $key ) + 2 );
  412. } else {
  413. $longest_key = max( $longest_key, strlen( $key ) );
  414. }
  415. }
  416. foreach ( $var as $key => $value ) {
  417. if ( is_numeric( $key ) ) {
  418. $html .= str_repeat( ' ', $indent ) . str_pad( $key, $longest_key, ' ');
  419. } else {
  420. $html .= str_repeat( ' ', $indent ) . str_pad( '"' . self::htmlentities( $key ) . '"', $longest_key, ' ' );
  421. }
  422. $html .= ' => ';
  423. $value = explode( '<br />', self::var_dump_plain( $value ) );
  424. foreach ( $value as $line => $val ) {
  425. if ( $line != 0 ) {
  426. $value[$line] = str_repeat( ' ', $indent * 2 ) . $val;
  427. }
  428. }
  429. $html .= implode( '<br />', $value ) . '<br />';
  430. }
  431. $html .= ']</span>';
  432. $html .= preg_replace( '/ +/', ' ', '<script type="text/javascript">(function() {
  433. var img = document.getElementById("' . $uuid . '");
  434. img.onclick = function() {
  435. if ( document.getElementById("' . $uuid . '-collapsable").style.display == "none" ) {
  436. document.getElementById("' . $uuid . '-collapsable").style.display = "inline";
  437. img.setAttribute( "data-expand", img.getAttribute("src") );
  438. img.src = img.getAttribute("data-collapse");
  439. var previousSibling = document.getElementById("' . $uuid . '-collapsable").previousSibling;
  440. } else {
  441. document.getElementById("' . $uuid . '-collapsable").style.display = "none";
  442. img.src = img.getAttribute("data-expand");
  443. var previousSibling = document.getElementById("' . $uuid . '-collapsable").previousSibling;
  444. }
  445. };
  446. })();
  447. </script>' );
  448. }
  449. return $html;
  450. }
  451. /**
  452. * Converts any accent characters to their equivalent normal characters
  453. * and converts any other non-alphanumeric characters to dashes, then
  454. * converts any sequence of two or more dashes to a single dash. This
  455. * function generates slugs safe for use as URLs, and if you pass true
  456. * as the second parameter, it will create strings safe for use as CSS
  457. * classes or IDs
  458. *
  459. * @param string $string A string to convert to a slug
  460. * @param bool $css_mode Whether or not to generate strings safe
  461. * for CSS classes/IDs (Default to false)
  462. * @return string
  463. *
  464. * @access public
  465. * @since 1.0.000
  466. * @static
  467. */
  468. public static function slugify( $string, $css_mode = false )
  469. {
  470. $slug = preg_replace( '/([^A-Za-z0-9\-]+)/', '-', strtolower( self::remove_accents( $string ) ) );
  471. $slug = preg_replace( '/(\-+)/', '-', $slug );
  472. if ( $css_mode ) {
  473. $digits = array( 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine' );
  474. if ( is_numeric( substr( $slug, 0, 1 ) ) ) {
  475. $slug = $digits[substr( $slug, 0, 1 )] . substr( $slug, 1 );
  476. }
  477. }
  478. return $slug;
  479. }
  480. /**
  481. * Converts a string to UTF-8 without the need to specify the source
  482. * encoding
  483. *
  484. * @param string $string A string that may or may not be UTF-8
  485. * @return string
  486. *
  487. * @link https://github.com/facebook/libphutil/blob/master/src/utils/utf8.php
  488. *
  489. * @access public
  490. * @since 1.0.000
  491. * @static
  492. */
  493. public static function str_to_utf8( $string )
  494. {
  495. // Don't re-encode a UTF-8 string since that will mess it up
  496. if ( self::seems_utf8( $string ) ) {
  497. return $string;
  498. } else {
  499. // There is no function to do this in iconv, mbstring or ICU to
  500. // do this, so do it (very very slowly) in pure PHP.
  501. $result = array();
  502. $regex = "/([\x01-\x7F]" .
  503. "|[\xC2-\xDF][\x80-\xBF]" .
  504. "|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]" .
  505. "|[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF])" .
  506. "|(.)/";
  507. $offset = 0;
  508. $matches = NULL;
  509. while ( preg_match( $regex, $string, $matches, 0, $offset ) ) {
  510. if ( ! isset( $matches[2] ) ) {
  511. $result[] = $matches[1];
  512. } else {
  513. // Unicode replacement character, U+FFFD.
  514. $result[] = "\xEF\xBF\xBD";
  515. }
  516. $offset += strlen( $matches[0] );
  517. }
  518. return implode( '', $result );
  519. }
  520. }
  521. /**
  522. * Checks to see if a string is utf8 encoded.
  523. *
  524. * NOTE: This function checks for 5-Byte sequences, UTF8
  525. * has Bytes Sequences with a maximum length of 4.
  526. *
  527. * @param string $string The string to be checked
  528. * @return bool
  529. *
  530. * @link https://github.com/facebook/libphutil/blob/master/src/utils/utf8.php
  531. *
  532. * @access public
  533. * @author bmorel@ssi.fr
  534. * @since 1.0.000
  535. * @static
  536. */
  537. public static function seems_utf8( $string )
  538. {
  539. if ( function_exists( 'mb_check_encoding' ) ) {
  540. // If mbstring is available, this is significantly faster than
  541. // using PHP regexps.
  542. return mb_check_encoding( $string, 'UTF-8' );
  543. }
  544. $regex = '/(
  545. | [\xF8-\xFF] # Invalid UTF-8 Bytes
  546. | [\xC0-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
  547. | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
  548. | [\xF0-\xF7](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
  549. | (?<=[\x0-\x7F\xF8-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
  550. | (?<![\xC0-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF7]|[\xF0-\xF7][\x80-\xBF]|[\xF0-\xF7][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
  551. | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
  552. | (?<=[\xF0-\xF7])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
  553. | (?<=[\xF0-\xF7][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
  554. )/x';
  555. return ! preg_match( $regex, $string );
  556. }
  557. /**
  558. * Nice formatting for computer sizes (Bytes)
  559. *
  560. * @param int $bytes The number in bytes to format
  561. * @param int $decimals The number of decimal points to include
  562. * @return string
  563. *
  564. * @access public
  565. * @since 1.0.000
  566. * @static
  567. */
  568. public static function size_format( $bytes, $decimals = 0 )
  569. {
  570. $bytes = floatval( $bytes );
  571. if ( $bytes < 1024 ) {
  572. return $bytes . ' B';
  573. } else if ( $bytes < pow( 1024, 2 ) ) {
  574. return number_format( $bytes / 1024, $decimals, '.', '' ) . ' KiB';
  575. } else if ( $bytes < pow( 1024, 3 ) ) {
  576. return number_format( $bytes / pow( 1024, 2 ), $decimals, '.', '' ) . ' MiB';
  577. } else if ( $bytes < pow( 1024, 4 ) ) {
  578. return number_format( $bytes / pow( 1024, 3 ), $decimals, '.', '' ) . ' GiB';
  579. } else if ( $bytes < pow( 1024, 5 ) ) {
  580. return number_format( $bytes / pow( 1024, 4 ), $decimals, '.', '' ) . ' TiB';
  581. } else if ( $bytes < pow( 1024, 6 ) ) {
  582. return number_format( $bytes / pow( 1024, 5 ), $decimals, '.', '' ) . ' PiB';
  583. } else {
  584. return number_format( $bytes / pow( 1024, 5 ), $decimals, '.', '' ) . ' PiB';
  585. }
  586. }
  587. /**
  588. * Checks to see if the page is being server over SSL or not
  589. *
  590. * @return bool
  591. *
  592. * @access public
  593. * @since 1.0.000
  594. * @static
  595. */
  596. public static function is_https()
  597. {
  598. if ( isset( $_SERVER['HTTPS'] ) && ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] != 'off' ) {
  599. return true;
  600. } else {
  601. return false;
  602. }
  603. }
  604. /**
  605. * Retrieve a modified URL query string.
  606. *
  607. * You can rebuild the URL and append a new query variable to the URL
  608. * query by using this function. You can also retrieve the full URL
  609. * with query data.
  610. *
  611. * Adding a single key & value or an associative array. Setting a key
  612. * value to an empty string removes the key. Omitting oldquery_or_uri
  613. * uses the $_SERVER value. Additional values provided are expected
  614. * to be encoded appropriately with urlencode() or rawurlencode().
  615. *
  616. * @internal param mixed $newkey Either newkey or an associative
  617. * array
  618. * @internal param mixed $newvalue Either newvalue or oldquery or uri
  619. * @internal param mixed $oldquery_or_uri Optionally the old query or uri
  620. * @return string
  621. *
  622. * @link http://codex.wordpress.org/Function_Reference/add_query_arg
  623. *
  624. * @access public
  625. * @since 1.0.000
  626. * @static
  627. */
  628. public static function add_query_arg()
  629. {
  630. $ret = '';
  631. // Was an associative array of key => value pairs passed?
  632. if ( is_array( func_get_arg( 0 ) ) ) {
  633. // Was the URL passed as an argument?
  634. if ( func_num_args() == 2 && func_get_arg( 1 ) ) {
  635. $uri = func_get_arg( 1 );
  636. } else if ( func_num_args() == 3 && func_get_arg( 2 ) ) {
  637. $uri = func_get_arg( 2 );
  638. } else {
  639. $uri = $_SERVER['REQUEST_URI'];
  640. }
  641. } else {
  642. // Was the URL passed as an argument?
  643. if ( func_num_args() == 3 && func_get_arg( 2 ) ) {
  644. $uri = func_get_arg( 2 );
  645. } else {
  646. $uri = $_SERVER['REQUEST_URI'];
  647. }
  648. }
  649. // Does the URI contain a fragment section (The part after the #)
  650. if ( $frag = strstr( $uri, '#' ) ) {
  651. $uri = substr( $uri, 0, -strlen( $frag ) );
  652. } else {
  653. $frag = '';
  654. }
  655. // Get the URI protocol if possible
  656. if ( preg_match( '|^https?://|i', $uri, $matches ) ) {
  657. $protocol = $matches[0];
  658. $uri = substr( $uri, strlen( $protocol ) );
  659. } else {
  660. $protocol = '';
  661. }
  662. // Does the URI contain a query string?
  663. if ( strpos( $uri, '?' ) !== false ) {
  664. $parts = explode( '?', $uri, 2 );
  665. if ( 1 == count( $parts ) ) {
  666. $base = '?';
  667. $query = $parts[0];
  668. } else {
  669. $base = $parts[0] . '?';
  670. $query = $parts[1];
  671. }
  672. } else if ( ! empty( $protocol ) || strpos( $uri, '=' ) === false ) {
  673. $base = $uri . '?';
  674. $query = '';
  675. } else {
  676. $base = '';
  677. $query = $uri;
  678. }
  679. // Parse the query string into an array
  680. parse_str( $query, $qs );
  681. // This re-URL-encodes things that were already in the query string
  682. $qs = self::array_map_deep( $qs, 'urlencode' );
  683. if ( is_array( func_get_arg( 0 ) ) ) {
  684. $kayvees = func_get_arg( 0 );
  685. $qs = array_merge( $qs, $kayvees );
  686. } else {
  687. $qs[func_get_arg( 0 )] = func_get_arg( 1 );
  688. }
  689. foreach ( (array) $qs as $k => $v ) {
  690. if ( $v === false )
  691. unset( $qs[$k] );
  692. }
  693. $ret = http_build_query( $qs );
  694. $ret = trim( $ret, '?' );
  695. $ret = preg_replace( '#=(&|$)#', '$1', $ret );
  696. $ret = $protocol . $base . $ret . $frag;
  697. $ret = rtrim( $ret, '?' );
  698. return $ret;
  699. }
  700. /**
  701. * Removes an item or list from the query string.
  702. *
  703. * @param string|array $keys Query key or keys to remove.
  704. * @param bool $uri When false uses the $_SERVER value
  705. * @return string
  706. *
  707. * @link http://codex.wordpress.org/Function_Reference/remove_query_arg
  708. *
  709. * @access public
  710. * @since 1.0.000
  711. * @static
  712. */
  713. public static function remove_query_arg( $keys, $uri = false )
  714. {
  715. if ( is_array( $keys ) ) {
  716. foreach ( $keys as $key ) {
  717. $uri = self::add_query_arg( $key, false, $uri );
  718. }
  719. return $uri;
  720. }
  721. return self::add_query_arg( $keys, false, $uri );
  722. }
  723. /**
  724. * Converts many english words that equate to true or false to boolean
  725. *
  726. * Supports 'y', 'n', 'yes', 'no' and a few other variations
  727. *
  728. * @param string $string The string to convert to boolean
  729. * @param bool $default The value to return if we can't match any
  730. * yes/no words
  731. * @return bool
  732. *
  733. * @access public
  734. * @since 1.0.000
  735. * @static
  736. */
  737. public static function str_to_bool( $string, $default = false )
  738. {
  739. $yes_words = 'affirmative|all right|aye|indubitably|most assuredly|ok|of course|okay|sure thing|y|yes+|yea|yep|sure|yeah|true|t';
  740. $no_words = 'no*|no way|nope|nah|na|never|absolutely not|by no means|negative|never ever|false|f';
  741. if ( preg_match( '/^(' . $yes_words . ')$/i', $string ) ) {
  742. return true;
  743. } else if ( preg_match( '/^(' . $no_words . ')$/i', $string ) ) {
  744. return false;
  745. } else {
  746. return $default;
  747. }
  748. }
  749. /**
  750. * Return the absolute integer value of a given variable
  751. *
  752. * @param mixed $maybeint A variable that could be a string,
  753. * integer or other value
  754. * @return int
  755. *
  756. * @access public
  757. * @since 1.0.000
  758. * @static
  759. */
  760. public static function absint( $maybeint )
  761. {
  762. return abs( intval( $maybeint ) );
  763. }
  764. /**
  765. * Convert entities, while preserving already-encoded entities
  766. *
  767. * @param string $string The text to be converted
  768. * @param bool $preserve_encoded_entities
  769. * @return string
  770. *
  771. * @link http://ca2.php.net/manual/en/function.htmlentities.php#90111
  772. *
  773. * @access public
  774. * @since 1.0.000
  775. * @static
  776. */
  777. public static function htmlentities( $string, $preserve_encoded_entities = false )
  778. {
  779. if ( $preserve_encoded_entities ) {
  780. $translation_table = get_html_translation_table( HTML_ENTITIES, ENT_QUOTES );
  781. $translation_table[chr(38)] = '&';
  782. return preg_replace( '/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&amp;', strtr( $string, $translation_table ) );
  783. } else {
  784. return htmlentities( $string, ENT_QUOTES );
  785. }
  786. }
  787. /**
  788. * Convert >, <, ', " and & to html entities, but preserves entities
  789. * that are already encoded
  790. *
  791. * @param string $string The text to be converted
  792. * @param bool $preserve_encoded_entities
  793. * @return string
  794. *
  795. * @link http://ca2.php.net/manual/en/function.htmlentities.php#90111
  796. *
  797. * @access public
  798. * @since 1.0.000
  799. * @static
  800. */
  801. public static function htmlspecialchars( $string, $preserve_encoded_entities = false )
  802. {
  803. if ( $preserve_encoded_entities ) {
  804. $translation_table = get_html_translation_table( HTML_SPECIALCHARS, ENT_QUOTES );
  805. $translation_table[chr( 38 )] = '&';
  806. return preg_replace( '/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/', '&amp;', strtr( $string, $translation_table ) );
  807. } else {
  808. return htmlentities( $string, ENT_QUOTES );
  809. }
  810. }
  811. /**
  812. * Converts all accent characters to ASCII characters
  813. *
  814. * If there are no accent characters, then the string given is just
  815. * returned
  816. *
  817. * @param string $string Text that might have accent characters
  818. * @return string Filtered string with replaced "nice" characters
  819. *
  820. * @link http://codex.wordpress.org/Function_Reference/remove_accents
  821. *
  822. * @access public
  823. * @since 1.0.000
  824. * @static
  825. */
  826. public static function remove_accents( $string )
  827. {
  828. if ( ! preg_match( '/[\x80-\xff]/', $string ) ) {
  829. return $string;
  830. }
  831. if ( self::seems_utf8( $string ) ) {
  832. $chars = array(
  833. // Decompositions for Latin-1 Supplement
  834. chr(194).chr(170) => 'a', chr(194).chr(186) => 'o',
  835. chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
  836. chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
  837. chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
  838. chr(195).chr(134) => 'AE',chr(195).chr(135) => 'C',
  839. chr(195).chr(136) => 'E', chr(195).chr(137) => 'E',
  840. chr(195).chr(138) => 'E', chr(195).chr(139) => 'E',
  841. chr(195).chr(140) => 'I', chr(195).chr(141) => 'I',
  842. chr(195).chr(142) => 'I', chr(195).chr(143) => 'I',
  843. chr(195).chr(144) => 'D', chr(195).chr(145) => 'N',
  844. chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
  845. chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
  846. chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
  847. chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
  848. chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
  849. chr(195).chr(158) => 'TH',chr(195).chr(159) => 's',
  850. chr(195).chr(160) => 'a', chr(195).chr(161) => 'a',
  851. chr(195).chr(162) => 'a', chr(195).chr(163) => 'a',
  852. chr(195).chr(164) => 'a', chr(195).chr(165) => 'a',
  853. chr(195).chr(166) => 'ae',chr(195).chr(167) => 'c',
  854. chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
  855. chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
  856. chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
  857. chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
  858. chr(195).chr(176) => 'd', chr(195).chr(177) => 'n',
  859. chr(195).chr(178) => 'o', chr(195).chr(179) => 'o',
  860. chr(195).chr(180) => 'o', chr(195).chr(181) => 'o',
  861. chr(195).chr(182) => 'o', chr(195).chr(184) => 'o',
  862. chr(195).chr(185) => 'u', chr(195).chr(186) => 'u',
  863. chr(195).chr(187) => 'u', chr(195).chr(188) => 'u',
  864. chr(195).chr(189) => 'y', chr(195).chr(190) => 'th',
  865. chr(195).chr(191) => 'y', chr(195).chr(152) => 'O',
  866. // Decompositions for Latin Extended-A
  867. chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
  868. chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
  869. chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
  870. chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
  871. chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
  872. chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
  873. chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
  874. chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
  875. chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
  876. chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
  877. chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
  878. chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
  879. chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
  880. chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
  881. chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
  882. chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
  883. chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
  884. chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
  885. chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
  886. chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
  887. chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
  888. chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
  889. chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
  890. chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
  891. chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
  892. chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
  893. chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
  894. chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
  895. chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
  896. chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
  897. chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
  898. chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
  899. chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
  900. chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
  901. chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
  902. chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
  903. chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
  904. chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
  905. chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
  906. chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
  907. chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
  908. chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
  909. chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
  910. chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
  911. chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
  912. chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
  913. chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
  914. chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
  915. chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
  916. chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
  917. chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
  918. chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
  919. chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
  920. chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
  921. chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
  922. chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
  923. chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
  924. chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
  925. chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
  926. chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
  927. chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
  928. chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
  929. chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
  930. chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
  931. // Decompositions for Latin Extended-B
  932. chr(200).chr(152) => 'S', chr(200).chr(153) => 's',
  933. chr(200).chr(154) => 'T', chr(200).chr(155) => 't',
  934. // Euro Sign
  935. chr(226).chr(130).chr(172) => 'E',
  936. // GBP (Pound) Sign
  937. chr(194).chr(163) => ''
  938. );
  939. $string = strtr( $string, $chars );
  940. } else {
  941. // Assume ISO-8859-1 if not UTF-8
  942. $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
  943. .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
  944. .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
  945. .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
  946. .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
  947. .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
  948. .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
  949. .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
  950. .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
  951. .chr(252).chr(253).chr(255);
  952. $chars['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';
  953. $string = strtr( $string, $chars['in'], $chars['out'] );
  954. $double_chars['in'] = array( chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254) );
  955. $double_chars['out'] = array( 'OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th' );
  956. $string = str_replace( $double_chars['in'], $double_chars['out'], $string );
  957. }
  958. return $string;
  959. }
  960. /**
  961. * Pads a given string with zeroes on the left
  962. *
  963. * @param int $number The number to pad
  964. * @param int $length The total length of the desired string
  965. * @return string
  966. *
  967. * @access public
  968. * @since 1.0.000
  969. * @static
  970. */
  971. public static function zero_pad( $number, $length )
  972. {
  973. return str_pad( $number, $length, '0', STR_PAD_LEFT );
  974. }
  975. /**
  976. * Converts a unix timestamp to a relative time string, such as "3 days
  977. * ago" or "2 weeks ago"
  978. *
  979. * @param int $from The date to use as a starting point
  980. * @param int|string $to The date to compare to. Defaults to the
  981. * current time
  982. * @param bool $as_text
  983. * @param string $suffix The string to add to the end, defaults to
  984. * " ago"
  985. * @return string
  986. *
  987. * @access public
  988. * @since 1.0.000
  989. * @static
  990. */
  991. public static function human_time_diff( $from, $to = '', $as_text = false, $suffix = ' ago' )
  992. {
  993. if ( $to == '' ) {
  994. $to = time();
  995. }
  996. $from = new DateTime( date( 'Y-m-d H:i:s', $from ) );
  997. $to = new DateTime( date( 'Y-m-d H:i:s', $to ) );
  998. $diff = $from->diff( $to );
  999. if ( $diff->y > 1 ) {
  1000. $text = $diff->y . ' years';
  1001. } else if ( $diff->y == 1 ) {
  1002. $text = '1 year';
  1003. } else if ( $diff->m > 1 ) {
  1004. $text = $diff->m . ' months';
  1005. } else if ( $diff->m == 1 ) {
  1006. $text = '1 month';
  1007. } else if ( $diff->d > 7 ) {
  1008. $text = ceil( $diff->d / 7 ) . ' weeks';
  1009. } else if ( $diff->d == 7 ) {
  1010. $text = '1 week';
  1011. } else if ( $diff->d > 1 ) {
  1012. $text = $diff->d . ' days';
  1013. } else if ( $diff->d == 1 ) {

Large files files are truncated, but you can click here to view the full file