PageRenderTime 84ms CodeModel.GetById 4ms app.highlight 70ms RepoModel.GetById 1ms app.codeStats 0ms

/app/classes/util.php

https://github.com/schwarzmedia/bolt
PHP | 2106 lines | 1121 code | 201 blank | 784 comment | 300 complexity | b4828945cf5df6f8abe562e60da86959 MD5 | raw file

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

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