<?php

if (!function_exists("gzdecode")) {
    function gzdecode($data, $maxlength = null, $filename = '', $error = '')
    {
        $len = strlen($data);
        if ($len < 18 || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
            $error = "Not in GZIP format.";
            return null;  // Not GZIP format (See RFC 1952)
        }
        $method = ord(substr($data, 2, 1));  // Compression method
        $flags = ord(substr($data, 3, 1));  // Flags
        if ($flags & 31 != $flags) {
            $error = "Reserved bits not allowed.";
            return null;
        }
        // NOTE: $mtime may be negative (PHP integer limitations)
        $mtime = unpack("V", substr($data, 4, 4));
        $mtime = $mtime[1];
        $xfl = substr($data, 8, 1);
        $os = substr($data, 8, 1);
        $headerlen = 10;
        $extralen = 0;
        $extra = "";
        if ($flags & 4) {
            // 2-byte length prefixed EXTRA data in header
            if ($len - $headerlen - 2 < 8) {
                return false;  // invalid
            }
            $extralen = unpack("v", substr($data, 8, 2));
            $extralen = $extralen[1];
            if ($len - $headerlen - 2 - $extralen < 8) {
                return false;  // invalid
            }
            $extra = substr($data, 10, $extralen);
            $headerlen += 2 + $extralen;
        }
        $filenamelen = 0;
        $filename = "";
        if ($flags & 8) {
            // C-style string
            if ($len - $headerlen - 1 < 8) {
                return false; // invalid
            }
            $filenamelen = strpos(substr($data, $headerlen), chr(0));
            if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
                return false; // invalid
            }
            $filename = substr($data, $headerlen, $filenamelen);
            $headerlen += $filenamelen + 1;
        }
        $commentlen = 0;
        $comment = "";
        if ($flags & 16) {
            // C-style string COMMENT data in header
            if ($len - $headerlen - 1 < 8) {
                return false;    // invalid
            }
            $commentlen = strpos(substr($data, $headerlen), chr(0));
            if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
                return false;    // Invalid header format
            }
            $comment = substr($data, $headerlen, $commentlen);
            $headerlen += $commentlen + 1;
        }
        $headercrc = "";
        if ($flags & 2) {
            // 2-bytes (lowest order) of CRC32 on header present
            if ($len - $headerlen - 2 < 8) {
                return false;    // invalid
            }
            $calccrc = crc32(substr($data, 0, $headerlen)) & 0xffff;
            $headercrc = unpack("v", substr($data, $headerlen, 2));
            $headercrc = $headercrc[1];
            if ($headercrc != $calccrc) {
                $error = "Header checksum failed.";
                return false;    // Bad header CRC
            }
            $headerlen += 2;
        }
        // GZIP FOOTER
        $datacrc = unpack("V", substr($data, -8, 4));
        $datacrc = sprintf('%u', $datacrc[1] & 0xFFFFFFFF);
        $isize = unpack("V", substr($data, -4));
        $isize = $isize[1];
        // decompression:
        $bodylen = $len - $headerlen - 8;
        if ($bodylen < 1) {
            // IMPLEMENTATION BUG!
            return null;
        }
        $body = substr($data, $headerlen, $bodylen);
        $data = "";
        if ($bodylen > 0) {
            switch ($method) {
                case 8:
                    // Currently the only supported compression method:
                    $data = !is_null($maxlength) ? gzinflate($body, $maxlength) : gzinflate($body);
                    //$data = gzinflate($body,$maxlength);
                    break;
                default:
                    $error = "Unknown compression method.";
                    return false;
            }
        }  // zero-byte body content is allowed
        // Verifiy CRC32
        if ($data === false) {
            return false;
        }
        $crc = sprintf("%u", crc32($data));
        $crcOK = $crc == $datacrc;
        $lenOK = $isize == strlen($data);
        if (!$lenOK || !$crcOK) {
            $error = ($lenOK ? '' : 'Length check FAILED. ') . ($crcOK ? '' : 'Checksum FAILED.');
            return false;
        }
        return $data;
    }
}

if (!function_exists('set_magic_quotes_runtime')) {
    function set_magic_quotes_runtime($new_setting)
    {
        return false;
    }
}

if (!function_exists('gettext')) {
    function gettext($txt)
    {
        return $txt;
    }
}

if (!function_exists('array_any')) {
    /**
     * 配列の要素の中にコールバック関数を満たす要素があるかどうかをチェック
     * (PHP 8 >= 8.4.0)
     *
     * @see https://www.php.net/manual/ja/function.array-any.php
     * @param array $array
     * @param callable $callback
     * @return bool
     */
    function array_any(array $array, callable $callback): bool
    {
        foreach ($array as $key => $value) {
            if ($callback($value, $key)) {
                return true;
            }
        }

        return false;
    }
}

if (!function_exists('array_all')) {
    /**
     * 配列の全ての要素がコールバック関数を満たすかどうかをチェック
     * (PHP 8 >= 8.4.0)
     *
     * @see https://www.php.net/manual/ja/function.array-all.php
     * @param array $array
     * @param callable $callback
     * @return bool
     */
    function array_all(array $array, callable $callback): bool
    {
        foreach ($array as $key => $value) {
            if (!$callback($value, $key)) {
                return false;
            }
        }

        return true;
    }
}

if (!function_exists('array_find')) {
    /**
     * 配列の要素の中からコールバック関数を満たす要素を探す
     * (PHP 8 >= 8.4.0)
     *
     * @see https://www.php.net/manual/ja/function.array-find.php
     * @param array $array
     * @param callable $callback
     * @return mixed
     */
    function array_find(array $array, callable $callback)
    {
        foreach ($array as $key => $value) {
            if ($callback($value, $key)) {
                return $value;
            }
        }

        return null;
    }
}

if (!function_exists('array_find_key')) {
    /**
     * 配列の要素の中からコールバック関数を満たす最初の要素のキーを返す
     * (PHP 8 >= 8.4.0)
     *
     * @see https://www.php.net/manual/ja/function.array-find-key.php
     * @param array $array
     * @param callable $callback
     * @return mixed
     */
    function array_find_key(array $array, callable $callback)
    {
        foreach ($array as $key => $value) {
            if ($callback($value, $key)) {
                return $key;
            }
        }

        return null;
    }
}

// polyfill for PHP < 8.3
if (!function_exists('json_validate')) {
    /**
     * Polyfill of PHP 8.3 json_validate()
     * Signature: json_validate(string $json, int $depth = 512, int $flags = 0): bool
     */
    function json_validate(string $json, int $depth = 512, int $flags = 0): bool
    {
        // json_decode の depth は 1 以上が必須（PHPStan対策）
        $depth = max(1, $depth);
        // 本家 json_validate は例外を投げない（JSON_THROW_ON_ERROR が来ても false で返す）
        if (defined('JSON_THROW_ON_ERROR')) {
            $flags &= ~JSON_THROW_ON_ERROR;
        }
        // パースだけさせる（結果は捨てる）
        json_decode($json, false, $depth, $flags);

        return json_last_error() === JSON_ERROR_NONE;
    }
}
