e107inc/e107

View on GitHub
e107_handlers/Shims/Internal/StrptimeTrait.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php
/**
 * e107 website system
 *
 * Copyright (C) 2008-2020 e107 Inc (e107.org)
 * Released under the terms and conditions of the
 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
 *
 * Shims for PHP internal functions
 * strptime()
 */

namespace e107\Shims\Internal;

use DateTimeZone;
use e_date;

/**
 *
 */
trait StrptimeTrait
{
    /**
     * Parse a time/date generated with strftime()
     *
     * Resilient replacement for PHP internal strptime()
     *
     * @see https://www.php.net/manual/en/function.strptime.php what this function approximates
     * @param string $date The string to parse (e.g. returned from strftime()).
     * @param string $format The format used in date (e.g. the same as used in strftime()).
     * @return array|bool Returns FALSE on failure.
     *     The following parameters are returned in the array:
     *      "tm_sec"        Seconds after the minute (0-61)
     *      "tm_min"        Minutes after the hour (0-59)
     *      "tm_hour"       Hour since midnight (0-23)
     *      "tm_mday"       Day of the month (1-31)
     *      "tm_mon"        Months since January (0-11)
     *      "tm_year"       Years since 1900
     *      "tm_wday"       Days since Sunday (0-6)
     *      "tm_yday"       Days since January 1 (0-365)
     *      "unparsed"      the date part which was not recognized using the specified format
     */
    public static function strptime($date, $format)
    {
        $result = false;
        if (function_exists('strptime') && (new \ReflectionFunction('strptime'))->isInternal())
            // @ to suppress PHP 8.1 deprecation warning
            $result = @strptime($date, $format);
        if (!is_array($result))
            $result = self::strptime_alt($date, $format);
        return $result;
    }

    /**
     * Parse a time/date generated with strftime()
     *
     * Alternative implementation based on public domain library:
     * https://github.com/Polycademy/upgradephp/
     *
     * @param string $date
     * @param string $format
     * @return array|bool
     */
    public static function strptime_alt($date, $format)
    {
        static $expand = array('%D' => '%m/%d/%y', '%T' => '%H:%M:%S',);
        static $map_r = array(
            '%S' => 'tm_sec',
            '%M' => 'tm_min',
            '%H' => 'tm_hour',
            '%I' => 'tm_hour',
            '%d' => 'tm_mday',
            '%m' => 'tm_mon',
            '%Y' => 'tm_year',
            '%y' => 'tm_year',
            '%W' => 'tm_wday',
            '%D' => 'tm_yday',
            '%u' => 'unparsed',
        );

        $fullmonth = array();
        $abrevmonth = array();

        for ($i = 1; $i <= 12; $i++)
        {
            $k = @strftime('%B', mktime(0, 0, 0, $i));
            $fullmonth[$k] = $i;

            $j = @strftime('%b', mktime(0, 0, 0, $i));
            $abrevmonth[$j] = $i;
        }


        #-- transform $format into extraction regex
        $format = str_replace(array_keys($expand), array_values($expand), $format);
        $preg = preg_replace('/(%\w)/', '(\w+)', preg_quote($format));

        #-- record the positions of all STRFCMD-placeholders
        preg_match_all('/(%\w)/', $format, $positions);
        $positions = $positions[1];

        $vals = array();

        #-- get individual values
        if (preg_match("#$preg#", $date, $extracted))
        {
            #-- get values
            foreach ($positions as $pos => $strfc)
            {
                $v = $extracted[$pos + 1];
                #-- add
                if (isset($map_r[$strfc]))
                {
                    $n = $map_r[$strfc];
                    $vals[$n] = ($v > 0) ? (int)$v : $v;
                }
                else
                {
                    if (!isset($vals['unparsed'])) $vals['unparsed'] = '';
                    $vals['unparsed'] .= $v . ' ';
                }
            }

            #-- fixup some entries
            //$vals["tm_wday"] = $names[ substr($vals["tm_wday"], 0, 3) ];
            if ($vals['tm_year'] >= 1900)
            {
                $vals['tm_year'] -= 1900;
            }
            elseif ($vals['tm_year'] > 0)
            {
                $vals['tm_year'] += 100;
            }

            if ($vals['tm_mon'])
            {
                $vals['tm_mon'] -= 1;
            }

            if (!isset($vals['tm_sec']))
            {
                $vals['tm_sec'] = 0;
            }

            if (!isset($vals['tm_min']))
            {
                $vals['tm_min'] = 0;
            }

            if (!isset($vals['tm_hour']))
            {
                $vals['tm_hour'] = 0;
            }


            if (!isset($vals['unparsed']))
            {
                $vals['unparsed'] = '';
            }

            $unxTimestamp = mktime($vals['tm_hour'], $vals['tm_min'], $vals['tm_sec'], ($vals['tm_mon'] + 1), $vals['tm_mday'], ($vals['tm_year'] + 1900));

            $datetime = date_create("@$unxTimestamp");
            $datetime->setTimezone(new DateTimeZone(date_default_timezone_get()));
            $vals['tm_wday'] = date_format($datetime, 'w'); // Days since Sunday (0-6)
            $vals['tm_yday'] = date_format($datetime, 'z'); // Days since January 1 (0-365)
        }

        return !empty($vals) ? $vals : false;

    }
}