Php72.php
218 lines
| 1 | <?php |
| 2 | |
| 3 | /* |
| 4 | * This file is part of the Symfony package. |
| 5 | * |
| 6 | * (c) Fabien Potencier <fabien@symfony.com> |
| 7 | * |
| 8 | * For the full copyright and license information, please view the LICENSE |
| 9 | * file that was distributed with this source code. |
| 10 | */ |
| 11 | |
| 12 | namespace Symfony\Polyfill\Php72; |
| 13 | |
| 14 | /** |
| 15 | * @author Nicolas Grekas <p@tchwork.com> |
| 16 | * @author Dariusz Rumiński <dariusz.ruminski@gmail.com> |
| 17 | * |
| 18 | * @internal |
| 19 | */ |
| 20 | final class Php72 |
| 21 | { |
| 22 | private static $hashMask; |
| 23 | |
| 24 | public static function utf8_encode($s) |
| 25 | { |
| 26 | $s .= $s; |
| 27 | $len = \strlen($s); |
| 28 | |
| 29 | for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { |
| 30 | switch (true) { |
| 31 | case $s[$i] < "\x80": $s[$j] = $s[$i]; break; |
| 32 | case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; |
| 33 | default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | return substr($s, 0, $j); |
| 38 | } |
| 39 | |
| 40 | public static function utf8_decode($s) |
| 41 | { |
| 42 | $s = (string) $s; |
| 43 | $len = \strlen($s); |
| 44 | |
| 45 | for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { |
| 46 | switch ($s[$i] & "\xF0") { |
| 47 | case "\xC0": |
| 48 | case "\xD0": |
| 49 | $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); |
| 50 | $s[$j] = $c < 256 ? \chr($c) : '?'; |
| 51 | break; |
| 52 | |
| 53 | case "\xF0": |
| 54 | ++$i; |
| 55 | // no break |
| 56 | |
| 57 | case "\xE0": |
| 58 | $s[$j] = '?'; |
| 59 | $i += 2; |
| 60 | break; |
| 61 | |
| 62 | default: |
| 63 | $s[$j] = $s[$i]; |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | return substr($s, 0, $j); |
| 68 | } |
| 69 | |
| 70 | public static function php_os_family() |
| 71 | { |
| 72 | if ('\\' === \DIRECTORY_SEPARATOR) { |
| 73 | return 'Windows'; |
| 74 | } |
| 75 | |
| 76 | $map = array( |
| 77 | 'Darwin' => 'Darwin', |
| 78 | 'DragonFly' => 'BSD', |
| 79 | 'FreeBSD' => 'BSD', |
| 80 | 'NetBSD' => 'BSD', |
| 81 | 'OpenBSD' => 'BSD', |
| 82 | 'Linux' => 'Linux', |
| 83 | 'SunOS' => 'Solaris', |
| 84 | ); |
| 85 | |
| 86 | return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown'; |
| 87 | } |
| 88 | |
| 89 | public static function spl_object_id($object) |
| 90 | { |
| 91 | if (null === self::$hashMask) { |
| 92 | self::initHashMask(); |
| 93 | } |
| 94 | if (null === $hash = spl_object_hash($object)) { |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | // On 32-bit systems, PHP_INT_SIZE is 4, |
| 99 | return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); |
| 100 | } |
| 101 | |
| 102 | public static function sapi_windows_vt100_support($stream, $enable = null) |
| 103 | { |
| 104 | if (!\is_resource($stream)) { |
| 105 | trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); |
| 106 | |
| 107 | return false; |
| 108 | } |
| 109 | |
| 110 | $meta = stream_get_meta_data($stream); |
| 111 | |
| 112 | if ('STDIO' !== $meta['stream_type']) { |
| 113 | trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', E_USER_WARNING); |
| 114 | |
| 115 | return false; |
| 116 | } |
| 117 | |
| 118 | // We cannot actually disable vt100 support if it is set |
| 119 | if (false === $enable || !self::stream_isatty($stream)) { |
| 120 | return false; |
| 121 | } |
| 122 | |
| 123 | // The native function does not apply to stdin |
| 124 | $meta = array_map('strtolower', $meta); |
| 125 | $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; |
| 126 | |
| 127 | return !$stdin |
| 128 | && (false !== getenv('ANSICON') |
| 129 | || 'ON' === getenv('ConEmuANSI') |
| 130 | || 'xterm' === getenv('TERM') |
| 131 | || 'Hyper' === getenv('TERM_PROGRAM')); |
| 132 | } |
| 133 | |
| 134 | public static function stream_isatty($stream) |
| 135 | { |
| 136 | if (!\is_resource($stream)) { |
| 137 | trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); |
| 138 | |
| 139 | return false; |
| 140 | } |
| 141 | |
| 142 | if ('\\' === \DIRECTORY_SEPARATOR) { |
| 143 | $stat = @fstat($stream); |
| 144 | // Check if formatted mode is S_IFCHR |
| 145 | return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; |
| 146 | } |
| 147 | |
| 148 | return \function_exists('posix_isatty') && @posix_isatty($stream); |
| 149 | } |
| 150 | |
| 151 | private static function initHashMask() |
| 152 | { |
| 153 | $obj = (object) array(); |
| 154 | self::$hashMask = -1; |
| 155 | |
| 156 | // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below |
| 157 | $obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'); |
| 158 | foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { |
| 159 | if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { |
| 160 | $frame['line'] = 0; |
| 161 | break; |
| 162 | } |
| 163 | } |
| 164 | if (!empty($frame['line'])) { |
| 165 | ob_start(); |
| 166 | debug_zval_dump($obj); |
| 167 | self::$hashMask = (int) substr(ob_get_clean(), 17); |
| 168 | } |
| 169 | |
| 170 | self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); |
| 171 | } |
| 172 | |
| 173 | public static function mb_chr($code, $encoding = null) |
| 174 | { |
| 175 | if (0x80 > $code %= 0x200000) { |
| 176 | $s = \chr($code); |
| 177 | } elseif (0x800 > $code) { |
| 178 | $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); |
| 179 | } elseif (0x10000 > $code) { |
| 180 | $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
| 181 | } else { |
| 182 | $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
| 183 | } |
| 184 | |
| 185 | if ('UTF-8' !== $encoding) { |
| 186 | $s = mb_convert_encoding($s, $encoding, 'UTF-8'); |
| 187 | } |
| 188 | |
| 189 | return $s; |
| 190 | } |
| 191 | |
| 192 | public static function mb_ord($s, $encoding = null) |
| 193 | { |
| 194 | if (null == $encoding) { |
| 195 | $s = mb_convert_encoding($s, 'UTF-8'); |
| 196 | } elseif ('UTF-8' !== $encoding) { |
| 197 | $s = mb_convert_encoding($s, 'UTF-8', $encoding); |
| 198 | } |
| 199 | |
| 200 | if (1 === \strlen($s)) { |
| 201 | return \ord($s); |
| 202 | } |
| 203 | |
| 204 | $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; |
| 205 | if (0xF0 <= $code) { |
| 206 | return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; |
| 207 | } |
| 208 | if (0xE0 <= $code) { |
| 209 | return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; |
| 210 | } |
| 211 | if (0xC0 <= $code) { |
| 212 | return (($code - 0xC0) << 6) + $s[2] - 0x80; |
| 213 | } |
| 214 | |
| 215 | return $code; |
| 216 | } |
| 217 | } |
| 218 |