├── LICENSE ├── Php83.php ├── README.md ├── Resources └── stubs │ ├── DateError.php │ ├── DateException.php │ ├── DateInvalidOperationException.php │ ├── DateInvalidTimeZoneException.php │ ├── DateMalformedIntervalStringException.php │ ├── DateMalformedPeriodStringException.php │ ├── DateMalformedStringException.php │ ├── DateObjectError.php │ ├── DateRangeError.php │ ├── Override.php │ └── SQLite3Exception.php ├── bootstrap.php ├── bootstrap81.php └── composer.json /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022-present Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Php83.php: -------------------------------------------------------------------------------- 1 | 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\Php83; 13 | 14 | /** 15 | * @author Ion Bazan 16 | * @author Pierre Ambroise 17 | * 18 | * @internal 19 | */ 20 | final class Php83 21 | { 22 | private const JSON_MAX_DEPTH = 0x7FFFFFFF; // see https://www.php.net/manual/en/function.json-decode.php 23 | 24 | public static function json_validate(string $json, int $depth = 512, int $flags = 0): bool 25 | { 26 | if (0 !== $flags && \defined('JSON_INVALID_UTF8_IGNORE') && \JSON_INVALID_UTF8_IGNORE !== $flags) { 27 | throw new \ValueError('json_validate(): Argument #3 ($flags) must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)'); 28 | } 29 | 30 | if ($depth <= 0) { 31 | throw new \ValueError('json_validate(): Argument #2 ($depth) must be greater than 0'); 32 | } 33 | 34 | if ($depth > self::JSON_MAX_DEPTH) { 35 | throw new \ValueError(sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH)); 36 | } 37 | 38 | json_decode($json, null, $depth, $flags); 39 | 40 | return \JSON_ERROR_NONE === json_last_error(); 41 | } 42 | 43 | public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string 44 | { 45 | if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { 46 | throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); 47 | } 48 | 49 | if (null === $encoding) { 50 | $encoding = mb_internal_encoding(); 51 | } 52 | 53 | try { 54 | $validEncoding = @mb_check_encoding('', $encoding); 55 | } catch (\ValueError $e) { 56 | throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); 57 | } 58 | 59 | // BC for PHP 7.3 and lower 60 | if (!$validEncoding) { 61 | throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); 62 | } 63 | 64 | if (mb_strlen($pad_string, $encoding) <= 0) { 65 | throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); 66 | } 67 | 68 | $paddingRequired = $length - mb_strlen($string, $encoding); 69 | 70 | if ($paddingRequired < 1) { 71 | return $string; 72 | } 73 | 74 | switch ($pad_type) { 75 | case \STR_PAD_LEFT: 76 | return mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; 77 | case \STR_PAD_RIGHT: 78 | return $string.mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); 79 | default: 80 | $leftPaddingLength = floor($paddingRequired / 2); 81 | $rightPaddingLength = $paddingRequired - $leftPaddingLength; 82 | 83 | return mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); 84 | } 85 | } 86 | 87 | public static function str_increment(string $string): string 88 | { 89 | if ('' === $string) { 90 | throw new \ValueError('str_increment(): Argument #1 ($string) cannot be empty'); 91 | } 92 | 93 | if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) { 94 | throw new \ValueError('str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters'); 95 | } 96 | 97 | if (is_numeric($string)) { 98 | $offset = stripos($string, 'e'); 99 | if (false !== $offset) { 100 | $char = $string[$offset]; 101 | ++$char; 102 | $string[$offset] = $char; 103 | ++$string; 104 | 105 | switch ($string[$offset]) { 106 | case 'f': 107 | $string[$offset] = 'e'; 108 | break; 109 | case 'F': 110 | $string[$offset] = 'E'; 111 | break; 112 | case 'g': 113 | $string[$offset] = 'f'; 114 | break; 115 | case 'G': 116 | $string[$offset] = 'F'; 117 | break; 118 | } 119 | 120 | return $string; 121 | } 122 | } 123 | 124 | return ++$string; 125 | } 126 | 127 | public static function str_decrement(string $string): string 128 | { 129 | if ('' === $string) { 130 | throw new \ValueError('str_decrement(): Argument #1 ($string) cannot be empty'); 131 | } 132 | 133 | if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) { 134 | throw new \ValueError('str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters'); 135 | } 136 | 137 | if (preg_match('/\A(?:0[aA0]?|[aA])\z/', $string)) { 138 | throw new \ValueError(sprintf('str_decrement(): Argument #1 ($string) "%s" is out of decrement range', $string)); 139 | } 140 | 141 | if (!\in_array(substr($string, -1), ['A', 'a', '0'], true)) { 142 | return implode('', \array_slice(str_split($string), 0, -1)).\chr(\ord(substr($string, -1)) - 1); 143 | } 144 | 145 | $carry = ''; 146 | $decremented = ''; 147 | 148 | for ($i = \strlen($string) - 1; $i >= 0; --$i) { 149 | $char = $string[$i]; 150 | 151 | switch ($char) { 152 | case 'A': 153 | if ('' !== $carry) { 154 | $decremented = $carry.$decremented; 155 | $carry = ''; 156 | } 157 | $carry = 'Z'; 158 | 159 | break; 160 | case 'a': 161 | if ('' !== $carry) { 162 | $decremented = $carry.$decremented; 163 | $carry = ''; 164 | } 165 | $carry = 'z'; 166 | 167 | break; 168 | case '0': 169 | if ('' !== $carry) { 170 | $decremented = $carry.$decremented; 171 | $carry = ''; 172 | } 173 | $carry = '9'; 174 | 175 | break; 176 | case '1': 177 | if ('' !== $carry) { 178 | $decremented = $carry.$decremented; 179 | $carry = ''; 180 | } 181 | 182 | break; 183 | default: 184 | if ('' !== $carry) { 185 | $decremented = $carry.$decremented; 186 | $carry = ''; 187 | } 188 | 189 | if (!\in_array($char, ['A', 'a', '0'], true)) { 190 | $decremented = \chr(\ord($char) - 1).$decremented; 191 | } 192 | } 193 | } 194 | 195 | return $decremented; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Symfony Polyfill / Php83 2 | ======================== 3 | 4 | This component provides features added to PHP 8.3 core: 5 | 6 | - [`json_validate`](https://wiki.php.net/rfc/json_validate) 7 | - [`Override`](https://wiki.php.net/rfc/marking_overriden_methods) 8 | - [`mb_str_pad`](https://wiki.php.net/rfc/mb_str_pad) 9 | - [`ldap_exop_sync`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures) 10 | - [`ldap_connect_wallet`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures) 11 | - [`stream_context_set_options`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures) 12 | - [`str_increment` and `str_decrement`](https://wiki.php.net/rfc/saner-inc-dec-operators) 13 | - [`Date*Exception/Error classes`](https://wiki.php.net/rfc/datetime-exceptions) 14 | - [`SQLite3Exception`](https://wiki.php.net/rfc/sqlite3_exceptions) 15 | 16 | More information can be found in the 17 | [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). 18 | 19 | License 20 | ======= 21 | 22 | This library is released under the [MIT license](LICENSE). 23 | -------------------------------------------------------------------------------- /Resources/stubs/DateError.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateError extends Error 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateException extends Exception 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateInvalidOperationException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateInvalidOperationException extends DateException 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateInvalidTimeZoneException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateInvalidTimeZoneException extends DateException 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateMalformedIntervalStringException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateMalformedIntervalStringException extends DateException 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateMalformedPeriodStringException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateMalformedPeriodStringException extends DateException 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateMalformedStringException.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateMalformedStringException extends DateException 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateObjectError.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateObjectError extends DateError 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/DateRangeError.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class DateRangeError extends DateError 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Resources/stubs/Override.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | #[Attribute(Attribute::TARGET_METHOD)] 14 | final class Override 15 | { 16 | public function __construct() 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Resources/stubs/SQLite3Exception.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID < 80300) { 13 | class SQLite3Exception extends Exception 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bootstrap.php: -------------------------------------------------------------------------------- 1 | 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 | use Symfony\Polyfill\Php83 as p; 13 | 14 | if (\PHP_VERSION_ID >= 80300) { 15 | return; 16 | } 17 | 18 | if (!function_exists('json_validate')) { 19 | function json_validate(string $json, int $depth = 512, int $flags = 0): bool { return p\Php83::json_validate($json, $depth, $flags); } 20 | } 21 | 22 | if (extension_loaded('mbstring')) { 23 | if (!function_exists('mb_str_pad')) { 24 | function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } 25 | } 26 | } 27 | 28 | if (!function_exists('stream_context_set_options')) { 29 | function stream_context_set_options($context, array $options): bool { return stream_context_set_option($context, $options); } 30 | } 31 | 32 | if (!function_exists('str_increment')) { 33 | function str_increment(string $string): string { return p\Php83::str_increment($string); } 34 | } 35 | 36 | if (!function_exists('str_decrement')) { 37 | function str_decrement(string $string): string { return p\Php83::str_decrement($string); } 38 | } 39 | 40 | if (\PHP_VERSION_ID >= 80100) { 41 | return require __DIR__.'/bootstrap81.php'; 42 | } 43 | 44 | if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) { 45 | function ldap_exop_sync($ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); } 46 | } 47 | 48 | if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) { 49 | function ldap_connect_wallet(?string $uri, string $wallet, string $password, int $auth_mode = \GSLC_SSL_NO_AUTH) { return ldap_connect($uri, $wallet, $password, $auth_mode); } 50 | } 51 | -------------------------------------------------------------------------------- /bootstrap81.php: -------------------------------------------------------------------------------- 1 | 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 | if (\PHP_VERSION_ID >= 80300) { 13 | return; 14 | } 15 | 16 | if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) { 17 | function ldap_exop_sync(\LDAP\Connection $ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); } 18 | } 19 | 20 | if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) { 21 | function ldap_connect_wallet(?string $uri, string $wallet, #[\SensitiveParameter] string $password, int $auth_mode = \GSLC_SSL_NO_AUTH): \LDAP\Connection|false { return ldap_connect($uri, $wallet, $password, $auth_mode); } 22 | } 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/polyfill-php83", 3 | "type": "library", 4 | "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", 5 | "keywords": ["polyfill", "shim", "compatibility", "portable"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Nicolas Grekas", 11 | "email": "p@tchwork.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=7.2" 20 | }, 21 | "autoload": { 22 | "psr-4": { "Symfony\\Polyfill\\Php83\\": "" }, 23 | "files": [ "bootstrap.php" ], 24 | "classmap": [ "Resources/stubs" ] 25 | }, 26 | "minimum-stability": "dev", 27 | "extra": { 28 | "thanks": { 29 | "name": "symfony/polyfill", 30 | "url": "https://github.com/symfony/polyfill" 31 | } 32 | } 33 | } 34 | --------------------------------------------------------------------------------