取消https验证,并添加vendor文件夹。

This commit is contained in:
2025-04-18 12:58:39 +08:00
parent 552909d82b
commit 2d3f7d8511
727 changed files with 132015 additions and 19 deletions

925
vendor/symfony/polyfill-intl-idn/Idn.php vendored Normal file
View File

@@ -0,0 +1,925 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Intl\Idn;
use Exception;
use Normalizer;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex;
/**
* @see https://www.unicode.org/reports/tr46/
*
* @internal
*/
final class Idn
{
public const ERROR_EMPTY_LABEL = 1;
public const ERROR_LABEL_TOO_LONG = 2;
public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
public const ERROR_LEADING_HYPHEN = 8;
public const ERROR_TRAILING_HYPHEN = 0x10;
public const ERROR_HYPHEN_3_4 = 0x20;
public const ERROR_LEADING_COMBINING_MARK = 0x40;
public const ERROR_DISALLOWED = 0x80;
public const ERROR_PUNYCODE = 0x100;
public const ERROR_LABEL_HAS_DOT = 0x200;
public const ERROR_INVALID_ACE_LABEL = 0x400;
public const ERROR_BIDI = 0x800;
public const ERROR_CONTEXTJ = 0x1000;
public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
public const ERROR_CONTEXTO_DIGITS = 0x4000;
public const INTL_IDNA_VARIANT_2003 = 0;
public const INTL_IDNA_VARIANT_UTS46 = 1;
public const IDNA_DEFAULT = 0;
public const IDNA_ALLOW_UNASSIGNED = 1;
public const IDNA_USE_STD3_RULES = 2;
public const IDNA_CHECK_BIDI = 4;
public const IDNA_CHECK_CONTEXTJ = 8;
public const IDNA_NONTRANSITIONAL_TO_ASCII = 16;
public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;
public const MAX_DOMAIN_SIZE = 253;
public const MAX_LABEL_SIZE = 63;
public const BASE = 36;
public const TMIN = 1;
public const TMAX = 26;
public const SKEW = 38;
public const DAMP = 700;
public const INITIAL_BIAS = 72;
public const INITIAL_N = 128;
public const DELIMITER = '-';
public const MAX_INT = 2147483647;
/**
* Contains the numeric value of a basic code point (for use in representing integers) in the
* range 0 to BASE-1, or -1 if b is does not represent a value.
*
* @var array<int, int>
*/
private static $basicToDigit = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
];
/**
* @var array<int, int>
*/
private static $virama;
/**
* @var array<int, string>
*/
private static $mapped;
/**
* @var array<int, bool>
*/
private static $ignored;
/**
* @var array<int, string>
*/
private static $deviation;
/**
* @var array<int, bool>
*/
private static $disallowed;
/**
* @var array<int, string>
*/
private static $disallowed_STD3_mapped;
/**
* @var array<int, bool>
*/
private static $disallowed_STD3_valid;
/**
* @var bool
*/
private static $mappingTableLoaded = false;
/**
* @see https://www.unicode.org/reports/tr46/#ToASCII
*
* @param string $domainName
* @param int $options
* @param int $variant
* @param array $idna_info
*
* @return string|false
*/
public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}
$options = [
'CheckHyphens' => true,
'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII),
'VerifyDnsLength' => true,
];
$info = new Info();
$labels = self::process((string) $domainName, $options, $info);
foreach ($labels as $i => $label) {
// Only convert labels to punycode that contain non-ASCII code points
if (1 === preg_match('/[^\x00-\x7F]/', $label)) {
try {
$label = 'xn--'.self::punycodeEncode($label);
} catch (Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;
}
$labels[$i] = $label;
}
}
if ($options['VerifyDnsLength']) {
self::validateDomainAndLabelLength($labels, $info);
}
$idna_info = [
'result' => implode('.', $labels),
'isTransitionalDifferent' => $info->transitionalDifferent,
'errors' => $info->errors,
];
return 0 === $info->errors ? $idna_info['result'] : false;
}
/**
* @see https://www.unicode.org/reports/tr46/#ToUnicode
*
* @param string $domainName
* @param int $options
* @param int $variant
* @param array $idna_info
*
* @return string|false
*/
public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}
$info = new Info();
$labels = self::process((string) $domainName, [
'CheckHyphens' => true,
'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE),
], $info);
$idna_info = [
'result' => implode('.', $labels),
'isTransitionalDifferent' => $info->transitionalDifferent,
'errors' => $info->errors,
];
return 0 === $info->errors ? $idna_info['result'] : false;
}
/**
* @param string $label
*
* @return bool
*/
private static function isValidContextJ(array $codePoints, $label)
{
if (!isset(self::$virama)) {
self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php';
}
$offset = 0;
foreach ($codePoints as $i => $codePoint) {
if (0x200C !== $codePoint && 0x200D !== $codePoint) {
continue;
}
if (!isset($codePoints[$i - 1])) {
return false;
}
// If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True;
if (isset(self::$virama[$codePoints[$i - 1]])) {
continue;
}
// If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then
// True;
// Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\u200C[Joining_Type:T]*)[Joining_Type:{R,D}]
if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \PREG_OFFSET_CAPTURE, $offset)) {
$offset += \strlen($matches[1][0]);
continue;
}
return false;
}
return true;
}
/**
* @see https://www.unicode.org/reports/tr46/#ProcessingStepMap
*
* @param string $input
* @param array<string, bool> $options
*
* @return string
*/
private static function mapCodePoints($input, array $options, Info $info)
{
$str = '';
$useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
$transitional = $options['Transitional_Processing'];
foreach (self::utf8Decode($input) as $codePoint) {
$data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
switch ($data['status']) {
case 'disallowed':
$info->errors |= self::ERROR_DISALLOWED;
// no break.
case 'valid':
$str .= mb_chr($codePoint, 'utf-8');
break;
case 'ignored':
// Do nothing.
break;
case 'mapped':
$str .= $data['mapping'];
break;
case 'deviation':
$info->transitionalDifferent = true;
$str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8'));
break;
}
}
return $str;
}
/**
* @see https://www.unicode.org/reports/tr46/#Processing
*
* @param string $domain
* @param array<string, bool> $options
*
* @return array<int, string>
*/
private static function process($domain, array $options, Info $info)
{
// If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and
// we need to respect the VerifyDnsLength option.
$checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'];
if ($checkForEmptyLabels && '' === $domain) {
$info->errors |= self::ERROR_EMPTY_LABEL;
return [$domain];
}
// Step 1. Map each code point in the domain name string
$domain = self::mapCodePoints($domain, $options, $info);
// Step 2. Normalize the domain name string to Unicode Normalization Form C.
if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) {
$domain = Normalizer::normalize($domain, Normalizer::FORM_C);
}
// Step 3. Break the string into labels at U+002E (.) FULL STOP.
$labels = explode('.', $domain);
$lastLabelIndex = \count($labels) - 1;
// Step 4. Convert and validate each label in the domain name string.
foreach ($labels as $i => $label) {
$validationOptions = $options;
if ('xn--' === substr($label, 0, 4)) {
try {
$label = self::punycodeDecode(substr($label, 4));
} catch (Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;
continue;
}
$validationOptions['Transitional_Processing'] = false;
$labels[$i] = $label;
}
self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex);
}
if ($info->bidiDomain && !$info->validBidiDomain) {
$info->errors |= self::ERROR_BIDI;
}
// Any input domain name string that does not record an error has been successfully
// processed according to this specification. Conversely, if an input domain_name string
// causes an error, then the processing of the input domain_name string fails. Determining
// what to do with error input is up to the caller, and not in the scope of this document.
return $labels;
}
/**
* @see https://tools.ietf.org/html/rfc5893#section-2
*
* @param string $label
*/
private static function validateBidiLabel($label, Info $info)
{
if (1 === preg_match(Regex::RTL_LABEL, $label)) {
$info->bidiDomain = true;
// Step 1. The first character must be a character with Bidi property L, R, or AL.
// If it has the R or AL property, it is an RTL label
if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) {
$info->validBidiDomain = false;
return;
}
// Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES,
// CS, ET, ON, BN, or NSM are allowed.
if (1 === preg_match(Regex::BIDI_STEP_2, $label)) {
$info->validBidiDomain = false;
return;
}
// Step 3. In an RTL label, the end of the label must be a character with Bidi property
// R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM.
if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) {
$info->validBidiDomain = false;
return;
}
// Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa.
if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) {
$info->validBidiDomain = false;
return;
}
return;
}
// We are a LTR label
// Step 1. The first character must be a character with Bidi property L, R, or AL.
// If it has the L property, it is an LTR label.
if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) {
$info->validBidiDomain = false;
return;
}
// Step 5. In an LTR label, only characters with the Bidi properties L, EN,
// ES, CS, ET, ON, BN, or NSM are allowed.
if (1 === preg_match(Regex::BIDI_STEP_5, $label)) {
$info->validBidiDomain = false;
return;
}
// Step 6.In an LTR label, the end of the label must be a character with Bidi property L or
// EN, followed by zero or more characters with Bidi property NSM.
if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) {
$info->validBidiDomain = false;
return;
}
}
/**
* @param array<int, string> $labels
*/
private static function validateDomainAndLabelLength(array $labels, Info $info)
{
$maxDomainSize = self::MAX_DOMAIN_SIZE;
$length = \count($labels);
// Number of "." delimiters.
$domainLength = $length - 1;
// If the last label is empty and it is not the first label, then it is the root label.
// Increase the max size by 1, making it 254, to account for the root label's "."
// delimiter. This also means we don't need to check the last label's length for being too
// long.
if ($length > 1 && '' === $labels[$length - 1]) {
++$maxDomainSize;
--$length;
}
for ($i = 0; $i < $length; ++$i) {
$bytes = \strlen($labels[$i]);
$domainLength += $bytes;
if ($bytes > self::MAX_LABEL_SIZE) {
$info->errors |= self::ERROR_LABEL_TOO_LONG;
}
}
if ($domainLength > $maxDomainSize) {
$info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG;
}
}
/**
* @see https://www.unicode.org/reports/tr46/#Validity_Criteria
*
* @param string $label
* @param array<string, bool> $options
* @param bool $canBeEmpty
*/
private static function validateLabel($label, Info $info, array $options, $canBeEmpty)
{
if ('' === $label) {
if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) {
$info->errors |= self::ERROR_EMPTY_LABEL;
}
return;
}
// Step 1. The label must be in Unicode Normalization Form C.
if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) {
$info->errors |= self::ERROR_INVALID_ACE_LABEL;
}
$codePoints = self::utf8Decode($label);
if ($options['CheckHyphens']) {
// Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
// in both the thrid and fourth positions.
if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) {
$info->errors |= self::ERROR_HYPHEN_3_4;
}
// Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D
// HYPHEN-MINUS character.
if ('-' === substr($label, 0, 1)) {
$info->errors |= self::ERROR_LEADING_HYPHEN;
}
if ('-' === substr($label, -1, 1)) {
$info->errors |= self::ERROR_TRAILING_HYPHEN;
}
}
// Step 4. The label must not contain a U+002E (.) FULL STOP.
if (false !== strpos($label, '.')) {
$info->errors |= self::ERROR_LABEL_HAS_DOT;
}
// Step 5. The label must not begin with a combining mark, that is: General_Category=Mark.
if (1 === preg_match(Regex::COMBINING_MARK, $label)) {
$info->errors |= self::ERROR_LEADING_COMBINING_MARK;
}
// Step 6. Each code point in the label must only have certain status values according to
// Section 5, IDNA Mapping Table:
$transitional = $options['Transitional_Processing'];
$useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
foreach ($codePoints as $codePoint) {
$data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
$status = $data['status'];
if ('valid' === $status || (!$transitional && 'deviation' === $status)) {
continue;
}
$info->errors |= self::ERROR_DISALLOWED;
break;
}
// Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in
// The Unicode Code Points and Internationalized Domain Names for Applications (IDNA)
// [IDNA2008].
if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) {
$info->errors |= self::ERROR_CONTEXTJ;
}
// Step 8. If CheckBidi, and if the domain name is a Bidi domain name, then the label must
// satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2.
if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) {
self::validateBidiLabel($label, $info);
}
}
/**
* @see https://tools.ietf.org/html/rfc3492#section-6.2
*
* @param string $input
*
* @return string
*/
private static function punycodeDecode($input)
{
$n = self::INITIAL_N;
$out = 0;
$i = 0;
$bias = self::INITIAL_BIAS;
$lastDelimIndex = strrpos($input, self::DELIMITER);
$b = false === $lastDelimIndex ? 0 : $lastDelimIndex;
$inputLength = \strlen($input);
$output = [];
$bytes = array_map('ord', str_split($input));
for ($j = 0; $j < $b; ++$j) {
if ($bytes[$j] > 0x7F) {
throw new Exception('Invalid input');
}
$output[$out++] = $input[$j];
}
if ($b > 0) {
++$b;
}
for ($in = $b; $in < $inputLength; ++$out) {
$oldi = $i;
$w = 1;
for ($k = self::BASE; /* no condition */; $k += self::BASE) {
if ($in >= $inputLength) {
throw new Exception('Invalid input');
}
$digit = self::$basicToDigit[$bytes[$in++] & 0xFF];
if ($digit < 0) {
throw new Exception('Invalid input');
}
if ($digit > intdiv(self::MAX_INT - $i, $w)) {
throw new Exception('Integer overflow');
}
$i += $digit * $w;
if ($k <= $bias) {
$t = self::TMIN;
} elseif ($k >= $bias + self::TMAX) {
$t = self::TMAX;
} else {
$t = $k - $bias;
}
if ($digit < $t) {
break;
}
$baseMinusT = self::BASE - $t;
if ($w > intdiv(self::MAX_INT, $baseMinusT)) {
throw new Exception('Integer overflow');
}
$w *= $baseMinusT;
}
$outPlusOne = $out + 1;
$bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);
if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {
throw new Exception('Integer overflow');
}
$n += intdiv($i, $outPlusOne);
$i %= $outPlusOne;
array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]);
}
return implode('', $output);
}
/**
* @see https://tools.ietf.org/html/rfc3492#section-6.3
*
* @param string $input
*
* @return string
*/
private static function punycodeEncode($input)
{
$n = self::INITIAL_N;
$delta = 0;
$out = 0;
$bias = self::INITIAL_BIAS;
$inputLength = 0;
$output = '';
$iter = self::utf8Decode($input);
foreach ($iter as $codePoint) {
++$inputLength;
if ($codePoint < 0x80) {
$output .= \chr($codePoint);
++$out;
}
}
$h = $out;
$b = $out;
if ($b > 0) {
$output .= self::DELIMITER;
++$out;
}
while ($h < $inputLength) {
$m = self::MAX_INT;
foreach ($iter as $codePoint) {
if ($codePoint >= $n && $codePoint < $m) {
$m = $codePoint;
}
}
if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {
throw new Exception('Integer overflow');
}
$delta += ($m - $n) * ($h + 1);
$n = $m;
foreach ($iter as $codePoint) {
if ($codePoint < $n && 0 === ++$delta) {
throw new Exception('Integer overflow');
}
if ($codePoint === $n) {
$q = $delta;
for ($k = self::BASE; /* no condition */; $k += self::BASE) {
if ($k <= $bias) {
$t = self::TMIN;
} elseif ($k >= $bias + self::TMAX) {
$t = self::TMAX;
} else {
$t = $k - $bias;
}
if ($q < $t) {
break;
}
$qMinusT = $q - $t;
$baseMinusT = self::BASE - $t;
$output .= self::encodeDigit($t + $qMinusT % $baseMinusT, false);
++$out;
$q = intdiv($qMinusT, $baseMinusT);
}
$output .= self::encodeDigit($q, false);
++$out;
$bias = self::adaptBias($delta, $h + 1, $h === $b);
$delta = 0;
++$h;
}
}
++$delta;
++$n;
}
return $output;
}
/**
* @see https://tools.ietf.org/html/rfc3492#section-6.1
*
* @param int $delta
* @param int $numPoints
* @param bool $firstTime
*
* @return int
*/
private static function adaptBias($delta, $numPoints, $firstTime)
{
// xxx >> 1 is a faster way of doing intdiv(xxx, 2)
$delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1;
$delta += intdiv($delta, $numPoints);
$k = 0;
while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) {
$delta = intdiv($delta, self::BASE - self::TMIN);
$k += self::BASE;
}
return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW);
}
/**
* @param int $d
* @param bool $flag
*
* @return string
*/
private static function encodeDigit($d, $flag)
{
return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5));
}
/**
* Takes a UTF-8 encoded string and converts it into a series of integer code points. Any
* invalid byte sequences will be replaced by a U+FFFD replacement code point.
*
* @see https://encoding.spec.whatwg.org/#utf-8-decoder
*
* @param string $input
*
* @return array<int, int>
*/
private static function utf8Decode($input)
{
$bytesSeen = 0;
$bytesNeeded = 0;
$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
$codePoint = 0;
$codePoints = [];
$length = \strlen($input);
for ($i = 0; $i < $length; ++$i) {
$byte = \ord($input[$i]);
if (0 === $bytesNeeded) {
if ($byte >= 0x00 && $byte <= 0x7F) {
$codePoints[] = $byte;
continue;
}
if ($byte >= 0xC2 && $byte <= 0xDF) {
$bytesNeeded = 1;
$codePoint = $byte & 0x1F;
} elseif ($byte >= 0xE0 && $byte <= 0xEF) {
if (0xE0 === $byte) {
$lowerBoundary = 0xA0;
} elseif (0xED === $byte) {
$upperBoundary = 0x9F;
}
$bytesNeeded = 2;
$codePoint = $byte & 0xF;
} elseif ($byte >= 0xF0 && $byte <= 0xF4) {
if (0xF0 === $byte) {
$lowerBoundary = 0x90;
} elseif (0xF4 === $byte) {
$upperBoundary = 0x8F;
}
$bytesNeeded = 3;
$codePoint = $byte & 0x7;
} else {
$codePoints[] = 0xFFFD;
}
continue;
}
if ($byte < $lowerBoundary || $byte > $upperBoundary) {
$codePoint = 0;
$bytesNeeded = 0;
$bytesSeen = 0;
$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
--$i;
$codePoints[] = 0xFFFD;
continue;
}
$lowerBoundary = 0x80;
$upperBoundary = 0xBF;
$codePoint = ($codePoint << 6) | ($byte & 0x3F);
if (++$bytesSeen !== $bytesNeeded) {
continue;
}
$codePoints[] = $codePoint;
$codePoint = 0;
$bytesNeeded = 0;
$bytesSeen = 0;
}
// String unexpectedly ended, so append a U+FFFD code point.
if (0 !== $bytesNeeded) {
$codePoints[] = 0xFFFD;
}
return $codePoints;
}
/**
* @param int $codePoint
* @param bool $useSTD3ASCIIRules
*
* @return array{status: string, mapping?: string}
*/
private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules)
{
if (!self::$mappingTableLoaded) {
self::$mappingTableLoaded = true;
self::$mapped = require __DIR__.'/Resources/unidata/mapped.php';
self::$ignored = require __DIR__.'/Resources/unidata/ignored.php';
self::$deviation = require __DIR__.'/Resources/unidata/deviation.php';
self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php';
self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php';
self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php';
}
if (isset(self::$mapped[$codePoint])) {
return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]];
}
if (isset(self::$ignored[$codePoint])) {
return ['status' => 'ignored'];
}
if (isset(self::$deviation[$codePoint])) {
return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]];
}
if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) {
return ['status' => 'disallowed'];
}
$isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]);
if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) {
$status = 'disallowed';
if (!$useSTD3ASCIIRules) {
$status = $isDisallowedMapped ? 'mapped' : 'valid';
}
if ($isDisallowedMapped) {
return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]];
}
return ['status' => $status];
}
return ['status' => 'valid'];
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Intl\Idn;
/**
* @internal
*/
class Info
{
public $bidiDomain = false;
public $errors = 0;
public $validBidiDomain = true;
public $transitionalDifferent = false;
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2018-2019 Fabien Potencier and Trevor Rowbotham <trevor.rowbotham@pm.me>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,12 @@
Symfony Polyfill / Intl: Idn
============================
This component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

View File

@@ -0,0 +1,375 @@
<?php
namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;
/**
* @internal
*/
final class DisallowedRanges
{
/**
* @param int $codePoint
*
* @return bool
*/
public static function inRange($codePoint)
{
if ($codePoint >= 128 && $codePoint <= 159) {
return true;
}
if ($codePoint >= 2155 && $codePoint <= 2207) {
return true;
}
if ($codePoint >= 3676 && $codePoint <= 3712) {
return true;
}
if ($codePoint >= 3808 && $codePoint <= 3839) {
return true;
}
if ($codePoint >= 4059 && $codePoint <= 4095) {
return true;
}
if ($codePoint >= 4256 && $codePoint <= 4293) {
return true;
}
if ($codePoint >= 6849 && $codePoint <= 6911) {
return true;
}
if ($codePoint >= 11859 && $codePoint <= 11903) {
return true;
}
if ($codePoint >= 42955 && $codePoint <= 42996) {
return true;
}
if ($codePoint >= 55296 && $codePoint <= 57343) {
return true;
}
if ($codePoint >= 57344 && $codePoint <= 63743) {
return true;
}
if ($codePoint >= 64218 && $codePoint <= 64255) {
return true;
}
if ($codePoint >= 64976 && $codePoint <= 65007) {
return true;
}
if ($codePoint >= 65630 && $codePoint <= 65663) {
return true;
}
if ($codePoint >= 65953 && $codePoint <= 65999) {
return true;
}
if ($codePoint >= 66046 && $codePoint <= 66175) {
return true;
}
if ($codePoint >= 66518 && $codePoint <= 66559) {
return true;
}
if ($codePoint >= 66928 && $codePoint <= 67071) {
return true;
}
if ($codePoint >= 67432 && $codePoint <= 67583) {
return true;
}
if ($codePoint >= 67760 && $codePoint <= 67807) {
return true;
}
if ($codePoint >= 67904 && $codePoint <= 67967) {
return true;
}
if ($codePoint >= 68256 && $codePoint <= 68287) {
return true;
}
if ($codePoint >= 68528 && $codePoint <= 68607) {
return true;
}
if ($codePoint >= 68681 && $codePoint <= 68735) {
return true;
}
if ($codePoint >= 68922 && $codePoint <= 69215) {
return true;
}
if ($codePoint >= 69298 && $codePoint <= 69375) {
return true;
}
if ($codePoint >= 69466 && $codePoint <= 69551) {
return true;
}
if ($codePoint >= 70207 && $codePoint <= 70271) {
return true;
}
if ($codePoint >= 70517 && $codePoint <= 70655) {
return true;
}
if ($codePoint >= 70874 && $codePoint <= 71039) {
return true;
}
if ($codePoint >= 71134 && $codePoint <= 71167) {
return true;
}
if ($codePoint >= 71370 && $codePoint <= 71423) {
return true;
}
if ($codePoint >= 71488 && $codePoint <= 71679) {
return true;
}
if ($codePoint >= 71740 && $codePoint <= 71839) {
return true;
}
if ($codePoint >= 72026 && $codePoint <= 72095) {
return true;
}
if ($codePoint >= 72441 && $codePoint <= 72703) {
return true;
}
if ($codePoint >= 72887 && $codePoint <= 72959) {
return true;
}
if ($codePoint >= 73130 && $codePoint <= 73439) {
return true;
}
if ($codePoint >= 73465 && $codePoint <= 73647) {
return true;
}
if ($codePoint >= 74650 && $codePoint <= 74751) {
return true;
}
if ($codePoint >= 75076 && $codePoint <= 77823) {
return true;
}
if ($codePoint >= 78905 && $codePoint <= 82943) {
return true;
}
if ($codePoint >= 83527 && $codePoint <= 92159) {
return true;
}
if ($codePoint >= 92784 && $codePoint <= 92879) {
return true;
}
if ($codePoint >= 93072 && $codePoint <= 93759) {
return true;
}
if ($codePoint >= 93851 && $codePoint <= 93951) {
return true;
}
if ($codePoint >= 94112 && $codePoint <= 94175) {
return true;
}
if ($codePoint >= 101590 && $codePoint <= 101631) {
return true;
}
if ($codePoint >= 101641 && $codePoint <= 110591) {
return true;
}
if ($codePoint >= 110879 && $codePoint <= 110927) {
return true;
}
if ($codePoint >= 111356 && $codePoint <= 113663) {
return true;
}
if ($codePoint >= 113828 && $codePoint <= 118783) {
return true;
}
if ($codePoint >= 119366 && $codePoint <= 119519) {
return true;
}
if ($codePoint >= 119673 && $codePoint <= 119807) {
return true;
}
if ($codePoint >= 121520 && $codePoint <= 122879) {
return true;
}
if ($codePoint >= 122923 && $codePoint <= 123135) {
return true;
}
if ($codePoint >= 123216 && $codePoint <= 123583) {
return true;
}
if ($codePoint >= 123648 && $codePoint <= 124927) {
return true;
}
if ($codePoint >= 125143 && $codePoint <= 125183) {
return true;
}
if ($codePoint >= 125280 && $codePoint <= 126064) {
return true;
}
if ($codePoint >= 126133 && $codePoint <= 126208) {
return true;
}
if ($codePoint >= 126270 && $codePoint <= 126463) {
return true;
}
if ($codePoint >= 126652 && $codePoint <= 126703) {
return true;
}
if ($codePoint >= 126706 && $codePoint <= 126975) {
return true;
}
if ($codePoint >= 127406 && $codePoint <= 127461) {
return true;
}
if ($codePoint >= 127590 && $codePoint <= 127743) {
return true;
}
if ($codePoint >= 129202 && $codePoint <= 129279) {
return true;
}
if ($codePoint >= 129751 && $codePoint <= 129791) {
return true;
}
if ($codePoint >= 129995 && $codePoint <= 130031) {
return true;
}
if ($codePoint >= 130042 && $codePoint <= 131069) {
return true;
}
if ($codePoint >= 173790 && $codePoint <= 173823) {
return true;
}
if ($codePoint >= 191457 && $codePoint <= 194559) {
return true;
}
if ($codePoint >= 195102 && $codePoint <= 196605) {
return true;
}
if ($codePoint >= 201547 && $codePoint <= 262141) {
return true;
}
if ($codePoint >= 262144 && $codePoint <= 327677) {
return true;
}
if ($codePoint >= 327680 && $codePoint <= 393213) {
return true;
}
if ($codePoint >= 393216 && $codePoint <= 458749) {
return true;
}
if ($codePoint >= 458752 && $codePoint <= 524285) {
return true;
}
if ($codePoint >= 524288 && $codePoint <= 589821) {
return true;
}
if ($codePoint >= 589824 && $codePoint <= 655357) {
return true;
}
if ($codePoint >= 655360 && $codePoint <= 720893) {
return true;
}
if ($codePoint >= 720896 && $codePoint <= 786429) {
return true;
}
if ($codePoint >= 786432 && $codePoint <= 851965) {
return true;
}
if ($codePoint >= 851968 && $codePoint <= 917501) {
return true;
}
if ($codePoint >= 917536 && $codePoint <= 917631) {
return true;
}
if ($codePoint >= 917632 && $codePoint <= 917759) {
return true;
}
if ($codePoint >= 918000 && $codePoint <= 983037) {
return true;
}
if ($codePoint >= 983040 && $codePoint <= 1048573) {
return true;
}
if ($codePoint >= 1048576 && $codePoint <= 1114109) {
return true;
}
return false;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
<?php
return array (
223 => 'ss',
962 => 'σ',
8204 => '',
8205 => '',
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
<?php
return array (
160 => ' ',
168 => ' ̈',
175 => ' ̄',
180 => ' ́',
184 => ' ̧',
728 => ' ̆',
729 => ' ̇',
730 => ' ̊',
731 => ' ̨',
732 => ' ̃',
733 => ' ̋',
890 => ' ι',
894 => ';',
900 => ' ́',
901 => ' ̈́',
8125 => ' ̓',
8127 => ' ̓',
8128 => ' ͂',
8129 => ' ̈͂',
8141 => ' ̓̀',
8142 => ' ̓́',
8143 => ' ̓͂',
8157 => ' ̔̀',
8158 => ' ̔́',
8159 => ' ̔͂',
8173 => ' ̈̀',
8174 => ' ̈́',
8175 => '`',
8189 => ' ́',
8190 => ' ̔',
8192 => ' ',
8193 => ' ',
8194 => ' ',
8195 => ' ',
8196 => ' ',
8197 => ' ',
8198 => ' ',
8199 => ' ',
8200 => ' ',
8201 => ' ',
8202 => ' ',
8215 => ' ̳',
8239 => ' ',
8252 => '!!',
8254 => ' ̅',
8263 => '??',
8264 => '?!',
8265 => '!?',
8287 => ' ',
8314 => '+',
8316 => '=',
8317 => '(',
8318 => ')',
8330 => '+',
8332 => '=',
8333 => '(',
8334 => ')',
8448 => 'a/c',
8449 => 'a/s',
8453 => 'c/o',
8454 => 'c/u',
9332 => '(1)',
9333 => '(2)',
9334 => '(3)',
9335 => '(4)',
9336 => '(5)',
9337 => '(6)',
9338 => '(7)',
9339 => '(8)',
9340 => '(9)',
9341 => '(10)',
9342 => '(11)',
9343 => '(12)',
9344 => '(13)',
9345 => '(14)',
9346 => '(15)',
9347 => '(16)',
9348 => '(17)',
9349 => '(18)',
9350 => '(19)',
9351 => '(20)',
9372 => '(a)',
9373 => '(b)',
9374 => '(c)',
9375 => '(d)',
9376 => '(e)',
9377 => '(f)',
9378 => '(g)',
9379 => '(h)',
9380 => '(i)',
9381 => '(j)',
9382 => '(k)',
9383 => '(l)',
9384 => '(m)',
9385 => '(n)',
9386 => '(o)',
9387 => '(p)',
9388 => '(q)',
9389 => '(r)',
9390 => '(s)',
9391 => '(t)',
9392 => '(u)',
9393 => '(v)',
9394 => '(w)',
9395 => '(x)',
9396 => '(y)',
9397 => '(z)',
10868 => '::=',
10869 => '==',
10870 => '===',
12288 => ' ',
12443 => ' ゙',
12444 => ' ゚',
12800 => '(ᄀ)',
12801 => '(ᄂ)',
12802 => '(ᄃ)',
12803 => '(ᄅ)',
12804 => '(ᄆ)',
12805 => '(ᄇ)',
12806 => '(ᄉ)',
12807 => '(ᄋ)',
12808 => '(ᄌ)',
12809 => '(ᄎ)',
12810 => '(ᄏ)',
12811 => '(ᄐ)',
12812 => '(ᄑ)',
12813 => '(ᄒ)',
12814 => '(가)',
12815 => '(나)',
12816 => '(다)',
12817 => '(라)',
12818 => '(마)',
12819 => '(바)',
12820 => '(사)',
12821 => '(아)',
12822 => '(자)',
12823 => '(차)',
12824 => '(카)',
12825 => '(타)',
12826 => '(파)',
12827 => '(하)',
12828 => '(주)',
12829 => '(오전)',
12830 => '(오후)',
12832 => '(一)',
12833 => '(二)',
12834 => '(三)',
12835 => '(四)',
12836 => '(五)',
12837 => '(六)',
12838 => '(七)',
12839 => '(八)',
12840 => '(九)',
12841 => '(十)',
12842 => '(月)',
12843 => '(火)',
12844 => '(水)',
12845 => '(木)',
12846 => '(金)',
12847 => '(土)',
12848 => '(日)',
12849 => '(株)',
12850 => '(有)',
12851 => '(社)',
12852 => '(名)',
12853 => '(特)',
12854 => '(財)',
12855 => '(祝)',
12856 => '(労)',
12857 => '(代)',
12858 => '(呼)',
12859 => '(学)',
12860 => '(監)',
12861 => '(企)',
12862 => '(資)',
12863 => '(協)',
12864 => '(祭)',
12865 => '(休)',
12866 => '(自)',
12867 => '(至)',
64297 => '+',
64606 => ' ٌّ',
64607 => ' ٍّ',
64608 => ' َّ',
64609 => ' ُّ',
64610 => ' ِّ',
64611 => ' ّٰ',
65018 => 'صلى الله عليه وسلم',
65019 => 'جل جلاله',
65040 => ',',
65043 => ':',
65044 => ';',
65045 => '!',
65046 => '?',
65075 => '_',
65076 => '_',
65077 => '(',
65078 => ')',
65079 => '{',
65080 => '}',
65095 => '[',
65096 => ']',
65097 => ' ̅',
65098 => ' ̅',
65099 => ' ̅',
65100 => ' ̅',
65101 => '_',
65102 => '_',
65103 => '_',
65104 => ',',
65108 => ';',
65109 => ':',
65110 => '?',
65111 => '!',
65113 => '(',
65114 => ')',
65115 => '{',
65116 => '}',
65119 => '#',
65120 => '&',
65121 => '*',
65122 => '+',
65124 => '<',
65125 => '>',
65126 => '=',
65128 => '\\',
65129 => '$',
65130 => '%',
65131 => '@',
65136 => ' ً',
65138 => ' ٌ',
65140 => ' ٍ',
65142 => ' َ',
65144 => ' ُ',
65146 => ' ِ',
65148 => ' ّ',
65150 => ' ْ',
65281 => '!',
65282 => '"',
65283 => '#',
65284 => '$',
65285 => '%',
65286 => '&',
65287 => '\'',
65288 => '(',
65289 => ')',
65290 => '*',
65291 => '+',
65292 => ',',
65295 => '/',
65306 => ':',
65307 => ';',
65308 => '<',
65309 => '=',
65310 => '>',
65311 => '?',
65312 => '@',
65339 => '[',
65340 => '\\',
65341 => ']',
65342 => '^',
65343 => '_',
65344 => '`',
65371 => '{',
65372 => '|',
65373 => '}',
65374 => '~',
65507 => ' ̄',
127233 => '0,',
127234 => '1,',
127235 => '2,',
127236 => '3,',
127237 => '4,',
127238 => '5,',
127239 => '6,',
127240 => '7,',
127241 => '8,',
127242 => '9,',
127248 => '(a)',
127249 => '(b)',
127250 => '(c)',
127251 => '(d)',
127252 => '(e)',
127253 => '(f)',
127254 => '(g)',
127255 => '(h)',
127256 => '(i)',
127257 => '(j)',
127258 => '(k)',
127259 => '(l)',
127260 => '(m)',
127261 => '(n)',
127262 => '(o)',
127263 => '(p)',
127264 => '(q)',
127265 => '(r)',
127266 => '(s)',
127267 => '(t)',
127268 => '(u)',
127269 => '(v)',
127270 => '(w)',
127271 => '(x)',
127272 => '(y)',
127273 => '(z)',
);

View File

@@ -0,0 +1,71 @@
<?php
return array (
0 => true,
1 => true,
2 => true,
3 => true,
4 => true,
5 => true,
6 => true,
7 => true,
8 => true,
9 => true,
10 => true,
11 => true,
12 => true,
13 => true,
14 => true,
15 => true,
16 => true,
17 => true,
18 => true,
19 => true,
20 => true,
21 => true,
22 => true,
23 => true,
24 => true,
25 => true,
26 => true,
27 => true,
28 => true,
29 => true,
30 => true,
31 => true,
32 => true,
33 => true,
34 => true,
35 => true,
36 => true,
37 => true,
38 => true,
39 => true,
40 => true,
41 => true,
42 => true,
43 => true,
44 => true,
47 => true,
58 => true,
59 => true,
60 => true,
61 => true,
62 => true,
63 => true,
64 => true,
91 => true,
92 => true,
93 => true,
94 => true,
95 => true,
96 => true,
123 => true,
124 => true,
125 => true,
126 => true,
127 => true,
8800 => true,
8814 => true,
8815 => true,
);

View File

@@ -0,0 +1,273 @@
<?php
return array (
173 => true,
847 => true,
6155 => true,
6156 => true,
6157 => true,
8203 => true,
8288 => true,
8292 => true,
65024 => true,
65025 => true,
65026 => true,
65027 => true,
65028 => true,
65029 => true,
65030 => true,
65031 => true,
65032 => true,
65033 => true,
65034 => true,
65035 => true,
65036 => true,
65037 => true,
65038 => true,
65039 => true,
65279 => true,
113824 => true,
113825 => true,
113826 => true,
113827 => true,
917760 => true,
917761 => true,
917762 => true,
917763 => true,
917764 => true,
917765 => true,
917766 => true,
917767 => true,
917768 => true,
917769 => true,
917770 => true,
917771 => true,
917772 => true,
917773 => true,
917774 => true,
917775 => true,
917776 => true,
917777 => true,
917778 => true,
917779 => true,
917780 => true,
917781 => true,
917782 => true,
917783 => true,
917784 => true,
917785 => true,
917786 => true,
917787 => true,
917788 => true,
917789 => true,
917790 => true,
917791 => true,
917792 => true,
917793 => true,
917794 => true,
917795 => true,
917796 => true,
917797 => true,
917798 => true,
917799 => true,
917800 => true,
917801 => true,
917802 => true,
917803 => true,
917804 => true,
917805 => true,
917806 => true,
917807 => true,
917808 => true,
917809 => true,
917810 => true,
917811 => true,
917812 => true,
917813 => true,
917814 => true,
917815 => true,
917816 => true,
917817 => true,
917818 => true,
917819 => true,
917820 => true,
917821 => true,
917822 => true,
917823 => true,
917824 => true,
917825 => true,
917826 => true,
917827 => true,
917828 => true,
917829 => true,
917830 => true,
917831 => true,
917832 => true,
917833 => true,
917834 => true,
917835 => true,
917836 => true,
917837 => true,
917838 => true,
917839 => true,
917840 => true,
917841 => true,
917842 => true,
917843 => true,
917844 => true,
917845 => true,
917846 => true,
917847 => true,
917848 => true,
917849 => true,
917850 => true,
917851 => true,
917852 => true,
917853 => true,
917854 => true,
917855 => true,
917856 => true,
917857 => true,
917858 => true,
917859 => true,
917860 => true,
917861 => true,
917862 => true,
917863 => true,
917864 => true,
917865 => true,
917866 => true,
917867 => true,
917868 => true,
917869 => true,
917870 => true,
917871 => true,
917872 => true,
917873 => true,
917874 => true,
917875 => true,
917876 => true,
917877 => true,
917878 => true,
917879 => true,
917880 => true,
917881 => true,
917882 => true,
917883 => true,
917884 => true,
917885 => true,
917886 => true,
917887 => true,
917888 => true,
917889 => true,
917890 => true,
917891 => true,
917892 => true,
917893 => true,
917894 => true,
917895 => true,
917896 => true,
917897 => true,
917898 => true,
917899 => true,
917900 => true,
917901 => true,
917902 => true,
917903 => true,
917904 => true,
917905 => true,
917906 => true,
917907 => true,
917908 => true,
917909 => true,
917910 => true,
917911 => true,
917912 => true,
917913 => true,
917914 => true,
917915 => true,
917916 => true,
917917 => true,
917918 => true,
917919 => true,
917920 => true,
917921 => true,
917922 => true,
917923 => true,
917924 => true,
917925 => true,
917926 => true,
917927 => true,
917928 => true,
917929 => true,
917930 => true,
917931 => true,
917932 => true,
917933 => true,
917934 => true,
917935 => true,
917936 => true,
917937 => true,
917938 => true,
917939 => true,
917940 => true,
917941 => true,
917942 => true,
917943 => true,
917944 => true,
917945 => true,
917946 => true,
917947 => true,
917948 => true,
917949 => true,
917950 => true,
917951 => true,
917952 => true,
917953 => true,
917954 => true,
917955 => true,
917956 => true,
917957 => true,
917958 => true,
917959 => true,
917960 => true,
917961 => true,
917962 => true,
917963 => true,
917964 => true,
917965 => true,
917966 => true,
917967 => true,
917968 => true,
917969 => true,
917970 => true,
917971 => true,
917972 => true,
917973 => true,
917974 => true,
917975 => true,
917976 => true,
917977 => true,
917978 => true,
917979 => true,
917980 => true,
917981 => true,
917982 => true,
917983 => true,
917984 => true,
917985 => true,
917986 => true,
917987 => true,
917988 => true,
917989 => true,
917990 => true,
917991 => true,
917992 => true,
917993 => true,
917994 => true,
917995 => true,
917996 => true,
917997 => true,
917998 => true,
917999 => true,
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
<?php
return array (
2381 => 9,
2509 => 9,
2637 => 9,
2765 => 9,
2893 => 9,
3021 => 9,
3149 => 9,
3277 => 9,
3387 => 9,
3388 => 9,
3405 => 9,
3530 => 9,
3642 => 9,
3770 => 9,
3972 => 9,
4153 => 9,
4154 => 9,
5908 => 9,
5940 => 9,
6098 => 9,
6752 => 9,
6980 => 9,
7082 => 9,
7083 => 9,
7154 => 9,
7155 => 9,
11647 => 9,
43014 => 9,
43052 => 9,
43204 => 9,
43347 => 9,
43456 => 9,
43766 => 9,
44013 => 9,
68159 => 9,
69702 => 9,
69759 => 9,
69817 => 9,
69939 => 9,
69940 => 9,
70080 => 9,
70197 => 9,
70378 => 9,
70477 => 9,
70722 => 9,
70850 => 9,
71103 => 9,
71231 => 9,
71350 => 9,
71467 => 9,
71737 => 9,
71997 => 9,
71998 => 9,
72160 => 9,
72244 => 9,
72263 => 9,
72345 => 9,
72767 => 9,
73028 => 9,
73029 => 9,
73111 => 9,
);

View File

@@ -0,0 +1,145 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Idn as p;
if (extension_loaded('intl')) {
return;
}
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!defined('U_IDNA_PROHIBITED_ERROR')) {
define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_2003')) {
define('INTL_IDNA_VARIANT_2003', 0);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
define('IDNA_ERROR_CONTEXTJ', 4096);
}
if (\PHP_VERSION_ID < 70400) {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
}
} else {
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
}
}

View File

@@ -0,0 +1,125 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Idn as p;
if (!defined('U_IDNA_PROHIBITED_ERROR')) {
define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
define('IDNA_ERROR_CONTEXTJ', 4096);
}
if (!function_exists('idn_to_ascii')) {
function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}

View File

@@ -0,0 +1,44 @@
{
"name": "symfony/polyfill-intl-idn",
"type": "library",
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
"keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "idn"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Laurent Bassin",
"email": "laurent@bassin.info"
},
{
"name": "Trevor Rowbotham",
"email": "trevor.rowbotham@pm.me"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1",
"symfony/polyfill-intl-normalizer": "^1.10",
"symfony/polyfill-php72": "^1.10"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-intl": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2015-2019 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,310 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Intl\Normalizer;
/**
* Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.
*
* It has been validated with Unicode 6.3 Normalization Conformance Test.
* See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Normalizer
{
public const FORM_D = \Normalizer::FORM_D;
public const FORM_KD = \Normalizer::FORM_KD;
public const FORM_C = \Normalizer::FORM_C;
public const FORM_KC = \Normalizer::FORM_KC;
public const NFD = \Normalizer::NFD;
public const NFKD = \Normalizer::NFKD;
public const NFC = \Normalizer::NFC;
public const NFKC = \Normalizer::NFKC;
private static $C;
private static $D;
private static $KD;
private static $cC;
private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
public static function isNormalized(string $s, int $form = self::FORM_C)
{
if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {
return false;
}
if (!isset($s[strspn($s, self::$ASCII)])) {
return true;
}
if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) {
return true;
}
return self::normalize($s, $form) === $s;
}
public static function normalize(string $s, int $form = self::FORM_C)
{
if (!preg_match('//u', $s)) {
return false;
}
switch ($form) {
case self::NFC: $C = true; $K = false; break;
case self::NFD: $C = false; $K = false; break;
case self::NFKC: $C = true; $K = true; break;
case self::NFKD: $C = false; $K = true; break;
default:
if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) {
return $s;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');
}
if ('' === $s) {
return '';
}
if ($K && null === self::$KD) {
self::$KD = self::getData('compatibilityDecomposition');
}
if (null === self::$D) {
self::$D = self::getData('canonicalDecomposition');
self::$cC = self::getData('combiningClass');
}
if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {
mb_internal_encoding('8bit');
}
$r = self::decompose($s, $K);
if ($C) {
if (null === self::$C) {
self::$C = self::getData('canonicalComposition');
}
$r = self::recompose($r);
}
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
return $r;
}
private static function recompose($s)
{
$ASCII = self::$ASCII;
$compMap = self::$C;
$combClass = self::$cC;
$ulenMask = self::$ulenMask;
$result = $tail = '';
$i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"];
$len = \strlen($s);
$lastUchr = substr($s, 0, $i);
$lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;
while ($i < $len) {
if ($s[$i] < "\x80") {
// ASCII chars
if ($tail) {
$lastUchr .= $tail;
$tail = '';
}
if ($j = strspn($s, $ASCII, $i + 1)) {
$lastUchr .= substr($s, $i, $j);
$i += $j;
}
$result .= $lastUchr;
$lastUchr = $s[$i];
$lastUcls = 0;
++$i;
continue;
}
$ulen = $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr
|| $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
|| $lastUcls) {
// Table lookup and combining chars composition
$ucls = $combClass[$uchr] ?? 0;
if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {
$lastUchr = $compMap[$lastUchr.$uchr];
} elseif ($lastUcls = $ucls) {
$tail .= $uchr;
} else {
if ($tail) {
$lastUchr .= $tail;
$tail = '';
}
$result .= $lastUchr;
$lastUchr = $uchr;
}
} else {
// Hangul chars
$L = \ord($lastUchr[2]) - 0x80;
$V = \ord($uchr[2]) - 0xA1;
$T = 0;
$uchr = substr($s, $i + $ulen, 3);
if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") {
$T = \ord($uchr[2]) - 0xA7;
0 > $T && $T += 0x40;
$ulen += 3;
}
$L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
$lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F);
}
$i += $ulen;
}
return $result.$lastUchr.$tail;
}
private static function decompose($s, $c)
{
$result = '';
$ASCII = self::$ASCII;
$decompMap = self::$D;
$combClass = self::$cC;
$ulenMask = self::$ulenMask;
if ($c) {
$compatMap = self::$KD;
}
$c = [];
$i = 0;
$len = \strlen($s);
while ($i < $len) {
if ($s[$i] < "\x80") {
// ASCII chars
if ($c) {
ksort($c);
$result .= implode('', $c);
$c = [];
}
$j = 1 + strspn($s, $ASCII, $i + 1);
$result .= substr($s, $i, $j);
$i += $j;
continue;
}
$ulen = $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {
// Table lookup
if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {
$uchr = $j;
$j = \strlen($uchr);
$ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"];
if ($ulen != $j) {
// Put trailing chars in $s
$j -= $ulen;
$i -= $j;
if (0 > $i) {
$s = str_repeat(' ', -$i).$s;
$len -= $i;
$i = 0;
}
while ($j--) {
$s[$i + $j] = $uchr[$ulen + $j];
}
$uchr = substr($uchr, 0, $ulen);
}
}
if (isset($combClass[$uchr])) {
// Combining chars, for sorting
if (!isset($c[$combClass[$uchr]])) {
$c[$combClass[$uchr]] = '';
}
$c[$combClass[$uchr]] .= $uchr;
continue;
}
} else {
// Hangul chars
$uchr = unpack('C*', $uchr);
$j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;
$uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588))
."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28));
if ($j %= 28) {
$uchr .= $j < 25
? ("\xE1\x86".\chr(0xA7 + $j))
: ("\xE1\x87".\chr(0x67 + $j));
}
}
if ($c) {
ksort($c);
$result .= implode('', $c);
$c = [];
}
$result .= $uchr;
}
if ($c) {
ksort($c);
$result .= implode('', $c);
}
return $result;
}
private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}
return false;
}
}

View File

@@ -0,0 +1,14 @@
Symfony Polyfill / Intl: Normalizer
===================================
This component provides a fallback implementation for the
[`Normalizer`](https://php.net/Normalizer) class provided
by the [Intl](https://php.net/intl) extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

View File

@@ -0,0 +1,17 @@
<?php
class Normalizer extends Symfony\Polyfill\Intl\Normalizer\Normalizer
{
/**
* @deprecated since ICU 56 and removed in PHP 8
*/
public const NONE = 2;
public const FORM_D = 4;
public const FORM_KD = 8;
public const FORM_C = 16;
public const FORM_KC = 32;
public const NFD = 4;
public const NFKD = 8;
public const NFC = 16;
public const NFKC = 32;
}

View File

@@ -0,0 +1,945 @@
<?php
return array (
'À' => 'À',
'Á' => 'Á',
'Â' => 'Â',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Å' => 'Å',
'Ç' => 'Ç',
'È' => 'È',
'É' => 'É',
'Ê' => 'Ê',
'Ë' => 'Ë',
'Ì' => 'Ì',
'Í' => 'Í',
'Î' => 'Î',
'Ï' => 'Ï',
'Ñ' => 'Ñ',
'Ò' => 'Ò',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Õ' => 'Õ',
'Ö' => 'Ö',
'Ù' => 'Ù',
'Ú' => 'Ú',
'Û' => 'Û',
'Ü' => 'Ü',
'Ý' => 'Ý',
'à' => 'à',
'á' => 'á',
'â' => 'â',
'ã' => 'ã',
'ä' => 'ä',
'å' => 'å',
'ç' => 'ç',
'è' => 'è',
'é' => 'é',
'ê' => 'ê',
'ë' => 'ë',
'ì' => 'ì',
'í' => 'í',
'î' => 'î',
'ï' => 'ï',
'ñ' => 'ñ',
'ò' => 'ò',
'ó' => 'ó',
'ô' => 'ô',
'õ' => 'õ',
'ö' => 'ö',
'ù' => 'ù',
'ú' => 'ú',
'û' => 'û',
'ü' => 'ü',
'ý' => 'ý',
'ÿ' => 'ÿ',
'Ā' => 'Ā',
'ā' => 'ā',
'Ă' => 'Ă',
'ă' => 'ă',
'Ą' => 'Ą',
'ą' => 'ą',
'Ć' => 'Ć',
'ć' => 'ć',
'Ĉ' => 'Ĉ',
'ĉ' => 'ĉ',
'Ċ' => 'Ċ',
'ċ' => 'ċ',
'Č' => 'Č',
'č' => 'č',
'Ď' => 'Ď',
'ď' => 'ď',
'Ē' => 'Ē',
'ē' => 'ē',
'Ĕ' => 'Ĕ',
'ĕ' => 'ĕ',
'Ė' => 'Ė',
'ė' => 'ė',
'Ę' => 'Ę',
'ę' => 'ę',
'Ě' => 'Ě',
'ě' => 'ě',
'Ĝ' => 'Ĝ',
'ĝ' => 'ĝ',
'Ğ' => 'Ğ',
'ğ' => 'ğ',
'Ġ' => 'Ġ',
'ġ' => 'ġ',
'Ģ' => 'Ģ',
'ģ' => 'ģ',
'Ĥ' => 'Ĥ',
'ĥ' => 'ĥ',
'Ĩ' => 'Ĩ',
'ĩ' => 'ĩ',
'Ī' => 'Ī',
'ī' => 'ī',
'Ĭ' => 'Ĭ',
'ĭ' => 'ĭ',
'Į' => 'Į',
'į' => 'į',
'İ' => 'İ',
'Ĵ' => 'Ĵ',
'ĵ' => 'ĵ',
'Ķ' => 'Ķ',
'ķ' => 'ķ',
'Ĺ' => 'Ĺ',
'ĺ' => 'ĺ',
'Ļ' => 'Ļ',
'ļ' => 'ļ',
'Ľ' => 'Ľ',
'ľ' => 'ľ',
'Ń' => 'Ń',
'ń' => 'ń',
'Ņ' => 'Ņ',
'ņ' => 'ņ',
'Ň' => 'Ň',
'ň' => 'ň',
'Ō' => 'Ō',
'ō' => 'ō',
'Ŏ' => 'Ŏ',
'ŏ' => 'ŏ',
'Ő' => 'Ő',
'ő' => 'ő',
'Ŕ' => 'Ŕ',
'ŕ' => 'ŕ',
'Ŗ' => 'Ŗ',
'ŗ' => 'ŗ',
'Ř' => 'Ř',
'ř' => 'ř',
'Ś' => 'Ś',
'ś' => 'ś',
'Ŝ' => 'Ŝ',
'ŝ' => 'ŝ',
'Ş' => 'Ş',
'ş' => 'ş',
'Š' => 'Š',
'š' => 'š',
'Ţ' => 'Ţ',
'ţ' => 'ţ',
'Ť' => 'Ť',
'ť' => 'ť',
'Ũ' => 'Ũ',
'ũ' => 'ũ',
'Ū' => 'Ū',
'ū' => 'ū',
'Ŭ' => 'Ŭ',
'ŭ' => 'ŭ',
'Ů' => 'Ů',
'ů' => 'ů',
'Ű' => 'Ű',
'ű' => 'ű',
'Ų' => 'Ų',
'ų' => 'ų',
'Ŵ' => 'Ŵ',
'ŵ' => 'ŵ',
'Ŷ' => 'Ŷ',
'ŷ' => 'ŷ',
'Ÿ' => 'Ÿ',
'Ź' => 'Ź',
'ź' => 'ź',
'Ż' => 'Ż',
'ż' => 'ż',
'Ž' => 'Ž',
'ž' => 'ž',
'Ơ' => 'Ơ',
'ơ' => 'ơ',
'Ư' => 'Ư',
'ư' => 'ư',
'Ǎ' => 'Ǎ',
'ǎ' => 'ǎ',
'Ǐ' => 'Ǐ',
'ǐ' => 'ǐ',
'Ǒ' => 'Ǒ',
'ǒ' => 'ǒ',
'Ǔ' => 'Ǔ',
'ǔ' => 'ǔ',
'Ǖ' => 'Ǖ',
'ǖ' => 'ǖ',
'Ǘ' => 'Ǘ',
'ǘ' => 'ǘ',
'Ǚ' => 'Ǚ',
'ǚ' => 'ǚ',
'Ǜ' => 'Ǜ',
'ǜ' => 'ǜ',
'Ǟ' => 'Ǟ',
'ǟ' => 'ǟ',
'Ǡ' => 'Ǡ',
'ǡ' => 'ǡ',
'Ǣ' => 'Ǣ',
'ǣ' => 'ǣ',
'Ǧ' => 'Ǧ',
'ǧ' => 'ǧ',
'Ǩ' => 'Ǩ',
'ǩ' => 'ǩ',
'Ǫ' => 'Ǫ',
'ǫ' => 'ǫ',
'Ǭ' => 'Ǭ',
'ǭ' => 'ǭ',
'Ǯ' => 'Ǯ',
'ǯ' => 'ǯ',
'ǰ' => 'ǰ',
'Ǵ' => 'Ǵ',
'ǵ' => 'ǵ',
'Ǹ' => 'Ǹ',
'ǹ' => 'ǹ',
'Ǻ' => 'Ǻ',
'ǻ' => 'ǻ',
'Ǽ' => 'Ǽ',
'ǽ' => 'ǽ',
'Ǿ' => 'Ǿ',
'ǿ' => 'ǿ',
'Ȁ' => 'Ȁ',
'ȁ' => 'ȁ',
'Ȃ' => 'Ȃ',
'ȃ' => 'ȃ',
'Ȅ' => 'Ȅ',
'ȅ' => 'ȅ',
'Ȇ' => 'Ȇ',
'ȇ' => 'ȇ',
'Ȉ' => 'Ȉ',
'ȉ' => 'ȉ',
'Ȋ' => 'Ȋ',
'ȋ' => 'ȋ',
'Ȍ' => 'Ȍ',
'ȍ' => 'ȍ',
'Ȏ' => 'Ȏ',
'ȏ' => 'ȏ',
'Ȑ' => 'Ȑ',
'ȑ' => 'ȑ',
'Ȓ' => 'Ȓ',
'ȓ' => 'ȓ',
'Ȕ' => 'Ȕ',
'ȕ' => 'ȕ',
'Ȗ' => 'Ȗ',
'ȗ' => 'ȗ',
'Ș' => 'Ș',
'ș' => 'ș',
'Ț' => 'Ț',
'ț' => 'ț',
'Ȟ' => 'Ȟ',
'ȟ' => 'ȟ',
'Ȧ' => 'Ȧ',
'ȧ' => 'ȧ',
'Ȩ' => 'Ȩ',
'ȩ' => 'ȩ',
'Ȫ' => 'Ȫ',
'ȫ' => 'ȫ',
'Ȭ' => 'Ȭ',
'ȭ' => 'ȭ',
'Ȯ' => 'Ȯ',
'ȯ' => 'ȯ',
'Ȱ' => 'Ȱ',
'ȱ' => 'ȱ',
'Ȳ' => 'Ȳ',
'ȳ' => 'ȳ',
'΅' => '΅',
'Ά' => 'Ά',
'Έ' => 'Έ',
'Ή' => 'Ή',
'Ί' => 'Ί',
'Ό' => 'Ό',
'Ύ' => 'Ύ',
'Ώ' => 'Ώ',
'ΐ' => 'ΐ',
'Ϊ' => 'Ϊ',
'Ϋ' => 'Ϋ',
'ά' => 'ά',
'έ' => 'έ',
'ή' => 'ή',
'ί' => 'ί',
'ΰ' => 'ΰ',
'ϊ' => 'ϊ',
'ϋ' => 'ϋ',
'ό' => 'ό',
'ύ' => 'ύ',
'ώ' => 'ώ',
'ϓ' => 'ϓ',
'ϔ' => 'ϔ',
'Ѐ' => 'Ѐ',
'Ё' => 'Ё',
'Ѓ' => 'Ѓ',
'Ї' => 'Ї',
'Ќ' => 'Ќ',
'Ѝ' => 'Ѝ',
'Ў' => 'Ў',
'Й' => 'Й',
'й' => 'й',
'ѐ' => 'ѐ',
'ё' => 'ё',
'ѓ' => 'ѓ',
'ї' => 'ї',
'ќ' => 'ќ',
'ѝ' => 'ѝ',
'ў' => 'ў',
'Ѷ' => 'Ѷ',
'ѷ' => 'ѷ',
'Ӂ' => 'Ӂ',
'ӂ' => 'ӂ',
'Ӑ' => 'Ӑ',
'ӑ' => 'ӑ',
'Ӓ' => 'Ӓ',
'ӓ' => 'ӓ',
'Ӗ' => 'Ӗ',
'ӗ' => 'ӗ',
'Ӛ' => 'Ӛ',
'ӛ' => 'ӛ',
'Ӝ' => 'Ӝ',
'ӝ' => 'ӝ',
'Ӟ' => 'Ӟ',
'ӟ' => 'ӟ',
'Ӣ' => 'Ӣ',
'ӣ' => 'ӣ',
'Ӥ' => 'Ӥ',
'ӥ' => 'ӥ',
'Ӧ' => 'Ӧ',
'ӧ' => 'ӧ',
'Ӫ' => 'Ӫ',
'ӫ' => 'ӫ',
'Ӭ' => 'Ӭ',
'ӭ' => 'ӭ',
'Ӯ' => 'Ӯ',
'ӯ' => 'ӯ',
'Ӱ' => 'Ӱ',
'ӱ' => 'ӱ',
'Ӳ' => 'Ӳ',
'ӳ' => 'ӳ',
'Ӵ' => 'Ӵ',
'ӵ' => 'ӵ',
'Ӹ' => 'Ӹ',
'ӹ' => 'ӹ',
'آ' => 'آ',
'أ' => 'أ',
'ؤ' => 'ؤ',
'إ' => 'إ',
'ئ' => 'ئ',
'ۀ' => 'ۀ',
'ۂ' => 'ۂ',
'ۓ' => 'ۓ',
'ऩ' => 'ऩ',
'ऱ' => 'ऱ',
'ऴ' => 'ऴ',
'ো' => 'ো',
'ৌ' => 'ৌ',
'ୈ' => 'ୈ',
'ୋ' => 'ୋ',
'ୌ' => 'ୌ',
'ஔ' => 'ஔ',
'ொ' => 'ொ',
'ோ' => 'ோ',
'ௌ' => 'ௌ',
'ై' => 'ై',
'ೀ' => 'ೀ',
'ೇ' => 'ೇ',
'ೈ' => 'ೈ',
'ೊ' => 'ೊ',
'ೋ' => 'ೋ',
'ൊ' => 'ൊ',
'ോ' => 'ോ',
'ൌ' => 'ൌ',
'ේ' => 'ේ',
'ො' => 'ො',
'ෝ' => 'ෝ',
'ෞ' => 'ෞ',
'ဦ' => 'ဦ',
'ᬆ' => 'ᬆ',
'ᬈ' => 'ᬈ',
'ᬊ' => 'ᬊ',
'ᬌ' => 'ᬌ',
'ᬎ' => 'ᬎ',
'ᬒ' => 'ᬒ',
'ᬻ' => 'ᬻ',
'ᬽ' => 'ᬽ',
'ᭀ' => 'ᭀ',
'ᭁ' => 'ᭁ',
'ᭃ' => 'ᭃ',
'Ḁ' => 'Ḁ',
'ḁ' => 'ḁ',
'Ḃ' => 'Ḃ',
'ḃ' => 'ḃ',
'Ḅ' => 'Ḅ',
'ḅ' => 'ḅ',
'Ḇ' => 'Ḇ',
'ḇ' => 'ḇ',
'Ḉ' => 'Ḉ',
'ḉ' => 'ḉ',
'Ḋ' => 'Ḋ',
'ḋ' => 'ḋ',
'Ḍ' => 'Ḍ',
'ḍ' => 'ḍ',
'Ḏ' => 'Ḏ',
'ḏ' => 'ḏ',
'Ḑ' => 'Ḑ',
'ḑ' => 'ḑ',
'Ḓ' => 'Ḓ',
'ḓ' => 'ḓ',
'Ḕ' => 'Ḕ',
'ḕ' => 'ḕ',
'Ḗ' => 'Ḗ',
'ḗ' => 'ḗ',
'Ḙ' => 'Ḙ',
'ḙ' => 'ḙ',
'Ḛ' => 'Ḛ',
'ḛ' => 'ḛ',
'Ḝ' => 'Ḝ',
'ḝ' => 'ḝ',
'Ḟ' => 'Ḟ',
'ḟ' => 'ḟ',
'Ḡ' => 'Ḡ',
'ḡ' => 'ḡ',
'Ḣ' => 'Ḣ',
'ḣ' => 'ḣ',
'Ḥ' => 'Ḥ',
'ḥ' => 'ḥ',
'Ḧ' => 'Ḧ',
'ḧ' => 'ḧ',
'Ḩ' => 'Ḩ',
'ḩ' => 'ḩ',
'Ḫ' => 'Ḫ',
'ḫ' => 'ḫ',
'Ḭ' => 'Ḭ',
'ḭ' => 'ḭ',
'Ḯ' => 'Ḯ',
'ḯ' => 'ḯ',
'Ḱ' => 'Ḱ',
'ḱ' => 'ḱ',
'Ḳ' => 'Ḳ',
'ḳ' => 'ḳ',
'Ḵ' => 'Ḵ',
'ḵ' => 'ḵ',
'Ḷ' => 'Ḷ',
'ḷ' => 'ḷ',
'Ḹ' => 'Ḹ',
'ḹ' => 'ḹ',
'Ḻ' => 'Ḻ',
'ḻ' => 'ḻ',
'Ḽ' => 'Ḽ',
'ḽ' => 'ḽ',
'Ḿ' => 'Ḿ',
'ḿ' => 'ḿ',
'Ṁ' => 'Ṁ',
'ṁ' => 'ṁ',
'Ṃ' => 'Ṃ',
'ṃ' => 'ṃ',
'Ṅ' => 'Ṅ',
'ṅ' => 'ṅ',
'Ṇ' => 'Ṇ',
'ṇ' => 'ṇ',
'Ṉ' => 'Ṉ',
'ṉ' => 'ṉ',
'Ṋ' => 'Ṋ',
'ṋ' => 'ṋ',
'Ṍ' => 'Ṍ',
'ṍ' => 'ṍ',
'Ṏ' => 'Ṏ',
'ṏ' => 'ṏ',
'Ṑ' => 'Ṑ',
'ṑ' => 'ṑ',
'Ṓ' => 'Ṓ',
'ṓ' => 'ṓ',
'Ṕ' => 'Ṕ',
'ṕ' => 'ṕ',
'Ṗ' => 'Ṗ',
'ṗ' => 'ṗ',
'Ṙ' => 'Ṙ',
'ṙ' => 'ṙ',
'Ṛ' => 'Ṛ',
'ṛ' => 'ṛ',
'Ṝ' => 'Ṝ',
'ṝ' => 'ṝ',
'Ṟ' => 'Ṟ',
'ṟ' => 'ṟ',
'Ṡ' => 'Ṡ',
'ṡ' => 'ṡ',
'Ṣ' => 'Ṣ',
'ṣ' => 'ṣ',
'Ṥ' => 'Ṥ',
'ṥ' => 'ṥ',
'Ṧ' => 'Ṧ',
'ṧ' => 'ṧ',
'Ṩ' => 'Ṩ',
'ṩ' => 'ṩ',
'Ṫ' => 'Ṫ',
'ṫ' => 'ṫ',
'Ṭ' => 'Ṭ',
'ṭ' => 'ṭ',
'Ṯ' => 'Ṯ',
'ṯ' => 'ṯ',
'Ṱ' => 'Ṱ',
'ṱ' => 'ṱ',
'Ṳ' => 'Ṳ',
'ṳ' => 'ṳ',
'Ṵ' => 'Ṵ',
'ṵ' => 'ṵ',
'Ṷ' => 'Ṷ',
'ṷ' => 'ṷ',
'Ṹ' => 'Ṹ',
'ṹ' => 'ṹ',
'Ṻ' => 'Ṻ',
'ṻ' => 'ṻ',
'Ṽ' => 'Ṽ',
'ṽ' => 'ṽ',
'Ṿ' => 'Ṿ',
'ṿ' => 'ṿ',
'Ẁ' => 'Ẁ',
'ẁ' => 'ẁ',
'Ẃ' => 'Ẃ',
'ẃ' => 'ẃ',
'Ẅ' => 'Ẅ',
'ẅ' => 'ẅ',
'Ẇ' => 'Ẇ',
'ẇ' => 'ẇ',
'Ẉ' => 'Ẉ',
'ẉ' => 'ẉ',
'Ẋ' => 'Ẋ',
'ẋ' => 'ẋ',
'Ẍ' => 'Ẍ',
'ẍ' => 'ẍ',
'Ẏ' => 'Ẏ',
'ẏ' => 'ẏ',
'Ẑ' => 'Ẑ',
'ẑ' => 'ẑ',
'Ẓ' => 'Ẓ',
'ẓ' => 'ẓ',
'Ẕ' => 'Ẕ',
'ẕ' => 'ẕ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẛ' => 'ẛ',
'Ạ' => 'Ạ',
'ạ' => 'ạ',
'Ả' => 'Ả',
'ả' => 'ả',
'Ấ' => 'Ấ',
'ấ' => 'ấ',
'Ầ' => 'Ầ',
'ầ' => 'ầ',
'Ẩ' => 'Ẩ',
'ẩ' => 'ẩ',
'Ẫ' => 'Ẫ',
'ẫ' => 'ẫ',
'Ậ' => 'Ậ',
'ậ' => 'ậ',
'Ắ' => 'Ắ',
'ắ' => 'ắ',
'Ằ' => 'Ằ',
'ằ' => 'ằ',
'Ẳ' => 'Ẳ',
'ẳ' => 'ẳ',
'Ẵ' => 'Ẵ',
'ẵ' => 'ẵ',
'Ặ' => 'Ặ',
'ặ' => 'ặ',
'Ẹ' => 'Ẹ',
'ẹ' => 'ẹ',
'Ẻ' => 'Ẻ',
'ẻ' => 'ẻ',
'Ẽ' => 'Ẽ',
'ẽ' => 'ẽ',
'Ế' => 'Ế',
'ế' => 'ế',
'Ề' => 'Ề',
'ề' => 'ề',
'Ể' => 'Ể',
'ể' => 'ể',
'Ễ' => 'Ễ',
'ễ' => 'ễ',
'Ệ' => 'Ệ',
'ệ' => 'ệ',
'Ỉ' => 'Ỉ',
'ỉ' => 'ỉ',
'Ị' => 'Ị',
'ị' => 'ị',
'Ọ' => 'Ọ',
'ọ' => 'ọ',
'Ỏ' => 'Ỏ',
'ỏ' => 'ỏ',
'Ố' => 'Ố',
'ố' => 'ố',
'Ồ' => 'Ồ',
'ồ' => 'ồ',
'Ổ' => 'Ổ',
'ổ' => 'ổ',
'Ỗ' => 'Ỗ',
'ỗ' => 'ỗ',
'Ộ' => 'Ộ',
'ộ' => 'ộ',
'Ớ' => 'Ớ',
'ớ' => 'ớ',
'Ờ' => 'Ờ',
'ờ' => 'ờ',
'Ở' => 'Ở',
'ở' => 'ở',
'Ỡ' => 'Ỡ',
'ỡ' => 'ỡ',
'Ợ' => 'Ợ',
'ợ' => 'ợ',
'Ụ' => 'Ụ',
'ụ' => 'ụ',
'Ủ' => 'Ủ',
'ủ' => 'ủ',
'Ứ' => 'Ứ',
'ứ' => 'ứ',
'Ừ' => 'Ừ',
'ừ' => 'ừ',
'Ử' => 'Ử',
'ử' => 'ử',
'Ữ' => 'Ữ',
'ữ' => 'ữ',
'Ự' => 'Ự',
'ự' => 'ự',
'Ỳ' => 'Ỳ',
'ỳ' => 'ỳ',
'Ỵ' => 'Ỵ',
'ỵ' => 'ỵ',
'Ỷ' => 'Ỷ',
'ỷ' => 'ỷ',
'Ỹ' => 'Ỹ',
'ỹ' => 'ỹ',
'ἀ' => 'ἀ',
'ἁ' => 'ἁ',
'ἂ' => 'ἂ',
'ἃ' => 'ἃ',
'ἄ' => 'ἄ',
'ἅ' => 'ἅ',
'ἆ' => 'ἆ',
'ἇ' => 'ἇ',
'Ἀ' => 'Ἀ',
'Ἁ' => 'Ἁ',
'Ἂ' => 'Ἂ',
'Ἃ' => 'Ἃ',
'Ἄ' => 'Ἄ',
'Ἅ' => 'Ἅ',
'Ἆ' => 'Ἆ',
'Ἇ' => 'Ἇ',
'ἐ' => 'ἐ',
'ἑ' => 'ἑ',
'ἒ' => 'ἒ',
'ἓ' => 'ἓ',
'ἔ' => 'ἔ',
'ἕ' => 'ἕ',
'Ἐ' => 'Ἐ',
'Ἑ' => 'Ἑ',
'Ἒ' => 'Ἒ',
'Ἓ' => 'Ἓ',
'Ἔ' => 'Ἔ',
'Ἕ' => 'Ἕ',
'ἠ' => 'ἠ',
'ἡ' => 'ἡ',
'ἢ' => 'ἢ',
'ἣ' => 'ἣ',
'ἤ' => 'ἤ',
'ἥ' => 'ἥ',
'ἦ' => 'ἦ',
'ἧ' => 'ἧ',
'Ἠ' => 'Ἠ',
'Ἡ' => 'Ἡ',
'Ἢ' => 'Ἢ',
'Ἣ' => 'Ἣ',
'Ἤ' => 'Ἤ',
'Ἥ' => 'Ἥ',
'Ἦ' => 'Ἦ',
'Ἧ' => 'Ἧ',
'ἰ' => 'ἰ',
'ἱ' => 'ἱ',
'ἲ' => 'ἲ',
'ἳ' => 'ἳ',
'ἴ' => 'ἴ',
'ἵ' => 'ἵ',
'ἶ' => 'ἶ',
'ἷ' => 'ἷ',
'Ἰ' => 'Ἰ',
'Ἱ' => 'Ἱ',
'Ἲ' => 'Ἲ',
'Ἳ' => 'Ἳ',
'Ἴ' => 'Ἴ',
'Ἵ' => 'Ἵ',
'Ἶ' => 'Ἶ',
'Ἷ' => 'Ἷ',
'ὀ' => 'ὀ',
'ὁ' => 'ὁ',
'ὂ' => 'ὂ',
'ὃ' => 'ὃ',
'ὄ' => 'ὄ',
'ὅ' => 'ὅ',
'Ὀ' => 'Ὀ',
'Ὁ' => 'Ὁ',
'Ὂ' => 'Ὂ',
'Ὃ' => 'Ὃ',
'Ὄ' => 'Ὄ',
'Ὅ' => 'Ὅ',
'ὐ' => 'ὐ',
'ὑ' => 'ὑ',
'ὒ' => 'ὒ',
'ὓ' => 'ὓ',
'ὔ' => 'ὔ',
'ὕ' => 'ὕ',
'ὖ' => 'ὖ',
'ὗ' => 'ὗ',
'Ὑ' => 'Ὑ',
'Ὓ' => 'Ὓ',
'Ὕ' => 'Ὕ',
'Ὗ' => 'Ὗ',
'ὠ' => 'ὠ',
'ὡ' => 'ὡ',
'ὢ' => 'ὢ',
'ὣ' => 'ὣ',
'ὤ' => 'ὤ',
'ὥ' => 'ὥ',
'ὦ' => 'ὦ',
'ὧ' => 'ὧ',
'Ὠ' => 'Ὠ',
'Ὡ' => 'Ὡ',
'Ὢ' => 'Ὢ',
'Ὣ' => 'Ὣ',
'Ὤ' => 'Ὤ',
'Ὥ' => 'Ὥ',
'Ὦ' => 'Ὦ',
'Ὧ' => 'Ὧ',
'ὰ' => 'ὰ',
'ὲ' => 'ὲ',
'ὴ' => 'ὴ',
'ὶ' => 'ὶ',
'ὸ' => 'ὸ',
'ὺ' => 'ὺ',
'ὼ' => 'ὼ',
'ᾀ' => 'ᾀ',
'ᾁ' => 'ᾁ',
'ᾂ' => 'ᾂ',
'ᾃ' => 'ᾃ',
'ᾄ' => 'ᾄ',
'ᾅ' => 'ᾅ',
'ᾆ' => 'ᾆ',
'ᾇ' => 'ᾇ',
'ᾈ' => 'ᾈ',
'ᾉ' => 'ᾉ',
'ᾊ' => 'ᾊ',
'ᾋ' => 'ᾋ',
'ᾌ' => 'ᾌ',
'ᾍ' => 'ᾍ',
'ᾎ' => 'ᾎ',
'ᾏ' => 'ᾏ',
'ᾐ' => 'ᾐ',
'ᾑ' => 'ᾑ',
'ᾒ' => 'ᾒ',
'ᾓ' => 'ᾓ',
'ᾔ' => 'ᾔ',
'ᾕ' => 'ᾕ',
'ᾖ' => 'ᾖ',
'ᾗ' => 'ᾗ',
'ᾘ' => 'ᾘ',
'ᾙ' => 'ᾙ',
'ᾚ' => 'ᾚ',
'ᾛ' => 'ᾛ',
'ᾜ' => 'ᾜ',
'ᾝ' => 'ᾝ',
'ᾞ' => 'ᾞ',
'ᾟ' => 'ᾟ',
'ᾠ' => 'ᾠ',
'ᾡ' => 'ᾡ',
'ᾢ' => 'ᾢ',
'ᾣ' => 'ᾣ',
'ᾤ' => 'ᾤ',
'ᾥ' => 'ᾥ',
'ᾦ' => 'ᾦ',
'ᾧ' => 'ᾧ',
'ᾨ' => 'ᾨ',
'ᾩ' => 'ᾩ',
'ᾪ' => 'ᾪ',
'ᾫ' => 'ᾫ',
'ᾬ' => 'ᾬ',
'ᾭ' => 'ᾭ',
'ᾮ' => 'ᾮ',
'ᾯ' => 'ᾯ',
'ᾰ' => 'ᾰ',
'ᾱ' => 'ᾱ',
'ᾲ' => 'ᾲ',
'ᾳ' => 'ᾳ',
'ᾴ' => 'ᾴ',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾷ',
'Ᾰ' => 'Ᾰ',
'Ᾱ' => 'Ᾱ',
'Ὰ' => 'Ὰ',
'ᾼ' => 'ᾼ',
'῁' => '῁',
'ῂ' => 'ῂ',
'ῃ' => 'ῃ',
'ῄ' => 'ῄ',
'ῆ' => 'ῆ',
'ῇ' => 'ῇ',
'Ὲ' => 'Ὲ',
'Ὴ' => 'Ὴ',
'ῌ' => 'ῌ',
'῍' => '῍',
'῎' => '῎',
'῏' => '῏',
'ῐ' => 'ῐ',
'ῑ' => 'ῑ',
'ῒ' => 'ῒ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'Ῐ' => 'Ῐ',
'Ῑ' => 'Ῑ',
'Ὶ' => 'Ὶ',
'῝' => '῝',
'῞' => '῞',
'῟' => '῟',
'ῠ' => 'ῠ',
'ῡ' => 'ῡ',
'ῢ' => 'ῢ',
'ῤ' => 'ῤ',
'ῥ' => 'ῥ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'Ῠ' => 'Ῠ',
'Ῡ' => 'Ῡ',
'Ὺ' => 'Ὺ',
'Ῥ' => 'Ῥ',
'῭' => '῭',
'ῲ' => 'ῲ',
'ῳ' => 'ῳ',
'ῴ' => 'ῴ',
'ῶ' => 'ῶ',
'ῷ' => 'ῷ',
'Ὸ' => 'Ὸ',
'Ὼ' => 'Ὼ',
'ῼ' => 'ῼ',
'↚' => '↚',
'↛' => '↛',
'↮' => '↮',
'⇍' => '⇍',
'⇎' => '⇎',
'⇏' => '⇏',
'∄' => '∄',
'∉' => '∉',
'∌' => '∌',
'∤' => '∤',
'∦' => '∦',
'≁' => '≁',
'≄' => '≄',
'≇' => '≇',
'≉' => '≉',
'≠' => '≠',
'≢' => '≢',
'≭' => '≭',
'≮' => '≮',
'≯' => '≯',
'≰' => '≰',
'≱' => '≱',
'≴' => '≴',
'≵' => '≵',
'≸' => '≸',
'≹' => '≹',
'⊀' => '⊀',
'⊁' => '⊁',
'⊄' => '⊄',
'⊅' => '⊅',
'⊈' => '⊈',
'⊉' => '⊉',
'⊬' => '⊬',
'⊭' => '⊭',
'⊮' => '⊮',
'⊯' => '⊯',
'⋠' => '⋠',
'⋡' => '⋡',
'⋢' => '⋢',
'⋣' => '⋣',
'⋪' => '⋪',
'⋫' => '⋫',
'⋬' => '⋬',
'⋭' => '⋭',
'が' => 'が',
'ぎ' => 'ぎ',
'ぐ' => 'ぐ',
'げ' => 'げ',
'ご' => 'ご',
'ざ' => 'ざ',
'じ' => 'じ',
'ず' => 'ず',
'ぜ' => 'ぜ',
'ぞ' => 'ぞ',
'だ' => 'だ',
'ぢ' => 'ぢ',
'づ' => 'づ',
'で' => 'で',
'ど' => 'ど',
'ば' => 'ば',
'ぱ' => 'ぱ',
'び' => 'び',
'ぴ' => 'ぴ',
'ぶ' => 'ぶ',
'ぷ' => 'ぷ',
'べ' => 'べ',
'ぺ' => 'ぺ',
'ぼ' => 'ぼ',
'ぽ' => 'ぽ',
'ゔ' => 'ゔ',
'ゞ' => 'ゞ',
'ガ' => 'ガ',
'ギ' => 'ギ',
'グ' => 'グ',
'ゲ' => 'ゲ',
'ゴ' => 'ゴ',
'ザ' => 'ザ',
'ジ' => 'ジ',
'ズ' => 'ズ',
'ゼ' => 'ゼ',
'ゾ' => 'ゾ',
'ダ' => 'ダ',
'ヂ' => 'ヂ',
'ヅ' => 'ヅ',
'デ' => 'デ',
'ド' => 'ド',
'バ' => 'バ',
'パ' => 'パ',
'ビ' => 'ビ',
'ピ' => 'ピ',
'ブ' => 'ブ',
'プ' => 'プ',
'ベ' => 'ベ',
'ペ' => 'ペ',
'ボ' => 'ボ',
'ポ' => 'ポ',
'ヴ' => 'ヴ',
'ヷ' => 'ヷ',
'ヸ' => 'ヸ',
'ヹ' => 'ヹ',
'ヺ' => 'ヺ',
'ヾ' => 'ヾ',
'𑂚' => '𑂚',
'𑂜' => '𑂜',
'𑂫' => '𑂫',
'𑄮' => '𑄮',
'𑄯' => '𑄯',
'𑍋' => '𑍋',
'𑍌' => '𑍌',
'𑒻' => '𑒻',
'𑒼' => '𑒼',
'𑒾' => '𑒾',
'𑖺' => '𑖺',
'𑖻' => '𑖻',
'𑤸' => '𑤸',
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,876 @@
<?php
return array (
'̀' => 230,
'́' => 230,
'̂' => 230,
'̃' => 230,
'̄' => 230,
'̅' => 230,
'̆' => 230,
'̇' => 230,
'̈' => 230,
'̉' => 230,
'̊' => 230,
'̋' => 230,
'̌' => 230,
'̍' => 230,
'̎' => 230,
'̏' => 230,
'̐' => 230,
'̑' => 230,
'̒' => 230,
'̓' => 230,
'̔' => 230,
'̕' => 232,
'̖' => 220,
'̗' => 220,
'̘' => 220,
'̙' => 220,
'̚' => 232,
'̛' => 216,
'̜' => 220,
'̝' => 220,
'̞' => 220,
'̟' => 220,
'̠' => 220,
'̡' => 202,
'̢' => 202,
'̣' => 220,
'̤' => 220,
'̥' => 220,
'̦' => 220,
'̧' => 202,
'̨' => 202,
'̩' => 220,
'̪' => 220,
'̫' => 220,
'̬' => 220,
'̭' => 220,
'̮' => 220,
'̯' => 220,
'̰' => 220,
'̱' => 220,
'̲' => 220,
'̳' => 220,
'̴' => 1,
'̵' => 1,
'̶' => 1,
'̷' => 1,
'̸' => 1,
'̹' => 220,
'̺' => 220,
'̻' => 220,
'̼' => 220,
'̽' => 230,
'̾' => 230,
'̿' => 230,
'̀' => 230,
'́' => 230,
'͂' => 230,
'̓' => 230,
'̈́' => 230,
'ͅ' => 240,
'͆' => 230,
'͇' => 220,
'͈' => 220,
'͉' => 220,
'͊' => 230,
'͋' => 230,
'͌' => 230,
'͍' => 220,
'͎' => 220,
'͐' => 230,
'͑' => 230,
'͒' => 230,
'͓' => 220,
'͔' => 220,
'͕' => 220,
'͖' => 220,
'͗' => 230,
'͘' => 232,
'͙' => 220,
'͚' => 220,
'͛' => 230,
'͜' => 233,
'͝' => 234,
'͞' => 234,
'͟' => 233,
'͠' => 234,
'͡' => 234,
'͢' => 233,
'ͣ' => 230,
'ͤ' => 230,
'ͥ' => 230,
'ͦ' => 230,
'ͧ' => 230,
'ͨ' => 230,
'ͩ' => 230,
'ͪ' => 230,
'ͫ' => 230,
'ͬ' => 230,
'ͭ' => 230,
'ͮ' => 230,
'ͯ' => 230,
'҃' => 230,
'҄' => 230,
'҅' => 230,
'҆' => 230,
'҇' => 230,
'֑' => 220,
'֒' => 230,
'֓' => 230,
'֔' => 230,
'֕' => 230,
'֖' => 220,
'֗' => 230,
'֘' => 230,
'֙' => 230,
'֚' => 222,
'֛' => 220,
'֜' => 230,
'֝' => 230,
'֞' => 230,
'֟' => 230,
'֠' => 230,
'֡' => 230,
'֢' => 220,
'֣' => 220,
'֤' => 220,
'֥' => 220,
'֦' => 220,
'֧' => 220,
'֨' => 230,
'֩' => 230,
'֪' => 220,
'֫' => 230,
'֬' => 230,
'֭' => 222,
'֮' => 228,
'֯' => 230,
'ְ' => 10,
'ֱ' => 11,
'ֲ' => 12,
'ֳ' => 13,
'ִ' => 14,
'ֵ' => 15,
'ֶ' => 16,
'ַ' => 17,
'ָ' => 18,
'ֹ' => 19,
'ֺ' => 19,
'ֻ' => 20,
'ּ' => 21,
'ֽ' => 22,
'ֿ' => 23,
'ׁ' => 24,
'ׂ' => 25,
'ׄ' => 230,
'ׅ' => 220,
'ׇ' => 18,
'ؐ' => 230,
'ؑ' => 230,
'ؒ' => 230,
'ؓ' => 230,
'ؔ' => 230,
'ؕ' => 230,
'ؖ' => 230,
'ؗ' => 230,
'ؘ' => 30,
'ؙ' => 31,
'ؚ' => 32,
'ً' => 27,
'ٌ' => 28,
'ٍ' => 29,
'َ' => 30,
'ُ' => 31,
'ِ' => 32,
'ّ' => 33,
'ْ' => 34,
'ٓ' => 230,
'ٔ' => 230,
'ٕ' => 220,
'ٖ' => 220,
'ٗ' => 230,
'٘' => 230,
'ٙ' => 230,
'ٚ' => 230,
'ٛ' => 230,
'ٜ' => 220,
'ٝ' => 230,
'ٞ' => 230,
'ٟ' => 220,
'ٰ' => 35,
'ۖ' => 230,
'ۗ' => 230,
'ۘ' => 230,
'ۙ' => 230,
'ۚ' => 230,
'ۛ' => 230,
'ۜ' => 230,
'۟' => 230,
'۠' => 230,
'ۡ' => 230,
'ۢ' => 230,
'ۣ' => 220,
'ۤ' => 230,
'ۧ' => 230,
'ۨ' => 230,
'۪' => 220,
'۫' => 230,
'۬' => 230,
'ۭ' => 220,
'ܑ' => 36,
'ܰ' => 230,
'ܱ' => 220,
'ܲ' => 230,
'ܳ' => 230,
'ܴ' => 220,
'ܵ' => 230,
'ܶ' => 230,
'ܷ' => 220,
'ܸ' => 220,
'ܹ' => 220,
'ܺ' => 230,
'ܻ' => 220,
'ܼ' => 220,
'ܽ' => 230,
'ܾ' => 220,
'ܿ' => 230,
'݀' => 230,
'݁' => 230,
'݂' => 220,
'݃' => 230,
'݄' => 220,
'݅' => 230,
'݆' => 220,
'݇' => 230,
'݈' => 220,
'݉' => 230,
'݊' => 230,
'߫' => 230,
'߬' => 230,
'߭' => 230,
'߮' => 230,
'߯' => 230,
'߰' => 230,
'߱' => 230,
'߲' => 220,
'߳' => 230,
'߽' => 220,
'ࠖ' => 230,
'ࠗ' => 230,
'࠘' => 230,
'࠙' => 230,
'ࠛ' => 230,
'ࠜ' => 230,
'ࠝ' => 230,
'ࠞ' => 230,
'ࠟ' => 230,
'ࠠ' => 230,
'ࠡ' => 230,
'ࠢ' => 230,
'ࠣ' => 230,
'ࠥ' => 230,
'ࠦ' => 230,
'ࠧ' => 230,
'ࠩ' => 230,
'ࠪ' => 230,
'ࠫ' => 230,
'ࠬ' => 230,
'࠭' => 230,
'࡙' => 220,
'࡚' => 220,
'࡛' => 220,
'࣓' => 220,
'ࣔ' => 230,
'ࣕ' => 230,
'ࣖ' => 230,
'ࣗ' => 230,
'ࣘ' => 230,
'ࣙ' => 230,
'ࣚ' => 230,
'ࣛ' => 230,
'ࣜ' => 230,
'ࣝ' => 230,
'ࣞ' => 230,
'ࣟ' => 230,
'࣠' => 230,
'࣡' => 230,
'ࣣ' => 220,
'ࣤ' => 230,
'ࣥ' => 230,
'ࣦ' => 220,
'ࣧ' => 230,
'ࣨ' => 230,
'ࣩ' => 220,
'࣪' => 230,
'࣫' => 230,
'࣬' => 230,
'࣭' => 220,
'࣮' => 220,
'࣯' => 220,
'ࣰ' => 27,
'ࣱ' => 28,
'ࣲ' => 29,
'ࣳ' => 230,
'ࣴ' => 230,
'ࣵ' => 230,
'ࣶ' => 220,
'ࣷ' => 230,
'ࣸ' => 230,
'ࣹ' => 220,
'ࣺ' => 220,
'ࣻ' => 230,
'ࣼ' => 230,
'ࣽ' => 230,
'ࣾ' => 230,
'ࣿ' => 230,
'़' => 7,
'्' => 9,
'॑' => 230,
'॒' => 220,
'॓' => 230,
'॔' => 230,
'়' => 7,
'্' => 9,
'৾' => 230,
'਼' => 7,
'੍' => 9,
'઼' => 7,
'્' => 9,
'଼' => 7,
'୍' => 9,
'்' => 9,
'్' => 9,
'ౕ' => 84,
'ౖ' => 91,
'಼' => 7,
'್' => 9,
'഻' => 9,
'഼' => 9,
'്' => 9,
'්' => 9,
'ุ' => 103,
'ู' => 103,
'ฺ' => 9,
'่' => 107,
'้' => 107,
'๊' => 107,
'๋' => 107,
'ຸ' => 118,
'ູ' => 118,
'຺' => 9,
'່' => 122,
'້' => 122,
'໊' => 122,
'໋' => 122,
'༘' => 220,
'༙' => 220,
'༵' => 220,
'༷' => 220,
'༹' => 216,
'ཱ' => 129,
'ི' => 130,
'ུ' => 132,
'ེ' => 130,
'ཻ' => 130,
'ོ' => 130,
'ཽ' => 130,
'ྀ' => 130,
'ྂ' => 230,
'ྃ' => 230,
'྄' => 9,
'྆' => 230,
'྇' => 230,
'࿆' => 220,
'့' => 7,
'္' => 9,
'်' => 9,
'ႍ' => 220,
'፝' => 230,
'፞' => 230,
'፟' => 230,
'᜔' => 9,
'᜴' => 9,
'្' => 9,
'៝' => 230,
'ᢩ' => 228,
'᤹' => 222,
'᤺' => 230,
'᤻' => 220,
'ᨗ' => 230,
'ᨘ' => 220,
'᩠' => 9,
'᩵' => 230,
'᩶' => 230,
'᩷' => 230,
'᩸' => 230,
'᩹' => 230,
'᩺' => 230,
'᩻' => 230,
'᩼' => 230,
'᩿' => 220,
'᪰' => 230,
'᪱' => 230,
'᪲' => 230,
'᪳' => 230,
'᪴' => 230,
'᪵' => 220,
'᪶' => 220,
'᪷' => 220,
'᪸' => 220,
'᪹' => 220,
'᪺' => 220,
'᪻' => 230,
'᪼' => 230,
'᪽' => 220,
'ᪿ' => 220,
'ᫀ' => 220,
'᬴' => 7,
'᭄' => 9,
'᭫' => 230,
'᭬' => 220,
'᭭' => 230,
'᭮' => 230,
'᭯' => 230,
'᭰' => 230,
'᭱' => 230,
'᭲' => 230,
'᭳' => 230,
'᮪' => 9,
'᮫' => 9,
'᯦' => 7,
'᯲' => 9,
'᯳' => 9,
'᰷' => 7,
'᳐' => 230,
'᳑' => 230,
'᳒' => 230,
'᳔' => 1,
'᳕' => 220,
'᳖' => 220,
'᳗' => 220,
'᳘' => 220,
'᳙' => 220,
'᳚' => 230,
'᳛' => 230,
'᳜' => 220,
'᳝' => 220,
'᳞' => 220,
'᳟' => 220,
'᳠' => 230,
'᳢' => 1,
'᳣' => 1,
'᳤' => 1,
'᳥' => 1,
'᳦' => 1,
'᳧' => 1,
'᳨' => 1,
'᳭' => 220,
'᳴' => 230,
'᳸' => 230,
'᳹' => 230,
'᷀' => 230,
'᷁' => 230,
'᷂' => 220,
'᷃' => 230,
'᷄' => 230,
'᷅' => 230,
'᷆' => 230,
'᷇' => 230,
'᷈' => 230,
'᷉' => 230,
'᷊' => 220,
'᷋' => 230,
'᷌' => 230,
'᷍' => 234,
'᷎' => 214,
'᷏' => 220,
'᷐' => 202,
'᷑' => 230,
'᷒' => 230,
'ᷓ' => 230,
'ᷔ' => 230,
'ᷕ' => 230,
'ᷖ' => 230,
'ᷗ' => 230,
'ᷘ' => 230,
'ᷙ' => 230,
'ᷚ' => 230,
'ᷛ' => 230,
'ᷜ' => 230,
'ᷝ' => 230,
'ᷞ' => 230,
'ᷟ' => 230,
'ᷠ' => 230,
'ᷡ' => 230,
'ᷢ' => 230,
'ᷣ' => 230,
'ᷤ' => 230,
'ᷥ' => 230,
'ᷦ' => 230,
'ᷧ' => 230,
'ᷨ' => 230,
'ᷩ' => 230,
'ᷪ' => 230,
'ᷫ' => 230,
'ᷬ' => 230,
'ᷭ' => 230,
'ᷮ' => 230,
'ᷯ' => 230,
'ᷰ' => 230,
'ᷱ' => 230,
'ᷲ' => 230,
'ᷳ' => 230,
'ᷴ' => 230,
'᷵' => 230,
'᷶' => 232,
'᷷' => 228,
'᷸' => 228,
'᷹' => 220,
'᷻' => 230,
'᷼' => 233,
'᷽' => 220,
'᷾' => 230,
'᷿' => 220,
'⃐' => 230,
'⃑' => 230,
'⃒' => 1,
'⃓' => 1,
'⃔' => 230,
'⃕' => 230,
'⃖' => 230,
'⃗' => 230,
'⃘' => 1,
'⃙' => 1,
'⃚' => 1,
'⃛' => 230,
'⃜' => 230,
'⃡' => 230,
'⃥' => 1,
'⃦' => 1,
'⃧' => 230,
'⃨' => 220,
'⃩' => 230,
'⃪' => 1,
'⃫' => 1,
'⃬' => 220,
'⃭' => 220,
'⃮' => 220,
'⃯' => 220,
'⃰' => 230,
'⳯' => 230,
'⳰' => 230,
'⳱' => 230,
'⵿' => 9,
'ⷠ' => 230,
'ⷡ' => 230,
'ⷢ' => 230,
'ⷣ' => 230,
'ⷤ' => 230,
'ⷥ' => 230,
'ⷦ' => 230,
'ⷧ' => 230,
'ⷨ' => 230,
'ⷩ' => 230,
'ⷪ' => 230,
'ⷫ' => 230,
'ⷬ' => 230,
'ⷭ' => 230,
'ⷮ' => 230,
'ⷯ' => 230,
'ⷰ' => 230,
'ⷱ' => 230,
'ⷲ' => 230,
'ⷳ' => 230,
'ⷴ' => 230,
'ⷵ' => 230,
'ⷶ' => 230,
'ⷷ' => 230,
'ⷸ' => 230,
'ⷹ' => 230,
'ⷺ' => 230,
'ⷻ' => 230,
'ⷼ' => 230,
'ⷽ' => 230,
'ⷾ' => 230,
'ⷿ' => 230,
'〪' => 218,
'〫' => 228,
'〬' => 232,
'〭' => 222,
'〮' => 224,
'〯' => 224,
'゙' => 8,
'゚' => 8,
'꙯' => 230,
'ꙴ' => 230,
'ꙵ' => 230,
'ꙶ' => 230,
'ꙷ' => 230,
'ꙸ' => 230,
'ꙹ' => 230,
'ꙺ' => 230,
'ꙻ' => 230,
'꙼' => 230,
'꙽' => 230,
'ꚞ' => 230,
'ꚟ' => 230,
'꛰' => 230,
'꛱' => 230,
'꠆' => 9,
'꠬' => 9,
'꣄' => 9,
'꣠' => 230,
'꣡' => 230,
'꣢' => 230,
'꣣' => 230,
'꣤' => 230,
'꣥' => 230,
'꣦' => 230,
'꣧' => 230,
'꣨' => 230,
'꣩' => 230,
'꣪' => 230,
'꣫' => 230,
'꣬' => 230,
'꣭' => 230,
'꣮' => 230,
'꣯' => 230,
'꣰' => 230,
'꣱' => 230,
'꤫' => 220,
'꤬' => 220,
'꤭' => 220,
'꥓' => 9,
'꦳' => 7,
'꧀' => 9,
'ꪰ' => 230,
'ꪲ' => 230,
'ꪳ' => 230,
'ꪴ' => 220,
'ꪷ' => 230,
'ꪸ' => 230,
'ꪾ' => 230,
'꪿' => 230,
'꫁' => 230,
'꫶' => 9,
'꯭' => 9,
'ﬞ' => 26,
'︠' => 230,
'︡' => 230,
'︢' => 230,
'︣' => 230,
'︤' => 230,
'︥' => 230,
'︦' => 230,
'︧' => 220,
'︨' => 220,
'︩' => 220,
'︪' => 220,
'︫' => 220,
'︬' => 220,
'︭' => 220,
'︮' => 230,
'︯' => 230,
'𐇽' => 220,
'𐋠' => 220,
'𐍶' => 230,
'𐍷' => 230,
'𐍸' => 230,
'𐍹' => 230,
'𐍺' => 230,
'𐨍' => 220,
'𐨏' => 230,
'𐨸' => 230,
'𐨹' => 1,
'𐨺' => 220,
'𐨿' => 9,
'𐫥' => 230,
'𐫦' => 220,
'𐴤' => 230,
'𐴥' => 230,
'𐴦' => 230,
'𐴧' => 230,
'𐺫' => 230,
'𐺬' => 230,
'𐽆' => 220,
'𐽇' => 220,
'𐽈' => 230,
'𐽉' => 230,
'𐽊' => 230,
'𐽋' => 220,
'𐽌' => 230,
'𐽍' => 220,
'𐽎' => 220,
'𐽏' => 220,
'𐽐' => 220,
'𑁆' => 9,
'𑁿' => 9,
'𑂹' => 9,
'𑂺' => 7,
'𑄀' => 230,
'𑄁' => 230,
'𑄂' => 230,
'𑄳' => 9,
'𑄴' => 9,
'𑅳' => 7,
'𑇀' => 9,
'𑇊' => 7,
'𑈵' => 9,
'𑈶' => 7,
'𑋩' => 7,
'𑋪' => 9,
'𑌻' => 7,
'𑌼' => 7,
'𑍍' => 9,
'𑍦' => 230,
'𑍧' => 230,
'𑍨' => 230,
'𑍩' => 230,
'𑍪' => 230,
'𑍫' => 230,
'𑍬' => 230,
'𑍰' => 230,
'𑍱' => 230,
'𑍲' => 230,
'𑍳' => 230,
'𑍴' => 230,
'𑑂' => 9,
'𑑆' => 7,
'𑑞' => 230,
'𑓂' => 9,
'𑓃' => 7,
'𑖿' => 9,
'𑗀' => 7,
'𑘿' => 9,
'𑚶' => 9,
'𑚷' => 7,
'𑜫' => 9,
'𑠹' => 9,
'𑠺' => 7,
'𑤽' => 9,
'𑤾' => 9,
'𑥃' => 7,
'𑧠' => 9,
'𑨴' => 9,
'𑩇' => 9,
'𑪙' => 9,
'𑰿' => 9,
'𑵂' => 7,
'𑵄' => 9,
'𑵅' => 9,
'𑶗' => 9,
'𖫰' => 1,
'𖫱' => 1,
'𖫲' => 1,
'𖫳' => 1,
'𖫴' => 1,
'𖬰' => 230,
'𖬱' => 230,
'𖬲' => 230,
'𖬳' => 230,
'𖬴' => 230,
'𖬵' => 230,
'𖬶' => 230,
'𖿰' => 6,
'𖿱' => 6,
'𛲞' => 1,
'𝅥' => 216,
'𝅦' => 216,
'𝅧' => 1,
'𝅨' => 1,
'𝅩' => 1,
'𝅭' => 226,
'𝅮' => 216,
'𝅯' => 216,
'𝅰' => 216,
'𝅱' => 216,
'𝅲' => 216,
'𝅻' => 220,
'𝅼' => 220,
'𝅽' => 220,
'𝅾' => 220,
'𝅿' => 220,
'𝆀' => 220,
'𝆁' => 220,
'𝆂' => 220,
'𝆅' => 230,
'𝆆' => 230,
'𝆇' => 230,
'𝆈' => 230,
'𝆉' => 230,
'𝆊' => 220,
'𝆋' => 220,
'𝆪' => 230,
'𝆫' => 230,
'𝆬' => 230,
'𝆭' => 230,
'𝉂' => 230,
'𝉃' => 230,
'𝉄' => 230,
'𞀀' => 230,
'𞀁' => 230,
'𞀂' => 230,
'𞀃' => 230,
'𞀄' => 230,
'𞀅' => 230,
'𞀆' => 230,
'𞀈' => 230,
'𞀉' => 230,
'𞀊' => 230,
'𞀋' => 230,
'𞀌' => 230,
'𞀍' => 230,
'𞀎' => 230,
'𞀏' => 230,
'𞀐' => 230,
'𞀑' => 230,
'𞀒' => 230,
'𞀓' => 230,
'𞀔' => 230,
'𞀕' => 230,
'𞀖' => 230,
'𞀗' => 230,
'𞀘' => 230,
'𞀛' => 230,
'𞀜' => 230,
'𞀝' => 230,
'𞀞' => 230,
'𞀟' => 230,
'𞀠' => 230,
'𞀡' => 230,
'𞀣' => 230,
'𞀤' => 230,
'𞀦' => 230,
'𞀧' => 230,
'𞀨' => 230,
'𞀩' => 230,
'𞀪' => 230,
'𞄰' => 230,
'𞄱' => 230,
'𞄲' => 230,
'𞄳' => 230,
'𞄴' => 230,
'𞄵' => 230,
'𞄶' => 230,
'𞋬' => 230,
'𞋭' => 230,
'𞋮' => 230,
'𞋯' => 230,
'𞣐' => 220,
'𞣑' => 220,
'𞣒' => 220,
'𞣓' => 220,
'𞣔' => 220,
'𞣕' => 220,
'𞣖' => 220,
'𞥄' => 230,
'𞥅' => 230,
'𞥆' => 230,
'𞥇' => 230,
'𞥈' => 230,
'𞥉' => 230,
'𞥊' => 7,
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Normalizer as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('normalizer_is_normalized')) {
function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); }
}
if (!function_exists('normalizer_normalize')) {
function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); }
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Intl\Normalizer as p;
if (!function_exists('normalizer_is_normalized')) {
function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); }
}
if (!function_exists('normalizer_normalize')) {
function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); }
}

View File

@@ -0,0 +1,39 @@
{
"name": "symfony/polyfill-intl-normalizer",
"type": "library",
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" },
"files": [ "bootstrap.php" ],
"classmap": [ "Resources/stubs" ]
},
"suggest": {
"ext-intl": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2015-2019 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,874 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Mbstring;
/**
* Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
*
* Implemented:
* - mb_chr - Returns a specific character from its Unicode code point
* - mb_convert_encoding - Convert character encoding
* - mb_convert_variables - Convert character code in variable(s)
* - mb_decode_mimeheader - Decode string in MIME header field
* - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
* - mb_decode_numericentity - Decode HTML numeric string reference to character
* - mb_encode_numericentity - Encode character to HTML numeric string reference
* - mb_convert_case - Perform case folding on a string
* - mb_detect_encoding - Detect character encoding
* - mb_get_info - Get internal settings of mbstring
* - mb_http_input - Detect HTTP input character encoding
* - mb_http_output - Set/Get HTTP output character encoding
* - mb_internal_encoding - Set/Get internal character encoding
* - mb_list_encodings - Returns an array of all supported encodings
* - mb_ord - Returns the Unicode code point of a character
* - mb_output_handler - Callback function converts character encoding in output buffer
* - mb_scrub - Replaces ill-formed byte sequences with substitute characters
* - mb_strlen - Get string length
* - mb_strpos - Find position of first occurrence of string in a string
* - mb_strrpos - Find position of last occurrence of a string in a string
* - mb_str_split - Convert a string to an array
* - mb_strtolower - Make a string lowercase
* - mb_strtoupper - Make a string uppercase
* - mb_substitute_character - Set/Get substitution character
* - mb_substr - Get part of string
* - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
* - mb_stristr - Finds first occurrence of a string within another, case insensitive
* - mb_strrchr - Finds the last occurrence of a character in a string within another
* - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
* - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
* - mb_strstr - Finds first occurrence of a string within another
* - mb_strwidth - Return width of string
* - mb_substr_count - Count the number of substring occurrences
*
* Not implemented:
* - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
* - mb_ereg_* - Regular expression with multibyte support
* - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
* - mb_preferred_mime_name - Get MIME charset string
* - mb_regex_encoding - Returns current encoding for multibyte regex as string
* - mb_regex_set_options - Set/Get the default options for mbregex functions
* - mb_send_mail - Send encoded mail
* - mb_split - Split multibyte string using regular expression
* - mb_strcut - Get part of string
* - mb_strimwidth - Get truncated string with specified width
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class Mbstring
{
public const MB_CASE_FOLD = \PHP_INT_MAX;
private const CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
];
private static $encodingList = ['ASCII', 'UTF-8'];
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
{
if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
} else {
$fromEncoding = self::getEncoding($fromEncoding);
}
$toEncoding = self::getEncoding($toEncoding);
if ('BASE64' === $fromEncoding) {
$s = base64_decode($s);
$fromEncoding = $toEncoding;
}
if ('BASE64' === $toEncoding) {
return base64_encode($s);
}
if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
$fromEncoding = 'Windows-1252';
}
if ('UTF-8' !== $fromEncoding) {
$s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
}
return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
}
if ('HTML-ENTITIES' === $fromEncoding) {
$s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
$fromEncoding = 'UTF-8';
}
return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
}
public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
{
$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
$ok = false;
}
});
return $ok ? $fromEncoding : false;
}
public static function mb_decode_mimeheader($s)
{
return iconv_mime_decode($s, 2, self::$internalEncoding);
}
public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
{
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
}
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return ''; // Instead of null (cf. mb_encode_numericentity).
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$cnt = floor(\count($convmap) / 4) * 4;
for ($i = 0; $i < $cnt; $i += 4) {
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
$convmap[$i] += $convmap[$i + 2];
$convmap[$i + 1] += $convmap[$i + 2];
}
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
for ($i = 0; $i < $cnt; $i += 4) {
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
return self::mb_chr($c - $convmap[$i + 2]);
}
}
return $m[0];
}, $s);
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null; // Instead of '' (cf. mb_decode_numericentity).
}
if (null !== $is_hex && !\is_scalar($is_hex)) {
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$cnt = floor(\count($convmap) / 4) * 4;
$i = 0;
$len = \strlen($s);
$result = '';
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
$c = self::mb_ord($uchr);
for ($j = 0; $j < $cnt; $j += 4) {
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
continue 2;
}
}
$result .= $uchr;
}
if (null === $encoding) {
return $result;
}
return iconv('UTF-8', $encoding.'//IGNORE', $result);
}
public static function mb_convert_case($s, $mode, $encoding = null)
{
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
if (\MB_CASE_TITLE == $mode) {
static $titleRegexp = null;
if (null === $titleRegexp) {
$titleRegexp = self::getData('titleCaseRegexp');
}
$s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
} else {
if (\MB_CASE_UPPER == $mode) {
static $upper = null;
if (null === $upper) {
$upper = self::getData('upperCase');
}
$map = $upper;
} else {
if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
}
static $lower = null;
if (null === $lower) {
$lower = self::getData('lowerCase');
}
$map = $lower;
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$i = 0;
$len = \strlen($s);
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
if (isset($map[$uchr])) {
$uchr = $map[$uchr];
$nlen = \strlen($uchr);
if ($nlen == $ulen) {
$nlen = $i;
do {
$s[--$nlen] = $uchr[--$ulen];
} while ($ulen);
} else {
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
$len += $nlen - $ulen;
$i += $nlen - $ulen;
}
}
}
}
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_internal_encoding($encoding = null)
{
if (null === $encoding) {
return self::$internalEncoding;
}
$normalizedEncoding = self::getEncoding($encoding);
if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
self::$internalEncoding = $normalizedEncoding;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
public static function mb_language($lang = null)
{
if (null === $lang) {
return self::$language;
}
switch ($normalizedLang = strtolower($lang)) {
case 'uni':
case 'neutral':
self::$language = $normalizedLang;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
}
public static function mb_list_encodings()
{
return ['UTF-8'];
}
public static function mb_encoding_aliases($encoding)
{
switch (strtoupper($encoding)) {
case 'UTF8':
case 'UTF-8':
return ['utf8'];
}
return false;
}
public static function mb_check_encoding($var = null, $encoding = null)
{
if (null === $encoding) {
if (null === $var) {
return false;
}
$encoding = self::$internalEncoding;
}
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
}
public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
{
if (null === $encodingList) {
$encodingList = self::$encodingList;
} else {
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
}
foreach ($encodingList as $enc) {
switch ($enc) {
case 'ASCII':
if (!preg_match('/[\x80-\xFF]/', $str)) {
return $enc;
}
break;
case 'UTF8':
case 'UTF-8':
if (preg_match('//u', $str)) {
return 'UTF-8';
}
break;
default:
if (0 === strncmp($enc, 'ISO-8859-', 9)) {
return $enc;
}
}
}
return false;
}
public static function mb_detect_order($encodingList = null)
{
if (null === $encodingList) {
return self::$encodingList;
}
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
foreach ($encodingList as $enc) {
switch ($enc) {
default:
if (strncmp($enc, 'ISO-8859-', 9)) {
return false;
}
// no break
case 'ASCII':
case 'UTF8':
case 'UTF-8':
}
}
self::$encodingList = $encodingList;
return true;
}
public static function mb_strlen($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return \strlen($s);
}
return @iconv_strlen($s, $encoding);
}
public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strpos($haystack, $needle, $offset);
}
$needle = (string) $needle;
if ('' === $needle) {
if (80000 > \PHP_VERSION_ID) {
trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
return false;
}
return 0;
}
return iconv_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strrpos($haystack, $needle, $offset);
}
if ($offset != (int) $offset) {
$offset = 0;
} elseif ($offset = (int) $offset) {
if ($offset < 0) {
if (0 > $offset += self::mb_strlen($needle)) {
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
}
$offset = 0;
} else {
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
}
}
$pos = '' !== $needle || 80000 > \PHP_VERSION_ID
? iconv_strrpos($haystack, $needle, $encoding)
: self::mb_strlen($haystack, $encoding);
return false !== $pos ? $offset + $pos : false;
}
public static function mb_str_split($string, $split_length = 1, $encoding = null)
{
if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
return null;
}
if (1 > $split_length = (int) $split_length) {
if (80000 > \PHP_VERSION_ID) {
trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
return false;
}
throw new \ValueError('Argument #2 ($length) must be greater than 0');
}
if (null === $encoding) {
$encoding = mb_internal_encoding();
}
if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
$rx = '/(';
while (65535 < $split_length) {
$rx .= '.{65535}';
$split_length -= 65535;
}
$rx .= '.{'.$split_length.'})/us';
return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
}
$result = [];
$length = mb_strlen($string, $encoding);
for ($i = 0; $i < $length; $i += $split_length) {
$result[] = mb_substr($string, $i, $split_length, $encoding);
}
return $result;
}
public static function mb_strtolower($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
}
public static function mb_strtoupper($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
}
public static function mb_substitute_character($c = null)
{
if (null === $c) {
return 'none';
}
if (0 === strcasecmp($c, 'none')) {
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
if (\is_int($c) || 'long' === $c || 'entity' === $c) {
return false;
}
throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
}
public static function mb_substr($s, $start, $length = null, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return (string) substr($s, $start, null === $length ? 2147483647 : $length);
}
if ($start < 0) {
$start = iconv_strlen($s, $encoding) + $start;
if ($start < 0) {
$start = 0;
}
}
if (null === $length) {
$length = 2147483647;
} elseif ($length < 0) {
$length = iconv_strlen($s, $encoding) + $length - $start;
if ($length < 0) {
return '';
}
}
return (string) iconv_substr($s, $start, $length, $encoding);
}
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
return self::mb_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
{
$pos = self::mb_stripos($haystack, $needle, 0, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
$pos = strrpos($haystack, $needle);
} else {
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = iconv_strrpos($haystack, $needle, $encoding);
}
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
{
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = self::mb_strripos($haystack, $needle, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
return self::mb_strrpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
{
$pos = strpos($haystack, $needle);
if (false === $pos) {
return false;
}
if ($part) {
return substr($haystack, 0, $pos);
}
return substr($haystack, $pos);
}
public static function mb_get_info($type = 'all')
{
$info = [
'internal_encoding' => self::$internalEncoding,
'http_output' => 'pass',
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
'func_overload' => 0,
'func_overload_list' => 'no overload',
'mail_charset' => 'UTF-8',
'mail_header_encoding' => 'BASE64',
'mail_body_encoding' => 'BASE64',
'illegal_chars' => 0,
'encoding_translation' => 'Off',
'language' => self::$language,
'detect_order' => self::$encodingList,
'substitute_character' => 'none',
'strict_detection' => 'Off',
];
if ('all' === $type) {
return $info;
}
if (isset($info[$type])) {
return $info[$type];
}
return false;
}
public static function mb_http_input($type = '')
{
return false;
}
public static function mb_http_output($encoding = null)
{
return null !== $encoding ? 'pass' === $encoding : 'pass';
}
public static function mb_strwidth($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('UTF-8' !== $encoding) {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
return ($wide << 1) + iconv_strlen($s, 'UTF-8');
}
public static function mb_substr_count($haystack, $needle, $encoding = null)
{
return substr_count($haystack, $needle);
}
public static function mb_output_handler($contents, $status)
{
return $contents;
}
public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}
return $s;
}
public static function mb_ord($s, $encoding = null)
{
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}
if (1 === \strlen($s)) {
return \ord($s);
}
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}
return $code;
}
private static function getSubpart($pos, $part, $haystack, $encoding)
{
if (false === $pos) {
return false;
}
if ($part) {
return self::mb_substr($haystack, 0, $pos, $encoding);
}
return self::mb_substr($haystack, $pos, null, $encoding);
}
private static function html_encoding_callback(array $m)
{
$i = 1;
$entities = '';
$m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
while (isset($m[$i])) {
if (0x80 > $m[$i]) {
$entities .= \chr($m[$i++]);
continue;
}
if (0xF0 <= $m[$i]) {
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} elseif (0xE0 <= $m[$i]) {
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} else {
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
}
$entities .= '&#'.$c.';';
}
return $entities;
}
private static function title_case(array $s)
{
return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
}
private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}
return false;
}
private static function getEncoding($encoding)
{
if (null === $encoding) {
return self::$internalEncoding;
}
if ('UTF-8' === $encoding) {
return 'UTF-8';
}
$encoding = strtoupper($encoding);
if ('8BIT' === $encoding || 'BINARY' === $encoding) {
return 'CP850';
}
if ('UTF8' === $encoding) {
return 'UTF-8';
}
return $encoding;
}
}

View File

@@ -0,0 +1,13 @@
Symfony Polyfill / Mbstring
===========================
This component provides a partial, native PHP implementation for the
[Mbstring](https://php.net/mbstring) extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language($language = null) { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

View File

@@ -0,0 +1,143 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

View File

@@ -0,0 +1,41 @@
{
"name": "symfony/polyfill-mbstring",
"type": "library",
"description": "Symfony polyfill for the Mbstring extension",
"keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-mbstring": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

19
vendor/symfony/polyfill-php72/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2015-2019 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

217
vendor/symfony/polyfill-php72/Php72.php vendored Normal file
View File

@@ -0,0 +1,217 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php72;
/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @internal
*/
final class Php72
{
private static $hashMask;
public static function utf8_encode($s)
{
$s .= $s;
$len = \strlen($s);
for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
switch (true) {
case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
}
}
return substr($s, 0, $j);
}
public static function utf8_decode($s)
{
$s = (string) $s;
$len = \strlen($s);
for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
switch ($s[$i] & "\xF0") {
case "\xC0":
case "\xD0":
$c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
$s[$j] = $c < 256 ? \chr($c) : '?';
break;
case "\xF0":
++$i;
// no break
case "\xE0":
$s[$j] = '?';
$i += 2;
break;
default:
$s[$j] = $s[$i];
}
}
return substr($s, 0, $j);
}
public static function php_os_family()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
return 'Windows';
}
$map = [
'Darwin' => 'Darwin',
'DragonFly' => 'BSD',
'FreeBSD' => 'BSD',
'NetBSD' => 'BSD',
'OpenBSD' => 'BSD',
'Linux' => 'Linux',
'SunOS' => 'Solaris',
];
return $map[\PHP_OS] ?? 'Unknown';
}
public static function spl_object_id($object)
{
if (null === self::$hashMask) {
self::initHashMask();
}
if (null === $hash = spl_object_hash($object)) {
return;
}
// On 32-bit systems, PHP_INT_SIZE is 4,
return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1));
}
public static function sapi_windows_vt100_support($stream, $enable = null)
{
if (!\is_resource($stream)) {
trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);
return false;
}
$meta = stream_get_meta_data($stream);
if ('STDIO' !== $meta['stream_type']) {
trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING);
return false;
}
// We cannot actually disable vt100 support if it is set
if (false === $enable || !self::stream_isatty($stream)) {
return false;
}
// The native function does not apply to stdin
$meta = array_map('strtolower', $meta);
$stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];
return !$stdin
&& (false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM')
|| 'Hyper' === getenv('TERM_PROGRAM'));
}
public static function stream_isatty($stream)
{
if (!\is_resource($stream)) {
trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);
return false;
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$stat = @fstat($stream);
// Check if formatted mode is S_IFCHR
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
return \function_exists('posix_isatty') && @posix_isatty($stream);
}
private static function initHashMask()
{
$obj = (object) [];
self::$hashMask = -1;
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
$obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'];
foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
$frame['line'] = 0;
break;
}
}
if (!empty($frame['line'])) {
ob_start();
debug_zval_dump($obj);
self::$hashMask = (int) substr(ob_get_clean(), 17);
}
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1));
}
public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}
if ('UTF-8' !== $encoding = $encoding ?? mb_internal_encoding()) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}
return $s;
}
public static function mb_ord($s, $encoding = null)
{
if (null === $encoding) {
$s = mb_convert_encoding($s, 'UTF-8');
} elseif ('UTF-8' !== $encoding) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}
if (1 === \strlen($s)) {
return \ord($s);
}
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}
return $code;
}
}

35
vendor/symfony/polyfill-php72/README.md vendored Normal file
View File

@@ -0,0 +1,35 @@
Symfony Polyfill / Php72
========================
This component provides functions added to PHP 7.2 core:
- [`spl_object_id`](https://php.net/spl_object_id)
- [`stream_isatty`](https://php.net/stream_isatty)
And also functions added to PHP 7.2 mbstring:
- [`mb_ord`](https://php.net/mb_ord)
- [`mb_chr`](https://php.net/mb_chr)
- [`mb_scrub`](https://php.net/mb_scrub)
On Windows only:
- [`sapi_windows_vt100_support`](https://php.net/sapi_windows_vt100_support)
Moved to core since 7.2 (was in the optional XML extension earlier):
- [`utf8_encode`](https://php.net/utf8_encode)
- [`utf8_decode`](https://php.net/utf8_decode)
Also, it provides constants added to PHP 7.2:
- [`PHP_FLOAT_*`](https://php.net/reserved.constants#constant.php-float-dig)
- [`PHP_OS_FAMILY`](https://php.net/reserved.constants#constant.php-os-family)
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Php72 as p;
if (\PHP_VERSION_ID >= 70200) {
return;
}
if (!defined('PHP_FLOAT_DIG')) {
define('PHP_FLOAT_DIG', 15);
}
if (!defined('PHP_FLOAT_EPSILON')) {
define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
}
if (!defined('PHP_FLOAT_MIN')) {
define('PHP_FLOAT_MIN', 2.2250738585072E-308);
}
if (!defined('PHP_FLOAT_MAX')) {
define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
}
if (!defined('PHP_OS_FAMILY')) {
define('PHP_OS_FAMILY', p\Php72::php_os_family());
}
if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) {
function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); }
}
if (!function_exists('stream_isatty')) {
function stream_isatty($stream) { return p\Php72::stream_isatty($stream); }
}
if (!function_exists('utf8_encode')) {
function utf8_encode($string) { return p\Php72::utf8_encode($string); }
}
if (!function_exists('utf8_decode')) {
function utf8_decode($string) { return p\Php72::utf8_decode($string); }
}
if (!function_exists('spl_object_id')) {
function spl_object_id($object) { return p\Php72::spl_object_id($object); }
}
if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}

View File

@@ -0,0 +1,35 @@
{
"name": "symfony/polyfill-php72",
"type": "library",
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"keywords": ["polyfill", "shim", "compatibility", "portable"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Php72\\": "" },
"files": [ "bootstrap.php" ]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

19
vendor/symfony/polyfill-php80/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2020 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

115
vendor/symfony/polyfill-php80/Php80.php vendored Normal file
View File

@@ -0,0 +1,115 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php80;
/**
* @author Ion Bazan <ion.bazan@gmail.com>
* @author Nico Oelgart <nicoswd@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class Php80
{
public static function fdiv(float $dividend, float $divisor): float
{
return @($dividend / $divisor);
}
public static function get_debug_type($value): string
{
switch (true) {
case null === $value: return 'null';
case \is_bool($value): return 'bool';
case \is_string($value): return 'string';
case \is_array($value): return 'array';
case \is_int($value): return 'int';
case \is_float($value): return 'float';
case \is_object($value): break;
case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
default:
if (null === $type = @get_resource_type($value)) {
return 'unknown';
}
if ('Unknown' === $type) {
$type = 'closed';
}
return "resource ($type)";
}
$class = \get_class($value);
if (false === strpos($class, '@')) {
return $class;
}
return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
}
public static function get_resource_id($res): int
{
if (!\is_resource($res) && null === @get_resource_type($res)) {
throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
}
return (int) $res;
}
public static function preg_last_error_msg(): string
{
switch (preg_last_error()) {
case \PREG_INTERNAL_ERROR:
return 'Internal error';
case \PREG_BAD_UTF8_ERROR:
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
case \PREG_BAD_UTF8_OFFSET_ERROR:
return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
case \PREG_BACKTRACK_LIMIT_ERROR:
return 'Backtrack limit exhausted';
case \PREG_RECURSION_LIMIT_ERROR:
return 'Recursion limit exhausted';
case \PREG_JIT_STACKLIMIT_ERROR:
return 'JIT stack limit exhausted';
case \PREG_NO_ERROR:
return 'No error';
default:
return 'Unknown error';
}
}
public static function str_contains(string $haystack, string $needle): bool
{
return '' === $needle || false !== strpos($haystack, $needle);
}
public static function str_starts_with(string $haystack, string $needle): bool
{
return 0 === strncmp($haystack, $needle, \strlen($needle));
}
public static function str_ends_with(string $haystack, string $needle): bool
{
if ('' === $needle || $needle === $haystack) {
return true;
}
if ('' === $haystack) {
return false;
}
$needleLength = \strlen($needle);
return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
}
}

View File

@@ -0,0 +1,103 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php80;
/**
* @author Fedonyuk Anton <info@ensostudio.ru>
*
* @internal
*/
class PhpToken implements \Stringable
{
/**
* @var int
*/
public $id;
/**
* @var string
*/
public $text;
/**
* @var int
*/
public $line;
/**
* @var int
*/
public $pos;
public function __construct(int $id, string $text, int $line = -1, int $position = -1)
{
$this->id = $id;
$this->text = $text;
$this->line = $line;
$this->pos = $position;
}
public function getTokenName(): ?string
{
if ('UNKNOWN' === $name = token_name($this->id)) {
$name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
}
return $name;
}
/**
* @param int|string|array $kind
*/
public function is($kind): bool
{
foreach ((array) $kind as $value) {
if (\in_array($value, [$this->id, $this->text], true)) {
return true;
}
}
return false;
}
public function isIgnorable(): bool
{
return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
}
public function __toString(): string
{
return (string) $this->text;
}
/**
* @return static[]
*/
public static function tokenize(string $code, int $flags = 0): array
{
$line = 1;
$position = 0;
$tokens = token_get_all($code, $flags);
foreach ($tokens as $index => $token) {
if (\is_string($token)) {
$id = \ord($token);
$text = $token;
} else {
[$id, $text, $line] = $token;
}
$tokens[$index] = new static($id, $text, $line, $position);
$position += \strlen($text);
}
return $tokens;
}
}

25
vendor/symfony/polyfill-php80/README.md vendored Normal file
View File

@@ -0,0 +1,25 @@
Symfony Polyfill / Php80
========================
This component provides features added to PHP 8.0 core:
- [`Stringable`](https://php.net/stringable) interface
- [`fdiv`](https://php.net/fdiv)
- [`ValueError`](https://php.net/valueerror) class
- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
- `FILTER_VALIDATE_BOOL` constant
- [`get_debug_type`](https://php.net/get_debug_type)
- [`PhpToken`](https://php.net/phptoken) class
- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
- [`str_contains`](https://php.net/str_contains)
- [`str_starts_with`](https://php.net/str_starts_with)
- [`str_ends_with`](https://php.net/str_ends_with)
- [`get_resource_id`](https://php.net/get_resource_id)
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class Attribute
{
public const TARGET_CLASS = 1;
public const TARGET_FUNCTION = 2;
public const TARGET_METHOD = 4;
public const TARGET_PROPERTY = 8;
public const TARGET_CLASS_CONSTANT = 16;
public const TARGET_PARAMETER = 32;
public const TARGET_ALL = 63;
public const IS_REPEATABLE = 64;
/** @var int */
public $flags;
public function __construct(int $flags = self::TARGET_ALL)
{
$this->flags = $flags;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
class PhpToken extends Symfony\Polyfill\Php80\PhpToken
{
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80000) {
interface Stringable
{
/**
* @return string
*/
public function __toString();
}
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80000) {
class UnhandledMatchError extends Error
{
}
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80000) {
class ValueError extends Error
{
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Php80 as p;
if (\PHP_VERSION_ID >= 80000) {
return;
}
if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
}
if (!function_exists('fdiv')) {
function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
}
if (!function_exists('preg_last_error_msg')) {
function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
}
if (!function_exists('str_contains')) {
function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_starts_with')) {
function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_ends_with')) {
function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('get_debug_type')) {
function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
}
if (!function_exists('get_resource_id')) {
function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
}

View File

@@ -0,0 +1,40 @@
{
"name": "symfony/polyfill-php80",
"type": "library",
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"keywords": ["polyfill", "shim", "compatibility", "portable"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
"files": [ "bootstrap.php" ],
"classmap": [ "Resources/stubs" ]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

53
vendor/symfony/var-dumper/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,53 @@
CHANGELOG
=========
4.4.0
-----
* added `VarDumperTestTrait::setUpVarDumper()` and `VarDumperTestTrait::tearDownVarDumper()`
to configure casters & flags to use in tests
* added `ImagineCaster` and infrastructure to dump images
* added the stamps of a message after it is dispatched in `TraceableMessageBus` and `MessengerDataCollector` collected data
* added `UuidCaster`
* made all casters final
* added support for the `NO_COLOR` env var (https://no-color.org/)
4.3.0
-----
* added `DsCaster` to support dumping the contents of data structures from the Ds extension
4.2.0
-----
* support selecting the format to use by setting the environment variable `VAR_DUMPER_FORMAT` to `html` or `cli`
4.1.0
-----
* added a `ServerDumper` to send serialized Data clones to a server
* added a `ServerDumpCommand` and `DumpServer` to run a server collecting
and displaying dumps on a single place with multiple formats support
* added `CliDescriptor` and `HtmlDescriptor` descriptors for `server:dump` CLI and HTML formats support
4.0.0
-----
* support for passing `\ReflectionClass` instances to the `Caster::castObject()`
method has been dropped, pass class names as strings instead
* the `Data::getRawData()` method has been removed
* the `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position.
* the `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position.
3.4.0
-----
* added `AbstractCloner::setMinDepth()` function to ensure minimum tree depth
* deprecated `MongoCaster`
2.7.0
-----
* deprecated `Cloner\Data::getLimitedClone()`. Use `withMaxDepth`, `withMaxItemsPerDepth` or `withRefHandles` instead.

View File

@@ -0,0 +1,212 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Amqp related classes to array representation.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*
* @final since Symfony 4.4
*/
class AmqpCaster
{
private const FLAGS = [
\AMQP_DURABLE => 'AMQP_DURABLE',
\AMQP_PASSIVE => 'AMQP_PASSIVE',
\AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE',
\AMQP_AUTODELETE => 'AMQP_AUTODELETE',
\AMQP_INTERNAL => 'AMQP_INTERNAL',
\AMQP_NOLOCAL => 'AMQP_NOLOCAL',
\AMQP_AUTOACK => 'AMQP_AUTOACK',
\AMQP_IFEMPTY => 'AMQP_IFEMPTY',
\AMQP_IFUNUSED => 'AMQP_IFUNUSED',
\AMQP_MANDATORY => 'AMQP_MANDATORY',
\AMQP_IMMEDIATE => 'AMQP_IMMEDIATE',
\AMQP_MULTIPLE => 'AMQP_MULTIPLE',
\AMQP_NOWAIT => 'AMQP_NOWAIT',
\AMQP_REQUEUE => 'AMQP_REQUEUE',
];
private const EXCHANGE_TYPES = [
\AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT',
\AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT',
\AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC',
\AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS',
];
public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += [
$prefix.'is_connected' => $c->isConnected(),
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPConnection\x00login"])) {
return $a;
}
// BC layer in the amqp lib
if (method_exists($c, 'getReadTimeout')) {
$timeout = $c->getReadTimeout();
} else {
$timeout = $c->getTimeout();
}
$a += [
$prefix.'is_connected' => $c->isConnected(),
$prefix.'login' => $c->getLogin(),
$prefix.'password' => $c->getPassword(),
$prefix.'host' => $c->getHost(),
$prefix.'vhost' => $c->getVhost(),
$prefix.'port' => $c->getPort(),
$prefix.'read_timeout' => $timeout,
];
return $a;
}
public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += [
$prefix.'is_connected' => $c->isConnected(),
$prefix.'channel_id' => $c->getChannelId(),
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPChannel\x00connection"])) {
return $a;
}
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'prefetch_size' => $c->getPrefetchSize(),
$prefix.'prefetch_count' => $c->getPrefetchCount(),
];
return $a;
}
public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += [
$prefix.'flags' => self::extractFlags($c->getFlags()),
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPQueue\x00name"])) {
return $a;
}
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'arguments' => $c->getArguments(),
];
return $a;
}
public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += [
$prefix.'flags' => self::extractFlags($c->getFlags()),
];
$type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType();
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPExchange\x00name"])) {
$a["\x00AMQPExchange\x00type"] = $type;
return $a;
}
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'type' => $type,
$prefix.'arguments' => $c->getArguments(),
];
return $a;
}
public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
$deliveryMode = new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode());
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPEnvelope\x00body"])) {
$a["\0AMQPEnvelope\0delivery_mode"] = $deliveryMode;
return $a;
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$a += [$prefix.'body' => $c->getBody()];
}
$a += [
$prefix.'delivery_tag' => $c->getDeliveryTag(),
$prefix.'is_redelivery' => $c->isRedelivery(),
$prefix.'exchange_name' => $c->getExchangeName(),
$prefix.'routing_key' => $c->getRoutingKey(),
$prefix.'content_type' => $c->getContentType(),
$prefix.'content_encoding' => $c->getContentEncoding(),
$prefix.'headers' => $c->getHeaders(),
$prefix.'delivery_mode' => $deliveryMode,
$prefix.'priority' => $c->getPriority(),
$prefix.'correlation_id' => $c->getCorrelationId(),
$prefix.'reply_to' => $c->getReplyTo(),
$prefix.'expiration' => $c->getExpiration(),
$prefix.'message_id' => $c->getMessageId(),
$prefix.'timestamp' => $c->getTimeStamp(),
$prefix.'type' => $c->getType(),
$prefix.'user_id' => $c->getUserId(),
$prefix.'app_id' => $c->getAppId(),
];
return $a;
}
private static function extractFlags(int $flags): ConstStub
{
$flagsArray = [];
foreach (self::FLAGS as $value => $name) {
if ($flags & $value) {
$flagsArray[] = $name;
}
}
if (!$flagsArray) {
$flagsArray = ['AMQP_NOPARAM'];
}
return new ConstStub(implode('|', $flagsArray), $flags);
}
}

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents a list of function arguments.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ArgsStub extends EnumStub
{
private static $parameters = [];
public function __construct(array $args, string $function, ?string $class)
{
[$variadic, $params] = self::getParameters($function, $class);
$values = [];
foreach ($args as $k => $v) {
$values[$k] = !\is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v;
}
if (null === $params) {
parent::__construct($values, false);
return;
}
if (\count($values) < \count($params)) {
$params = \array_slice($params, 0, \count($values));
} elseif (\count($values) > \count($params)) {
$values[] = new EnumStub(array_splice($values, \count($params)), false);
$params[] = $variadic;
}
if (['...'] === $params) {
$this->dumpKeys = false;
$this->value = $values[0]->value;
} else {
$this->value = array_combine($params, $values);
}
}
private static function getParameters(string $function, ?string $class): array
{
if (isset(self::$parameters[$k = $class.'::'.$function])) {
return self::$parameters[$k];
}
try {
$r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function);
} catch (\ReflectionException $e) {
return [null, null];
}
$variadic = '...';
$params = [];
foreach ($r->getParameters() as $v) {
$k = '$'.$v->name;
if ($v->isPassedByReference()) {
$k = '&'.$k;
}
if ($v->isVariadic()) {
$variadic .= $k;
} else {
$params[] = $k;
}
}
return self::$parameters[$k] = [$variadic, $params];
}
}

View File

@@ -0,0 +1,175 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Helper for filtering out properties in casters.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final
*/
class Caster
{
public const EXCLUDE_VERBOSE = 1;
public const EXCLUDE_VIRTUAL = 2;
public const EXCLUDE_DYNAMIC = 4;
public const EXCLUDE_PUBLIC = 8;
public const EXCLUDE_PROTECTED = 16;
public const EXCLUDE_PRIVATE = 32;
public const EXCLUDE_NULL = 64;
public const EXCLUDE_EMPTY = 128;
public const EXCLUDE_NOT_IMPORTANT = 256;
public const EXCLUDE_STRICT = 512;
public const PREFIX_VIRTUAL = "\0~\0";
public const PREFIX_DYNAMIC = "\0+\0";
public const PREFIX_PROTECTED = "\0*\0";
/**
* Casts objects to arrays and adds the dynamic property prefix.
*
* @param object $obj The object to cast
* @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not
*
* @return array The array-cast of the object, with prefixed dynamic properties
*/
public static function castObject($obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array
{
if ($hasDebugInfo) {
try {
$debugInfo = $obj->__debugInfo();
} catch (\Exception $e) {
// ignore failing __debugInfo()
$hasDebugInfo = false;
}
}
$a = $obj instanceof \Closure ? [] : (array) $obj;
if ($obj instanceof \__PHP_Incomplete_Class) {
return $a;
}
if ($a) {
static $publicProperties = [];
$debugClass = $debugClass ?? get_debug_type($obj);
$i = 0;
$prefixedKeys = [];
foreach ($a as $k => $v) {
if (isset($k[0]) ? "\0" !== $k[0] : \PHP_VERSION_ID >= 70200) {
if (!isset($publicProperties[$class])) {
foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
$publicProperties[$class][$prop->name] = true;
}
}
if (!isset($publicProperties[$class][$k])) {
$prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k;
}
} elseif ($debugClass !== $class && 1 === strpos($k, $class)) {
$prefixedKeys[$i] = "\0".$debugClass.strrchr($k, "\0");
}
++$i;
}
if ($prefixedKeys) {
$keys = array_keys($a);
foreach ($prefixedKeys as $i => $k) {
$keys[$i] = $k;
}
$a = array_combine($keys, $a);
}
}
if ($hasDebugInfo && \is_array($debugInfo)) {
foreach ($debugInfo as $k => $v) {
if (!isset($k[0]) || "\0" !== $k[0]) {
if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) {
continue;
}
$k = self::PREFIX_VIRTUAL.$k;
}
unset($a[$k]);
$a[$k] = $v;
}
}
return $a;
}
/**
* Filters out the specified properties.
*
* By default, a single match in the $filter bit field filters properties out, following an "or" logic.
* When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed.
*
* @param array $a The array containing the properties to filter
* @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out
* @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set
* @param int &$count Set to the number of removed properties
*
* @return array The filtered array
*/
public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0): array
{
$count = 0;
foreach ($a as $k => $v) {
$type = self::EXCLUDE_STRICT & $filter;
if (null === $v) {
$type |= self::EXCLUDE_NULL & $filter;
$type |= self::EXCLUDE_EMPTY & $filter;
} elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) {
$type |= self::EXCLUDE_EMPTY & $filter;
}
if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_NOT_IMPORTANT;
}
if ((self::EXCLUDE_VERBOSE & $filter) && \in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_VERBOSE;
}
if (!isset($k[1]) || "\0" !== $k[0]) {
$type |= self::EXCLUDE_PUBLIC & $filter;
} elseif ('~' === $k[1]) {
$type |= self::EXCLUDE_VIRTUAL & $filter;
} elseif ('+' === $k[1]) {
$type |= self::EXCLUDE_DYNAMIC & $filter;
} elseif ('*' === $k[1]) {
$type |= self::EXCLUDE_PROTECTED & $filter;
} else {
$type |= self::EXCLUDE_PRIVATE & $filter;
}
if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) {
unset($a[$k]);
++$count;
}
}
return $a;
}
public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array
{
if (isset($a['__PHP_Incomplete_Class_Name'])) {
$stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')';
unset($a['__PHP_Incomplete_Class_Name']);
}
return $a;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents a PHP class identifier.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ClassStub extends ConstStub
{
/**
* @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name
* @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier
*/
public function __construct(string $identifier, $callable = null)
{
$this->value = $identifier;
try {
if (null !== $callable) {
if ($callable instanceof \Closure) {
$r = new \ReflectionFunction($callable);
} elseif (\is_object($callable)) {
$r = [$callable, '__invoke'];
} elseif (\is_array($callable)) {
$r = $callable;
} elseif (false !== $i = strpos($callable, '::')) {
$r = [substr($callable, 0, $i), substr($callable, 2 + $i)];
} else {
$r = new \ReflectionFunction($callable);
}
} elseif (0 < $i = strpos($identifier, '::') ?: strpos($identifier, '->')) {
$r = [substr($identifier, 0, $i), substr($identifier, 2 + $i)];
} else {
$r = new \ReflectionClass($identifier);
}
if (\is_array($r)) {
try {
$r = new \ReflectionMethod($r[0], $r[1]);
} catch (\ReflectionException $e) {
$r = new \ReflectionClass($r[0]);
}
}
if (str_contains($identifier, "@anonymous\0")) {
$this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $identifier);
}
if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) {
$s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), true, Caster::EXCLUDE_VERBOSE);
$s = ReflectionCaster::getSignature($s);
if (str_ends_with($identifier, '()')) {
$this->value = substr_replace($identifier, $s, -2);
} else {
$this->value .= $s;
}
}
} catch (\ReflectionException $e) {
return;
} finally {
if (0 < $i = strrpos($this->value, '\\')) {
$this->attr['ellipsis'] = \strlen($this->value) - $i;
$this->attr['ellipsis-type'] = 'class';
$this->attr['ellipsis-tail'] = 1;
}
}
if ($f = $r->getFileName()) {
$this->attr['file'] = $f;
$this->attr['line'] = $r->getStartLine();
}
}
public static function wrapCallable($callable)
{
if (\is_object($callable) || !\is_callable($callable)) {
return $callable;
}
if (!\is_array($callable)) {
$callable = new static($callable, $callable);
} elseif (\is_string($callable[0])) {
$callable[0] = new static($callable[0], $callable);
} else {
$callable[1] = new static($callable[1], $callable);
}
return $callable;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents a PHP constant and its value.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ConstStub extends Stub
{
public function __construct(string $name, $value = null)
{
$this->class = $name;
$this->value = 1 < \func_num_args() ? $value : $name;
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
/**
* Represents a cut array.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class CutArrayStub extends CutStub
{
public $preservedSubset;
public function __construct(array $value, array $preservedKeys)
{
parent::__construct($value);
$this->preservedSubset = array_intersect_key($value, array_flip($preservedKeys));
$this->cut -= \count($this->preservedSubset);
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents the main properties of a PHP variable, pre-casted by a caster.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class CutStub extends Stub
{
public function __construct($value)
{
$this->value = $value;
switch (\gettype($value)) {
case 'object':
$this->type = self::TYPE_OBJECT;
$this->class = \get_class($value);
if ($value instanceof \Closure) {
ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE);
}
$this->cut = -1;
break;
case 'array':
$this->type = self::TYPE_ARRAY;
$this->class = self::ARRAY_ASSOC;
$this->cut = $this->value = \count($value);
break;
case 'resource':
case 'unknown type':
case 'resource (closed)':
$this->type = self::TYPE_RESOURCE;
$this->handle = (int) $value;
if ('Unknown' === $this->class = @get_resource_type($value)) {
$this->class = 'Closed';
}
$this->cut = -1;
break;
case 'string':
$this->type = self::TYPE_STRING;
$this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY;
$this->cut = self::STRING_BINARY === $this->class ? \strlen($value) : mb_strlen($value, 'UTF-8');
$this->value = '';
break;
}
}
}

View File

@@ -0,0 +1,304 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts DOM related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class DOMCaster
{
private const ERROR_CODES = [
\DOM_PHP_ERR => 'DOM_PHP_ERR',
\DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR',
\DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR',
\DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR',
\DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR',
\DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR',
\DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR',
\DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR',
\DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR',
\DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR',
\DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR',
\DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR',
\DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR',
\DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR',
\DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR',
\DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR',
\DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR',
];
private const NODE_TYPES = [
\XML_ELEMENT_NODE => 'XML_ELEMENT_NODE',
\XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE',
\XML_TEXT_NODE => 'XML_TEXT_NODE',
\XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE',
\XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE',
\XML_ENTITY_NODE => 'XML_ENTITY_NODE',
\XML_PI_NODE => 'XML_PI_NODE',
\XML_COMMENT_NODE => 'XML_COMMENT_NODE',
\XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE',
\XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE',
\XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE',
\XML_NOTATION_NODE => 'XML_NOTATION_NODE',
\XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE',
\XML_DTD_NODE => 'XML_DTD_NODE',
\XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE',
\XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE',
\XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE',
\XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE',
];
public static function castException(\DOMException $e, array $a, Stub $stub, $isNested)
{
$k = Caster::PREFIX_PROTECTED.'code';
if (isset($a[$k], self::ERROR_CODES[$a[$k]])) {
$a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]);
}
return $a;
}
public static function castLength($dom, array $a, Stub $stub, $isNested)
{
$a += [
'length' => $dom->length,
];
return $a;
}
public static function castImplementation($dom, array $a, Stub $stub, $isNested)
{
$a += [
Caster::PREFIX_VIRTUAL.'Core' => '1.0',
Caster::PREFIX_VIRTUAL.'XML' => '2.0',
];
return $a;
}
public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested)
{
$a += [
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType),
'parentNode' => new CutStub($dom->parentNode),
'childNodes' => $dom->childNodes,
'firstChild' => new CutStub($dom->firstChild),
'lastChild' => new CutStub($dom->lastChild),
'previousSibling' => new CutStub($dom->previousSibling),
'nextSibling' => new CutStub($dom->nextSibling),
'attributes' => $dom->attributes,
'ownerDocument' => new CutStub($dom->ownerDocument),
'namespaceURI' => $dom->namespaceURI,
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI,
'textContent' => new CutStub($dom->textContent),
];
return $a;
}
public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested)
{
$a += [
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType),
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'namespaceURI' => $dom->namespaceURI,
'ownerDocument' => new CutStub($dom->ownerDocument),
'parentNode' => new CutStub($dom->parentNode),
];
return $a;
}
public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += [
'doctype' => $dom->doctype,
'implementation' => $dom->implementation,
'documentElement' => new CutStub($dom->documentElement),
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'xmlEncoding' => $dom->xmlEncoding,
'standalone' => $dom->standalone,
'xmlStandalone' => $dom->xmlStandalone,
'version' => $dom->version,
'xmlVersion' => $dom->xmlVersion,
'strictErrorChecking' => $dom->strictErrorChecking,
'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI,
'config' => $dom->config,
'formatOutput' => $dom->formatOutput,
'validateOnParse' => $dom->validateOnParse,
'resolveExternals' => $dom->resolveExternals,
'preserveWhiteSpace' => $dom->preserveWhiteSpace,
'recover' => $dom->recover,
'substituteEntities' => $dom->substituteEntities,
];
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$formatOutput = $dom->formatOutput;
$dom->formatOutput = true;
$a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()];
$dom->formatOutput = $formatOutput;
}
return $a;
}
public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested)
{
$a += [
'data' => $dom->data,
'length' => $dom->length,
];
return $a;
}
public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested)
{
$a += [
'name' => $dom->name,
'specified' => $dom->specified,
'value' => $dom->value,
'ownerElement' => $dom->ownerElement,
'schemaTypeInfo' => $dom->schemaTypeInfo,
];
return $a;
}
public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested)
{
$a += [
'tagName' => $dom->tagName,
'schemaTypeInfo' => $dom->schemaTypeInfo,
];
return $a;
}
public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested)
{
$a += [
'wholeText' => $dom->wholeText,
];
return $a;
}
public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested)
{
$a += [
'typeName' => $dom->typeName,
'typeNamespace' => $dom->typeNamespace,
];
return $a;
}
public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested)
{
$a += [
'severity' => $dom->severity,
'message' => $dom->message,
'type' => $dom->type,
'relatedException' => $dom->relatedException,
'related_data' => $dom->related_data,
'location' => $dom->location,
];
return $a;
}
public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested)
{
$a += [
'lineNumber' => $dom->lineNumber,
'columnNumber' => $dom->columnNumber,
'offset' => $dom->offset,
'relatedNode' => $dom->relatedNode,
'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri,
];
return $a;
}
public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested)
{
$a += [
'name' => $dom->name,
'entities' => $dom->entities,
'notations' => $dom->notations,
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'internalSubset' => $dom->internalSubset,
];
return $a;
}
public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested)
{
$a += [
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
];
return $a;
}
public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested)
{
$a += [
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'notationName' => $dom->notationName,
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'version' => $dom->version,
];
return $a;
}
public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested)
{
$a += [
'target' => $dom->target,
'data' => $dom->data,
];
return $a;
}
public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested)
{
$a += [
'document' => $dom->document,
];
return $a;
}
}

View File

@@ -0,0 +1,129 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts DateTimeInterface related classes to array representation.
*
* @author Dany Maillard <danymaillard93b@gmail.com>
*
* @final since Symfony 4.4
*/
class DateCaster
{
private const PERIOD_LIMIT = 3;
public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, $isNested, $filter)
{
$prefix = Caster::PREFIX_VIRTUAL;
$location = $d->getTimezone()->getLocation();
$fromNow = (new \DateTime())->diff($d);
$title = $d->format('l, F j, Y')
."\n".self::formatInterval($fromNow).' from now'
.($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '')
;
unset(
$a[Caster::PREFIX_DYNAMIC.'date'],
$a[Caster::PREFIX_DYNAMIC.'timezone'],
$a[Caster::PREFIX_DYNAMIC.'timezone_type']
);
$a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title);
$stub->class .= $d->format(' @U');
return $a;
}
public static function castInterval(\DateInterval $interval, array $a, Stub $stub, $isNested, $filter)
{
$now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
$numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp();
$title = number_format($numberOfSeconds, 0, '.', ' ').'s';
$i = [Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title)];
return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a;
}
private static function formatInterval(\DateInterval $i): string
{
$format = '%R ';
if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) {
$d = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
$i = $d->diff($d->add($i)); // recalculate carry over points
$format .= 0 < $i->days ? '%ad ' : '';
} else {
$format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : '');
}
$format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, substr($i->f, 2)) : '';
$format = '%R ' === $format ? '0s' : $format;
return $i->format(rtrim($format));
}
public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, $isNested, $filter)
{
$location = $timeZone->getLocation();
$formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P');
$title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-'.$location['country_code']) : '';
$z = [Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title)];
return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a;
}
public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, $isNested, $filter)
{
$dates = [];
if (\PHP_VERSION_ID >= 70107) { // see https://bugs.php.net/74639
foreach (clone $p as $i => $d) {
if (self::PERIOD_LIMIT === $i) {
$now = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
$dates[] = sprintf('%s more', ($end = $p->getEndDate())
? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u')))
: $p->recurrences - $i
);
break;
}
$dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d));
}
}
$period = sprintf(
'every %s, from %s%s %s',
self::formatInterval($p->getDateInterval()),
$p->include_start_date ? '[' : ']',
self::formatDateTime($p->getStartDate()),
($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s'
);
$p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))];
return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a;
}
private static function formatDateTime(\DateTimeInterface $d, string $extra = ''): string
{
return $d->format('Y-m-d H:i:'.self::formatSeconds($d->format('s'), $d->format('u')).$extra);
}
private static function formatSeconds(string $s, string $us): string
{
return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us));
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Doctrine\Common\Proxy\Proxy as CommonProxy;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\Proxy as OrmProxy;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Doctrine related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class DoctrineCaster
{
public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested)
{
foreach (['__cloner__', '__initializer__'] as $k) {
if (\array_key_exists($k, $a)) {
unset($a[$k]);
++$stub->cut;
}
}
return $a;
}
public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested)
{
foreach (['_entityPersister', '_identifier'] as $k) {
if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) {
unset($a[$k]);
++$stub->cut;
}
}
return $a;
}
public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested)
{
foreach (['snapshot', 'association', 'typeClass'] as $k) {
if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) {
$a[$k] = new CutStub($a[$k]);
}
}
return $a;
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Ds\Collection;
use Ds\Map;
use Ds\Pair;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Ds extension classes to array representation.
*
* @author Jáchym Toušek <enumag@gmail.com>
*
* @final since Symfony 4.4
*/
class DsCaster
{
public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array
{
$a[Caster::PREFIX_VIRTUAL.'count'] = $c->count();
$a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity();
if (!$c instanceof Map) {
$a += $c->toArray();
}
return $a;
}
public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($c as $k => $v) {
$a[] = new DsPairStub($k, $v);
}
return $a;
}
public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($c->toArray() as $k => $v) {
$a[Caster::PREFIX_VIRTUAL.$k] = $v;
}
return $a;
}
public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array
{
if ($isNested) {
$stub->class = Pair::class;
$stub->value = null;
$stub->handle = 0;
$a = $c->value;
}
return $a;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DsPairStub extends Stub
{
public function __construct($key, $value)
{
$this->value = [
Caster::PREFIX_VIRTUAL.'key' => $key,
Caster::PREFIX_VIRTUAL.'value' => $value,
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents an enumeration of values.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class EnumStub extends Stub
{
public $dumpKeys = true;
public function __construct(array $values, bool $dumpKeys = true)
{
$this->value = $values;
$this->dumpKeys = $dumpKeys;
}
}

View File

@@ -0,0 +1,388 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
/**
* Casts common Exception classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ExceptionCaster
{
public static $srcContext = 1;
public static $traceArgs = true;
public static $errorTypes = [
\E_DEPRECATED => 'E_DEPRECATED',
\E_USER_DEPRECATED => 'E_USER_DEPRECATED',
\E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
\E_ERROR => 'E_ERROR',
\E_WARNING => 'E_WARNING',
\E_PARSE => 'E_PARSE',
\E_NOTICE => 'E_NOTICE',
\E_CORE_ERROR => 'E_CORE_ERROR',
\E_CORE_WARNING => 'E_CORE_WARNING',
\E_COMPILE_ERROR => 'E_COMPILE_ERROR',
\E_COMPILE_WARNING => 'E_COMPILE_WARNING',
\E_USER_ERROR => 'E_USER_ERROR',
\E_USER_WARNING => 'E_USER_WARNING',
\E_USER_NOTICE => 'E_USER_NOTICE',
\E_STRICT => 'E_STRICT',
];
private static $framesCache = [];
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
}
public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter);
}
public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested)
{
if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) {
$a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
}
return $a;
}
public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested)
{
$trace = Caster::PREFIX_VIRTUAL.'trace';
$prefix = Caster::PREFIX_PROTECTED;
$xPrefix = "\0Exception\0";
if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) {
$b = (array) $a[$xPrefix.'previous'];
$class = get_debug_type($a[$xPrefix.'previous']);
self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']);
$a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value));
}
unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']);
return $a;
}
public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, $isNested)
{
$sPrefix = "\0".SilencedErrorContext::class."\0";
if (!isset($a[$s = $sPrefix.'severity'])) {
return $a;
}
if (isset(self::$errorTypes[$a[$s]])) {
$a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
}
$trace = [[
'file' => $a[$sPrefix.'file'],
'line' => $a[$sPrefix.'line'],
]];
if (isset($a[$sPrefix.'trace'])) {
$trace = array_merge($trace, $a[$sPrefix.'trace']);
}
unset($a[$sPrefix.'file'], $a[$sPrefix.'line'], $a[$sPrefix.'trace']);
$a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs);
return $a;
}
public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$stub->class = '';
$stub->handle = 0;
$frames = $trace->value;
$prefix = Caster::PREFIX_VIRTUAL;
$a = [];
$j = \count($frames);
if (0 > $i = $trace->sliceOffset) {
$i = max(0, $j + $i);
}
if (!isset($trace->value[$i])) {
return [];
}
$lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '';
$frames[] = ['function' => ''];
$collapse = false;
for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
$f = $frames[$i];
$call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'] : '???';
$frame = new FrameStub(
[
'object' => $f['object'] ?? null,
'class' => $f['class'] ?? null,
'type' => $f['type'] ?? null,
'function' => $f['function'] ?? null,
] + $frames[$i - 1],
false,
true
);
$f = self::castFrameStub($frame, [], $frame, true);
if (isset($f[$prefix.'src'])) {
foreach ($f[$prefix.'src']->value as $label => $frame) {
if (str_starts_with($label, "\0~collapse=0")) {
if ($collapse) {
$label = substr_replace($label, '1', 11, 1);
} else {
$collapse = true;
}
}
$label = substr_replace($label, "title=Stack level $j.&", 2, 0);
}
$f = $frames[$i - 1];
if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) {
$frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null);
}
} elseif ('???' !== $lastCall) {
$label = new ClassStub($lastCall);
if (isset($label->attr['ellipsis'])) {
$label->attr['ellipsis'] += 2;
$label = substr_replace($prefix, "ellipsis-type=class&ellipsis={$label->attr['ellipsis']}&ellipsis-tail=1&title=Stack level $j.", 2, 0).$label->value.'()';
} else {
$label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$label->value.'()';
}
} else {
$label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall;
}
$a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame;
$lastCall = $call;
}
if (null !== $trace->sliceLength) {
$a = \array_slice($a, 0, $trace->sliceLength, true);
}
return $a;
}
public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$f = $frame->value;
$prefix = Caster::PREFIX_VIRTUAL;
if (isset($f['file'], $f['line'])) {
$cacheKey = $f;
unset($cacheKey['object'], $cacheKey['args']);
$cacheKey[] = self::$srcContext;
$cacheKey = implode('-', $cacheKey);
if (isset(self::$framesCache[$cacheKey])) {
$a[$prefix.'src'] = self::$framesCache[$cacheKey];
} else {
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
$f['file'] = substr($f['file'], 0, -\strlen($match[0]));
$f['line'] = (int) $match[1];
}
$src = $f['line'];
$srcKey = $f['file'];
$ellipsis = new LinkStub($srcKey, 0);
$srcAttr = 'collapse='.(int) $ellipsis->inVendor;
$ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0;
$ellipsis = $ellipsis->attr['ellipsis'] ?? 0;
if (file_exists($f['file']) && 0 <= self::$srcContext) {
if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) {
$template = null;
if (isset($f['object'])) {
$template = $f['object'];
} elseif ((new \ReflectionClass($f['class']))->isInstantiable()) {
$template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class']));
}
if (null !== $template) {
$ellipsis = 0;
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
$templateInfo = $template->getDebugInfo();
if (isset($templateInfo[$f['line']])) {
if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) {
$templatePath = null;
}
if ($templateSrc) {
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f);
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
}
}
}
}
if ($srcKey == $f['file']) {
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f);
$srcKey .= ':'.$f['line'];
if ($ellipsis) {
$ellipsis += 1 + \strlen($f['line']);
}
}
$srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']);
} else {
$srcAttr .= '&separator=:';
}
$srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : '';
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(["\0~$srcAttr\0$srcKey" => $src]);
}
}
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
if ($frame->inTraceStub) {
unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']);
}
foreach ($a as $k => $v) {
if (!$v) {
unset($a[$k]);
}
}
if ($frame->keepArgs && !empty($f['args'])) {
$a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']);
}
return $a;
}
private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array
{
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = [];
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) {
if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) {
self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']);
}
$a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs);
}
if (empty($a[$xPrefix.'previous'])) {
unset($a[$xPrefix.'previous']);
}
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) {
$a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $a[Caster::PREFIX_PROTECTED.'message']);
}
if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) {
$a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']);
}
return $a;
}
private static function traceUnshift(array &$trace, ?string $class, string $file, int $line): void
{
if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) {
return;
}
array_unshift($trace, [
'function' => $class ? 'new '.$class : null,
'file' => $file,
'line' => $line,
]);
}
private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub
{
$srcLines = explode("\n", $srcLines);
$src = [];
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
$src[] = ($srcLines[$i] ?? '')."\n";
}
if ($frame['function'] ?? false) {
$stub = new CutStub(new \stdClass());
$stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function'];
$stub->type = Stub::TYPE_OBJECT;
$stub->attr['cut_hash'] = true;
$stub->attr['file'] = $frame['file'];
$stub->attr['line'] = $frame['line'];
try {
$caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']);
$stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE));
if ($f = $caller->getFileName()) {
$stub->attr['file'] = $f;
$stub->attr['line'] = $caller->getStartLine();
}
} catch (\ReflectionException $e) {
// ignore fake class/function
}
$srcLines = ["\0~separator=\0" => $stub];
} else {
$stub = null;
$srcLines = [];
}
$ltrim = 0;
do {
$pad = null;
for ($i = $srcContext << 1; $i >= 0; --$i) {
if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) {
if (null === $pad) {
$pad = $c;
}
if ((' ' !== $c && "\t" !== $c) || $pad !== $c) {
break;
}
}
}
++$ltrim;
} while (0 > $i && null !== $pad);
--$ltrim;
foreach ($src as $i => $c) {
if ($ltrim) {
$c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? substr($c, $ltrim) : ltrim($c, " \t");
}
$c = substr($c, 0, -1);
if ($i !== $srcContext) {
$c = new ConstStub('default', $c);
} else {
$c = new ConstStub($c, $stub ? 'in '.$stub->class : '');
if (null !== $file) {
$c->attr['file'] = $file;
$c->attr['line'] = $line;
}
}
$c->attr['lang'] = $lang;
$srcLines[sprintf("\0~separator= &%d\0", $i + $line - $srcContext)] = $c;
}
return new EnumStub($srcLines);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
/**
* Represents a single backtrace frame as returned by debug_backtrace() or Exception->getTrace().
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class FrameStub extends EnumStub
{
public $keepArgs;
public $inTraceStub;
public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false)
{
$this->value = $frame;
$this->keepArgs = $keepArgs;
$this->inTraceStub = $inTraceStub;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts GMP objects to array representation.
*
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class GmpCaster
{
public static function castGmp(\GMP $gmp, array $a, Stub $stub, $isNested, $filter): array
{
$a[Caster::PREFIX_VIRTUAL.'value'] = new ConstStub(gmp_strval($gmp), gmp_strval($gmp));
return $a;
}
}

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Imagine\Image\ImageInterface;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
final class ImagineCaster
{
public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested): array
{
$imgData = $c->get('png');
if (\strlen($imgData) > 1 * 1000 * 1000) {
$a += [
Caster::PREFIX_VIRTUAL.'image' => new ConstStub($c->getSize()),
];
} else {
$a += [
Caster::PREFIX_VIRTUAL.'image' => new ImgStub($imgData, 'image/png', $c->getSize()),
];
}
return $a;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class ImgStub extends ConstStub
{
public function __construct(string $data, string $contentType, string $size)
{
$this->value = '';
$this->attr['img-data'] = $data;
$this->attr['img-size'] = $size;
$this->attr['content-type'] = $contentType;
}
}

View File

@@ -0,0 +1,172 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
*
* @final since Symfony 4.4
*/
class IntlCaster
{
public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, $isNested)
{
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
];
return self::castError($c, $a);
}
public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
];
if ($filter & Caster::EXCLUDE_VERBOSE) {
$stub->cut += 3;
return self::castError($c, $a);
}
$a += [
Caster::PREFIX_VIRTUAL.'attributes' => new EnumStub(
[
'PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY),
'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED),
'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN),
'MAX_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS),
'MIN_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS),
'INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::INTEGER_DIGITS),
'MAX_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS),
'MIN_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS),
'FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::FRACTION_DIGITS),
'MULTIPLIER' => $c->getAttribute(\NumberFormatter::MULTIPLIER),
'GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::GROUPING_SIZE),
'ROUNDING_MODE' => $c->getAttribute(\NumberFormatter::ROUNDING_MODE),
'ROUNDING_INCREMENT' => $c->getAttribute(\NumberFormatter::ROUNDING_INCREMENT),
'FORMAT_WIDTH' => $c->getAttribute(\NumberFormatter::FORMAT_WIDTH),
'PADDING_POSITION' => $c->getAttribute(\NumberFormatter::PADDING_POSITION),
'SECONDARY_GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE),
'SIGNIFICANT_DIGITS_USED' => $c->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED),
'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS),
'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS),
'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE),
]
),
Caster::PREFIX_VIRTUAL.'text_attributes' => new EnumStub(
[
'POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX),
'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX),
'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX),
'NEGATIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX),
'PADDING_CHARACTER' => $c->getTextAttribute(\NumberFormatter::PADDING_CHARACTER),
'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE),
'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET),
'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS),
]
),
Caster::PREFIX_VIRTUAL.'symbols' => new EnumStub(
[
'DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL),
'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL),
'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL),
'PERCENT_SYMBOL' => $c->getSymbol(\NumberFormatter::PERCENT_SYMBOL),
'ZERO_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL),
'DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::DIGIT_SYMBOL),
'MINUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL),
'PLUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL),
'CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::CURRENCY_SYMBOL),
'INTL_CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL),
'MONETARY_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL),
'EXPONENTIAL_SYMBOL' => $c->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL),
'PERMILL_SYMBOL' => $c->getSymbol(\NumberFormatter::PERMILL_SYMBOL),
'PAD_ESCAPE_SYMBOL' => $c->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL),
'INFINITY_SYMBOL' => $c->getSymbol(\NumberFormatter::INFINITY_SYMBOL),
'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL),
'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL),
'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL),
]
),
];
return self::castError($c, $a);
}
public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, $isNested)
{
$a += [
Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(),
Caster::PREFIX_VIRTUAL.'id' => $c->getID(),
Caster::PREFIX_VIRTUAL.'raw_offset' => $c->getRawOffset(),
];
if ($c->useDaylightTime()) {
$a += [
Caster::PREFIX_VIRTUAL.'dst_savings' => $c->getDSTSavings(),
];
}
return self::castError($c, $a);
}
public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += [
Caster::PREFIX_VIRTUAL.'type' => $c->getType(),
Caster::PREFIX_VIRTUAL.'first_day_of_week' => $c->getFirstDayOfWeek(),
Caster::PREFIX_VIRTUAL.'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(),
Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(),
Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(),
Caster::PREFIX_VIRTUAL.'time' => $c->getTime(),
Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(),
Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(),
Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(),
];
return self::castError($c, $a);
}
public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
Caster::PREFIX_VIRTUAL.'calendar' => $c->getCalendar(),
Caster::PREFIX_VIRTUAL.'time_zone_id' => $c->getTimeZoneId(),
Caster::PREFIX_VIRTUAL.'time_type' => $c->getTimeType(),
Caster::PREFIX_VIRTUAL.'date_type' => $c->getDateType(),
Caster::PREFIX_VIRTUAL.'calendar_object' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(),
Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(),
];
return self::castError($c, $a);
}
private static function castError($c, array $a): array
{
if ($errorCode = $c->getErrorCode()) {
$a += [
Caster::PREFIX_VIRTUAL.'error_code' => $errorCode,
Caster::PREFIX_VIRTUAL.'error_message' => $c->getErrorMessage(),
];
}
return $a;
}
}

View File

@@ -0,0 +1,108 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
/**
* Represents a file or a URL.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class LinkStub extends ConstStub
{
public $inVendor = false;
private static $vendorRoots;
private static $composerRoots;
public function __construct(string $label, int $line = 0, string $href = null)
{
$this->value = $label;
if (null === $href) {
$href = $label;
}
if (!\is_string($href)) {
return;
}
if (str_starts_with($href, 'file://')) {
if ($href === $label) {
$label = substr($label, 7);
}
$href = substr($href, 7);
} elseif (str_contains($href, '://')) {
$this->attr['href'] = $href;
return;
}
if (!file_exists($href)) {
return;
}
if ($line) {
$this->attr['line'] = $line;
}
if ($label !== $this->attr['file'] = realpath($href) ?: $href) {
return;
}
if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) {
$this->attr['ellipsis'] = \strlen($href) - \strlen($composerRoot) + 1;
$this->attr['ellipsis-type'] = 'path';
$this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + \strlen(implode('', \array_slice(explode(\DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0);
} elseif (3 < \count($ellipsis = explode(\DIRECTORY_SEPARATOR, $href))) {
$this->attr['ellipsis'] = 2 + \strlen(implode('', \array_slice($ellipsis, -2)));
$this->attr['ellipsis-type'] = 'path';
$this->attr['ellipsis-tail'] = 1;
}
}
private function getComposerRoot(string $file, bool &$inVendor)
{
if (null === self::$vendorRoots) {
self::$vendorRoots = [];
foreach (get_declared_classes() as $class) {
if ('C' === $class[0] && str_starts_with($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$v = \dirname($r->getFileName(), 2);
if (file_exists($v.'/composer/installed.json')) {
self::$vendorRoots[] = $v.\DIRECTORY_SEPARATOR;
}
}
}
}
$inVendor = false;
if (isset(self::$composerRoots[$dir = \dirname($file)])) {
return self::$composerRoots[$dir];
}
foreach (self::$vendorRoots as $root) {
if ($inVendor = str_starts_with($file, $root)) {
return $root;
}
}
$parent = $dir;
while (!@file_exists($parent.'/composer.json')) {
if (!@file_exists($parent)) {
// open_basedir restriction in effect
break;
}
if ($parent === \dirname($parent)) {
return self::$composerRoots[$dir] = false;
}
$parent = \dirname($parent);
}
return self::$composerRoots[$dir] = $parent.\DIRECTORY_SEPARATOR;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
*
* @final since Symfony 4.4
*/
class MemcachedCaster
{
private static $optionConstants;
private static $defaultOptions;
public static function castMemcached(\Memcached $c, array $a, Stub $stub, $isNested)
{
$a += [
Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(),
Caster::PREFIX_VIRTUAL.'options' => new EnumStub(
self::getNonDefaultOptions($c)
),
];
return $a;
}
private static function getNonDefaultOptions(\Memcached $c): array
{
self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions();
self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
$nonDefaultOptions = [];
foreach (self::$optionConstants as $constantKey => $value) {
if (self::$defaultOptions[$constantKey] !== $option = $c->getOption($value)) {
$nonDefaultOptions[$constantKey] = $option;
}
}
return $nonDefaultOptions;
}
private static function discoverDefaultOptions(): array
{
$defaultMemcached = new \Memcached();
$defaultMemcached->addServer('127.0.0.1', 11211);
$defaultOptions = [];
self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
foreach (self::$optionConstants as $constantKey => $value) {
$defaultOptions[$constantKey] = $defaultMemcached->getOption($value);
}
return $defaultOptions;
}
private static function getOptionConstants(): array
{
$reflectedMemcached = new \ReflectionClass(\Memcached::class);
$optionConstants = [];
foreach ($reflectedMemcached->getConstants() as $constantKey => $value) {
if (str_starts_with($constantKey, 'OPT_')) {
$optionConstants[$constantKey] = $value;
}
}
return $optionConstants;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class MysqliCaster
{
public static function castMysqliDriver(\mysqli_driver $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($a as $k => $v) {
if (isset($c->$k)) {
$a[$k] = $c->$k;
}
}
return $a;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts PDO related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class PdoCaster
{
private const PDO_ATTRIBUTES = [
'CASE' => [
\PDO::CASE_LOWER => 'LOWER',
\PDO::CASE_NATURAL => 'NATURAL',
\PDO::CASE_UPPER => 'UPPER',
],
'ERRMODE' => [
\PDO::ERRMODE_SILENT => 'SILENT',
\PDO::ERRMODE_WARNING => 'WARNING',
\PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
],
'TIMEOUT',
'PREFETCH',
'AUTOCOMMIT',
'PERSISTENT',
'DRIVER_NAME',
'SERVER_INFO',
'ORACLE_NULLS' => [
\PDO::NULL_NATURAL => 'NATURAL',
\PDO::NULL_EMPTY_STRING => 'EMPTY_STRING',
\PDO::NULL_TO_STRING => 'TO_STRING',
],
'CLIENT_VERSION',
'SERVER_VERSION',
'STATEMENT_CLASS',
'EMULATE_PREPARES',
'CONNECTION_STATUS',
'STRINGIFY_FETCHES',
'DEFAULT_FETCH_MODE' => [
\PDO::FETCH_ASSOC => 'ASSOC',
\PDO::FETCH_BOTH => 'BOTH',
\PDO::FETCH_LAZY => 'LAZY',
\PDO::FETCH_NUM => 'NUM',
\PDO::FETCH_OBJ => 'OBJ',
],
];
public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
{
$attr = [];
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
foreach (self::PDO_ATTRIBUTES as $k => $v) {
if (!isset($k[0])) {
$k = $v;
$v = [];
}
try {
$attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(\constant('PDO::ATTR_'.$k));
if ($v && isset($v[$attr[$k]])) {
$attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]);
}
} catch (\Exception $e) {
}
}
if (isset($attr[$k = 'STATEMENT_CLASS'][1])) {
if ($attr[$k][1]) {
$attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]);
}
$attr[$k][0] = new ClassStub($attr[$k][0]);
}
$prefix = Caster::PREFIX_VIRTUAL;
$a += [
$prefix.'inTransaction' => method_exists($c, 'inTransaction'),
$prefix.'errorInfo' => $c->errorInfo(),
$prefix.'attributes' => new EnumStub($attr),
];
if ($a[$prefix.'inTransaction']) {
$a[$prefix.'inTransaction'] = $c->inTransaction();
} else {
unset($a[$prefix.'inTransaction']);
}
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
$c->setAttribute(\PDO::ATTR_ERRMODE, $errmode);
return $a;
}
public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a[$prefix.'errorInfo'] = $c->errorInfo();
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
return $a;
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts pqsql resources to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class PgSqlCaster
{
private const PARAM_CODES = [
'server_encoding',
'client_encoding',
'is_superuser',
'session_authorization',
'DateStyle',
'TimeZone',
'IntervalStyle',
'integer_datetimes',
'application_name',
'standard_conforming_strings',
];
private const TRANSACTION_STATUS = [
\PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE',
\PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE',
\PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS',
\PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR',
\PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN',
];
private const RESULT_STATUS = [
\PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY',
\PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK',
\PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK',
\PGSQL_COPY_OUT => 'PGSQL_COPY_OUT',
\PGSQL_COPY_IN => 'PGSQL_COPY_IN',
\PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE',
\PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR',
\PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR',
];
private const DIAG_CODES = [
'severity' => \PGSQL_DIAG_SEVERITY,
'sqlstate' => \PGSQL_DIAG_SQLSTATE,
'message' => \PGSQL_DIAG_MESSAGE_PRIMARY,
'detail' => \PGSQL_DIAG_MESSAGE_DETAIL,
'hint' => \PGSQL_DIAG_MESSAGE_HINT,
'statement position' => \PGSQL_DIAG_STATEMENT_POSITION,
'internal position' => \PGSQL_DIAG_INTERNAL_POSITION,
'internal query' => \PGSQL_DIAG_INTERNAL_QUERY,
'context' => \PGSQL_DIAG_CONTEXT,
'file' => \PGSQL_DIAG_SOURCE_FILE,
'line' => \PGSQL_DIAG_SOURCE_LINE,
'function' => \PGSQL_DIAG_SOURCE_FUNCTION,
];
public static function castLargeObject($lo, array $a, Stub $stub, $isNested)
{
$a['seek position'] = pg_lo_tell($lo);
return $a;
}
public static function castLink($link, array $a, Stub $stub, $isNested)
{
$a['status'] = pg_connection_status($link);
$a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']);
$a['busy'] = pg_connection_busy($link);
$a['transaction'] = pg_transaction_status($link);
if (isset(self::TRANSACTION_STATUS[$a['transaction']])) {
$a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']);
}
$a['pid'] = pg_get_pid($link);
$a['last error'] = pg_last_error($link);
$a['last notice'] = pg_last_notice($link);
$a['host'] = pg_host($link);
$a['port'] = pg_port($link);
$a['dbname'] = pg_dbname($link);
$a['options'] = pg_options($link);
$a['version'] = pg_version($link);
foreach (self::PARAM_CODES as $v) {
if (false !== $s = pg_parameter_status($link, $v)) {
$a['param'][$v] = $s;
}
}
$a['param']['client_encoding'] = pg_client_encoding($link);
$a['param'] = new EnumStub($a['param']);
return $a;
}
public static function castResult($result, array $a, Stub $stub, $isNested)
{
$a['num rows'] = pg_num_rows($result);
$a['status'] = pg_result_status($result);
if (isset(self::RESULT_STATUS[$a['status']])) {
$a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']);
}
$a['command-completion tag'] = pg_result_status($result, \PGSQL_STATUS_STRING);
if (-1 === $a['num rows']) {
foreach (self::DIAG_CODES as $k => $v) {
$a['error'][$k] = pg_result_error_field($result, $v);
}
}
$a['affected rows'] = pg_affected_rows($result);
$a['last OID'] = pg_last_oid($result);
$fields = pg_num_fields($result);
for ($i = 0; $i < $fields; ++$i) {
$field = [
'name' => pg_field_name($result, $i),
'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)),
'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)),
'nullable' => (bool) pg_field_is_null($result, $i),
'storage' => pg_field_size($result, $i).' bytes',
'display' => pg_field_prtlen($result, $i).' chars',
];
if (' (OID: )' === $field['table']) {
$field['table'] = null;
}
if ('-1 bytes' === $field['storage']) {
$field['storage'] = 'variable size';
} elseif ('1 bytes' === $field['storage']) {
$field['storage'] = '1 byte';
}
if ('1 chars' === $field['display']) {
$field['display'] = '1 char';
}
$a['fields'][] = new EnumStub($field);
}
return $a;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use ProxyManager\Proxy\ProxyInterface;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ProxyManagerCaster
{
public static function castProxy(ProxyInterface $c, array $a, Stub $stub, $isNested)
{
if ($parent = get_parent_class($c)) {
$stub->class .= ' - '.$parent;
}
$stub->class .= '@proxy';
return $a;
}
}

View File

@@ -0,0 +1,152 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Redis class from ext-redis to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class RedisCaster
{
private const SERIALIZERS = [
\Redis::SERIALIZER_NONE => 'NONE',
\Redis::SERIALIZER_PHP => 'PHP',
2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY
];
private const MODES = [
\Redis::ATOMIC => 'ATOMIC',
\Redis::MULTI => 'MULTI',
\Redis::PIPELINE => 'PIPELINE',
];
private const COMPRESSION_MODES = [
0 => 'NONE', // Redis::COMPRESSION_NONE
1 => 'LZF', // Redis::COMPRESSION_LZF
];
private const FAILOVER_OPTIONS = [
\RedisCluster::FAILOVER_NONE => 'NONE',
\RedisCluster::FAILOVER_ERROR => 'ERROR',
\RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE',
\RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES',
];
public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if (!$connected = $c->isConnected()) {
return $a + [
$prefix.'isConnected' => $connected,
];
}
$mode = $c->getMode();
return $a + [
$prefix.'isConnected' => $connected,
$prefix.'host' => $c->getHost(),
$prefix.'port' => $c->getPort(),
$prefix.'auth' => $c->getAuth(),
$prefix.'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode,
$prefix.'dbNum' => $c->getDbNum(),
$prefix.'timeout' => $c->getTimeout(),
$prefix.'lastError' => $c->getLastError(),
$prefix.'persistentId' => $c->getPersistentID(),
$prefix.'options' => self::getRedisOptions($c),
];
}
public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a + [
$prefix.'hosts' => $c->_hosts(),
$prefix.'function' => ClassStub::wrapCallable($c->_function()),
$prefix.'lastError' => $c->getLastError(),
$prefix.'options' => self::getRedisOptions($c),
];
}
public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER);
$a += [
$prefix.'_masters' => $c->_masters(),
$prefix.'_redir' => $c->_redir(),
$prefix.'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()),
$prefix.'lastError' => $c->getLastError(),
$prefix.'options' => self::getRedisOptions($c, [
'SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover,
]),
];
return $a;
}
/**
* @param \Redis|\RedisArray|\RedisCluster $redis
*/
private static function getRedisOptions($redis, array $options = []): EnumStub
{
$serializer = $redis->getOption(\Redis::OPT_SERIALIZER);
if (\is_array($serializer)) {
foreach ($serializer as &$v) {
if (isset(self::SERIALIZERS[$v])) {
$v = new ConstStub(self::SERIALIZERS[$v], $v);
}
}
} elseif (isset(self::SERIALIZERS[$serializer])) {
$serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer);
}
$compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0;
if (\is_array($compression)) {
foreach ($compression as &$v) {
if (isset(self::COMPRESSION_MODES[$v])) {
$v = new ConstStub(self::COMPRESSION_MODES[$v], $v);
}
}
} elseif (isset(self::COMPRESSION_MODES[$compression])) {
$compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression);
}
$retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0;
if (\is_array($retry)) {
foreach ($retry as &$v) {
$v = new ConstStub($v ? 'RETRY' : 'NORETRY', $v);
}
} else {
$retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry);
}
$options += [
'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0,
'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT),
'COMPRESSION' => $compression,
'SERIALIZER' => $serializer,
'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX),
'SCAN' => $retry,
];
return new EnumStub($options);
}
}

View File

@@ -0,0 +1,405 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Reflector related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ReflectionCaster
{
public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo'];
private const EXTRA_MAP = [
'docComment' => 'getDocComment',
'extension' => 'getExtensionName',
'isDisabled' => 'isDisabled',
'isDeprecated' => 'isDeprecated',
'isInternal' => 'isInternal',
'isUserDefined' => 'isUserDefined',
'isGenerator' => 'isGenerator',
'isVariadic' => 'isVariadic',
];
public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
$c = new \ReflectionFunction($c);
$a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter);
if (!str_contains($c->name, '{closure}')) {
$stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name;
unset($a[$prefix.'class']);
}
unset($a[$prefix.'extra']);
$stub->class .= self::getSignature($a);
if ($f = $c->getFileName()) {
$stub->attr['file'] = $f;
$stub->attr['line'] = $c->getStartLine();
}
unset($a[$prefix.'parameters']);
if ($filter & Caster::EXCLUDE_VERBOSE) {
$stub->cut += ($c->getFileName() ? 2 : 0) + \count($a);
return [];
}
if ($f) {
$a[$prefix.'file'] = new LinkStub($f, $c->getStartLine());
$a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine();
}
return $a;
}
public static function unsetClosureFileInfo(\Closure $c, array $a)
{
unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']);
return $a;
}
public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested)
{
// Cannot create ReflectionGenerator based on a terminated Generator
try {
$reflectionGenerator = new \ReflectionGenerator($c);
} catch (\Exception $e) {
$a[Caster::PREFIX_VIRTUAL.'closed'] = true;
return $a;
}
return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested);
}
public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) {
$a += [
$prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c,
$prefix.'allowsNull' => $c->allowsNull(),
$prefix.'isBuiltin' => $c->isBuiltin(),
];
} elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) {
$a[$prefix.'allowsNull'] = $c->allowsNull();
self::addMap($a, $c, [
'types' => 'getTypes',
]);
} else {
$a[$prefix.'allowsNull'] = $c->allowsNull();
}
return $a;
}
public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if ($c->getThis()) {
$a[$prefix.'this'] = new CutStub($c->getThis());
}
$function = $c->getFunction();
$frame = [
'class' => $function->class ?? null,
'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null,
'function' => $function->name,
'file' => $c->getExecutingFile(),
'line' => $c->getExecutingLine(),
];
if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) {
$function = new \ReflectionGenerator($c->getExecutingGenerator());
array_unshift($trace, [
'function' => 'yield',
'file' => $function->getExecutingFile(),
'line' => $function->getExecutingLine() - (int) (\PHP_VERSION_ID < 80100),
]);
$trace[] = $frame;
$a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1);
} else {
$function = new FrameStub($frame, false, true);
$function = ExceptionCaster::castFrameStub($function, [], $function, true);
$a[$prefix.'executing'] = $function[$prefix.'src'];
}
$a[Caster::PREFIX_VIRTUAL.'closed'] = false;
return $a;
}
public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
if ($n = \Reflection::getModifierNames($c->getModifiers())) {
$a[$prefix.'modifiers'] = implode(' ', $n);
}
self::addMap($a, $c, [
'extends' => 'getParentClass',
'implements' => 'getInterfaceNames',
'constants' => 'getConstants',
]);
foreach ($c->getProperties() as $n) {
$a[$prefix.'properties'][$n->name] = $n;
}
foreach ($c->getMethods() as $n) {
$a[$prefix.'methods'][$n->name] = $n;
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
return $a;
}
public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
self::addMap($a, $c, [
'returnsReference' => 'returnsReference',
'returnType' => 'getReturnType',
'class' => 'getClosureScopeClass',
'this' => 'getClosureThis',
]);
if (isset($a[$prefix.'returnType'])) {
$v = $a[$prefix.'returnType'];
$v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
$a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']);
}
if (isset($a[$prefix.'class'])) {
$a[$prefix.'class'] = new ClassStub($a[$prefix.'class']);
}
if (isset($a[$prefix.'this'])) {
$a[$prefix.'this'] = new CutStub($a[$prefix.'this']);
}
foreach ($c->getParameters() as $v) {
$k = '$'.$v->name;
if ($v->isVariadic()) {
$k = '...'.$k;
}
if ($v->isPassedByReference()) {
$k = '&'.$k;
}
$a[$prefix.'parameters'][$k] = $v;
}
if (isset($a[$prefix.'parameters'])) {
$a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']);
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && $v = $c->getStaticVariables()) {
foreach ($v as $k => &$v) {
if (\is_object($v)) {
$a[$prefix.'use']['$'.$k] = new CutStub($v);
} else {
$a[$prefix.'use']['$'.$k] = &$v;
}
}
unset($v);
$a[$prefix.'use'] = new EnumStub($a[$prefix.'use']);
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
return $a;
}
public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
return $a;
}
public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
self::addMap($a, $c, [
'position' => 'getPosition',
'isVariadic' => 'isVariadic',
'byReference' => 'isPassedByReference',
'allowsNull' => 'allowsNull',
]);
if ($v = $c->getType()) {
$a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
}
if (isset($a[$prefix.'typeHint'])) {
$v = $a[$prefix.'typeHint'];
$a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']);
} else {
unset($a[$prefix.'allowsNull']);
}
if ($c->isOptional()) {
try {
$a[$prefix.'default'] = $v = $c->getDefaultValue();
if ($c->isDefaultValueConstant()) {
$a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
}
if (null === $v) {
unset($a[$prefix.'allowsNull']);
}
} catch (\ReflectionException $e) {
}
}
return $a;
}
public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
self::addExtra($a, $c);
return $a;
}
public static function castReference(\ReflectionReference $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId();
return $a;
}
public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, [
'version' => 'getVersion',
'dependencies' => 'getDependencies',
'iniEntries' => 'getIniEntries',
'isPersistent' => 'isPersistent',
'isTemporary' => 'isTemporary',
'constants' => 'getConstants',
'functions' => 'getFunctions',
'classes' => 'getClasses',
]);
return $a;
}
public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, [
'version' => 'getVersion',
'author' => 'getAuthor',
'copyright' => 'getCopyright',
'url' => 'getURL',
]);
return $a;
}
public static function getSignature(array $a)
{
$prefix = Caster::PREFIX_VIRTUAL;
$signature = '';
if (isset($a[$prefix.'parameters'])) {
foreach ($a[$prefix.'parameters']->value as $k => $param) {
$signature .= ', ';
if ($type = $param->getType()) {
if (!$type instanceof \ReflectionNamedType) {
$signature .= $type.' ';
} else {
if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) {
$signature .= '?';
}
$signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' ';
}
}
$signature .= $k;
if (!$param->isDefaultValueAvailable()) {
continue;
}
$v = $param->getDefaultValue();
$signature .= ' = ';
if ($param->isDefaultValueConstant()) {
$signature .= substr(strrchr('\\'.$param->getDefaultValueConstantName(), '\\'), 1);
} elseif (null === $v) {
$signature .= 'null';
} elseif (\is_array($v)) {
$signature .= $v ? '[…'.\count($v).']' : '[]';
} elseif (\is_string($v)) {
$signature .= 10 > \strlen($v) && !str_contains($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'";
} elseif (\is_bool($v)) {
$signature .= $v ? 'true' : 'false';
} elseif (\is_object($v)) {
$signature .= 'new '.substr(strrchr('\\'.get_debug_type($v), '\\'), 1);
} else {
$signature .= $v;
}
}
}
$signature = (empty($a[$prefix.'returnsReference']) ? '' : '&').'('.substr($signature, 2).')';
if (isset($a[$prefix.'returnType'])) {
$signature .= ': '.substr(strrchr('\\'.$a[$prefix.'returnType'], '\\'), 1);
}
return $signature;
}
private static function addExtra(array &$a, \Reflector $c)
{
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : [];
if (method_exists($c, 'getFileName') && $m = $c->getFileName()) {
$x['file'] = new LinkStub($m, $c->getStartLine());
$x['line'] = $c->getStartLine().' to '.$c->getEndLine();
}
self::addMap($x, $c, self::EXTRA_MAP, '');
if ($x) {
$a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x);
}
}
private static function addMap(array &$a, $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
{
foreach ($map as $k => $m) {
if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) {
continue;
}
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
}
}
}
}

View File

@@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts common resource types to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ResourceCaster
{
/**
* @param \CurlHandle|resource $h
*
* @return array
*/
public static function castCurl($h, array $a, Stub $stub, $isNested)
{
return curl_getinfo($h);
}
public static function castDba($dba, array $a, Stub $stub, $isNested)
{
$list = dba_list();
$a['file'] = $list[(int) $dba];
return $a;
}
public static function castProcess($process, array $a, Stub $stub, $isNested)
{
return proc_get_status($process);
}
public static function castStream($stream, array $a, Stub $stub, $isNested)
{
$a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested);
if ($a['uri'] ?? false) {
$a['uri'] = new LinkStub($a['uri']);
}
return $a;
}
public static function castStreamContext($stream, array $a, Stub $stub, $isNested)
{
return @stream_context_get_params($stream) ?: $a;
}
public static function castGd($gd, array $a, Stub $stub, $isNested)
{
$a['size'] = imagesx($gd).'x'.imagesy($gd);
$a['trueColor'] = imageistruecolor($gd);
return $a;
}
public static function castMysqlLink($h, array $a, Stub $stub, $isNested)
{
$a['host'] = mysql_get_host_info($h);
$a['protocol'] = mysql_get_proto_info($h);
$a['server'] = mysql_get_server_info($h);
return $a;
}
public static function castOpensslX509($h, array $a, Stub $stub, $isNested)
{
$stub->cut = -1;
$info = openssl_x509_parse($h, false);
$pin = openssl_pkey_get_public($h);
$pin = openssl_pkey_get_details($pin)['key'];
$pin = \array_slice(explode("\n", $pin), 1, -2);
$pin = base64_decode(implode('', $pin));
$pin = base64_encode(hash('sha256', $pin, true));
$a += [
'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])),
'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])),
'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']),
'fingerprint' => new EnumStub([
'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)),
'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)),
'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)),
'pin-sha256' => new ConstStub($pin),
]),
];
return $a;
}
}

View File

@@ -0,0 +1,245 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts SPL related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class SplCaster
{
private const SPL_FILE_OBJECT_FLAGS = [
\SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE',
\SplFileObject::READ_AHEAD => 'READ_AHEAD',
\SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY',
\SplFileObject::READ_CSV => 'READ_CSV',
];
public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested)
{
return self::castSplArray($c, $a, $stub, $isNested);
}
public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, $isNested)
{
return self::castSplArray($c, $a, $stub, $isNested);
}
public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
{
$a += [
Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c),
];
return $a;
}
public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$mode = $c->getIteratorMode();
$c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
$a += [
$prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode),
$prefix.'dllist' => iterator_to_array($c),
];
$c->setIteratorMode($mode);
return $a;
}
public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested)
{
static $map = [
'path' => 'getPath',
'filename' => 'getFilename',
'basename' => 'getBasename',
'pathname' => 'getPathname',
'extension' => 'getExtension',
'realPath' => 'getRealPath',
'aTime' => 'getATime',
'mTime' => 'getMTime',
'cTime' => 'getCTime',
'inode' => 'getInode',
'size' => 'getSize',
'perms' => 'getPerms',
'owner' => 'getOwner',
'group' => 'getGroup',
'type' => 'getType',
'writable' => 'isWritable',
'readable' => 'isReadable',
'executable' => 'isExecutable',
'file' => 'isFile',
'dir' => 'isDir',
'link' => 'isLink',
'linkTarget' => 'getLinkTarget',
];
$prefix = Caster::PREFIX_VIRTUAL;
unset($a["\0SplFileInfo\0fileName"]);
unset($a["\0SplFileInfo\0pathName"]);
if (\PHP_VERSION_ID < 80000) {
if (false === $c->getPathname()) {
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
}
} else {
try {
$c->isReadable();
} catch (\RuntimeException $e) {
if ('Object not initialized' !== $e->getMessage()) {
throw $e;
}
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
} catch (\Error $e) {
if ('Object not initialized' !== $e->getMessage()) {
throw $e;
}
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
}
}
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
if ($a[$prefix.'realPath'] ?? false) {
$a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']);
}
if (isset($a[$prefix.'perms'])) {
$a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
}
static $mapDate = ['aTime', 'mTime', 'cTime'];
foreach ($mapDate as $key) {
if (isset($a[$prefix.$key])) {
$a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]);
}
}
return $a;
}
public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested)
{
static $map = [
'csvControl' => 'getCsvControl',
'flags' => 'getFlags',
'maxLineLen' => 'getMaxLineLen',
'fstat' => 'fstat',
'eof' => 'eof',
'key' => 'key',
];
$prefix = Caster::PREFIX_VIRTUAL;
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
if (isset($a[$prefix.'flags'])) {
$flagsArray = [];
foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) {
if ($a[$prefix.'flags'] & $value) {
$flagsArray[] = $name;
}
}
$a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']);
}
if (isset($a[$prefix.'fstat'])) {
$a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']);
}
return $a;
}
public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested)
{
$storage = [];
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
unset($a["\0SplObjectStorage\0storage"]);
$clone = clone $c;
foreach ($clone as $obj) {
$storage[] = [
'object' => $obj,
'info' => $clone->getInfo(),
];
}
$a += [
Caster::PREFIX_VIRTUAL.'storage' => $storage,
];
return $a;
}
public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator();
return $a;
}
public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'object'] = $c->get();
return $a;
}
private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array
{
$prefix = Caster::PREFIX_VIRTUAL;
$flags = $c->getFlags();
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
$c->setFlags(\ArrayObject::STD_PROP_LIST);
$a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
$c->setFlags($flags);
}
if (\PHP_VERSION_ID < 70400) {
$a[$prefix.'storage'] = $c->getArrayCopy();
}
$a += [
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
];
if ($c instanceof \ArrayObject) {
$a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
}
return $a;
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts a caster's Stub.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class StubCaster
{
public static function castStub(Stub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->type = $c->type;
$stub->class = $c->class;
$stub->value = $c->value;
$stub->handle = $c->handle;
$stub->cut = $c->cut;
$stub->attr = $c->attr;
if (Stub::TYPE_REF === $c->type && !$c->class && \is_string($c->value) && !preg_match('//u', $c->value)) {
$stub->type = Stub::TYPE_STRING;
$stub->class = Stub::STRING_BINARY;
}
$a = [];
}
return $a;
}
public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested)
{
return $isNested ? $c->preservedSubset : $a;
}
public static function cutInternals($obj, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->cut += \count($a);
return [];
}
return $a;
}
public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->class = $c->dumpKeys ? '' : null;
$stub->handle = 0;
$stub->value = null;
$stub->cut = $c->cut;
$stub->attr = $c->attr;
$a = [];
if ($c->value) {
foreach (array_keys($c->value) as $k) {
$keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k;
}
// Preserve references with array_combine()
$a = array_combine($keys, $c->value);
}
}
return $a;
}
}

View File

@@ -0,0 +1,69 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @final since Symfony 4.4
*/
class SymfonyCaster
{
private const REQUEST_GETTERS = [
'pathInfo' => 'getPathInfo',
'requestUri' => 'getRequestUri',
'baseUrl' => 'getBaseUrl',
'basePath' => 'getBasePath',
'method' => 'getMethod',
'format' => 'getRequestFormat',
];
public static function castRequest(Request $request, array $a, Stub $stub, $isNested)
{
$clone = null;
foreach (self::REQUEST_GETTERS as $prop => $getter) {
$key = Caster::PREFIX_PROTECTED.$prop;
if (\array_key_exists($key, $a) && null === $a[$key]) {
if (null === $clone) {
$clone = clone $request;
}
$a[Caster::PREFIX_VIRTUAL.$prop] = $clone->{$getter}();
}
}
return $a;
}
public static function castHttpClient($client, array $a, Stub $stub, $isNested)
{
$multiKey = sprintf("\0%s\0multi", \get_class($client));
if (isset($a[$multiKey])) {
$a[$multiKey] = new CutStub($a[$multiKey]);
}
return $a;
}
public static function castHttpClientResponse($response, array $a, Stub $stub, $isNested)
{
$stub->cut += \count($a);
$a = [];
foreach ($response->getInfo() as $k => $v) {
$a[Caster::PREFIX_VIRTUAL.$k] = $v;
}
return $a;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Represents a backtrace as returned by debug_backtrace() or Exception->getTrace().
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class TraceStub extends Stub
{
public $keepArgs;
public $sliceOffset;
public $sliceLength;
public $numberingOffset;
public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0)
{
$this->value = $trace;
$this->keepArgs = $keepArgs;
$this->sliceOffset = $sliceOffset;
$this->sliceLength = $sliceLength;
$this->numberingOffset = $numberingOffset;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
final class UuidCaster
{
public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested): array
{
$a += [
Caster::PREFIX_VIRTUAL.'uuid' => (string) $c,
];
return $a;
}
}

View File

@@ -0,0 +1,91 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts XmlReader class to array representation.
*
* @author Baptiste Clavié <clavie.b@gmail.com>
*
* @final since Symfony 4.4
*/
class XmlReaderCaster
{
private const NODE_TYPES = [
\XMLReader::NONE => 'NONE',
\XMLReader::ELEMENT => 'ELEMENT',
\XMLReader::ATTRIBUTE => 'ATTRIBUTE',
\XMLReader::TEXT => 'TEXT',
\XMLReader::CDATA => 'CDATA',
\XMLReader::ENTITY_REF => 'ENTITY_REF',
\XMLReader::ENTITY => 'ENTITY',
\XMLReader::PI => 'PI (Processing Instruction)',
\XMLReader::COMMENT => 'COMMENT',
\XMLReader::DOC => 'DOC',
\XMLReader::DOC_TYPE => 'DOC_TYPE',
\XMLReader::DOC_FRAGMENT => 'DOC_FRAGMENT',
\XMLReader::NOTATION => 'NOTATION',
\XMLReader::WHITESPACE => 'WHITESPACE',
\XMLReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE',
\XMLReader::END_ELEMENT => 'END_ELEMENT',
\XMLReader::END_ENTITY => 'END_ENTITY',
\XMLReader::XML_DECLARATION => 'XML_DECLARATION',
];
public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, $isNested)
{
try {
$properties = [
'LOADDTD' => @$reader->getParserProperty(\XMLReader::LOADDTD),
'DEFAULTATTRS' => @$reader->getParserProperty(\XMLReader::DEFAULTATTRS),
'VALIDATE' => @$reader->getParserProperty(\XMLReader::VALIDATE),
'SUBST_ENTITIES' => @$reader->getParserProperty(\XMLReader::SUBST_ENTITIES),
];
} catch (\Error $e) {
$properties = [
'LOADDTD' => false,
'DEFAULTATTRS' => false,
'VALIDATE' => false,
'SUBST_ENTITIES' => false,
];
}
$props = Caster::PREFIX_VIRTUAL.'parserProperties';
$info = [
'localName' => $reader->localName,
'prefix' => $reader->prefix,
'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType),
'depth' => $reader->depth,
'isDefault' => $reader->isDefault,
'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement,
'xmlLang' => $reader->xmlLang,
'attributeCount' => $reader->attributeCount,
'value' => $reader->value,
'namespaceURI' => $reader->namespaceURI,
'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI,
$props => $properties,
];
if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) {
$info[$props] = new EnumStub($info[$props]);
$info[$props]->cut = $count;
}
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count);
// +2 because hasValue and hasAttributes are always filtered
$stub->cut += $count + 2;
return $a + $info;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts XML resources to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class XmlResourceCaster
{
private const XML_ERRORS = [
\XML_ERROR_NONE => 'XML_ERROR_NONE',
\XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY',
\XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX',
\XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS',
\XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN',
\XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN',
\XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR',
\XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH',
\XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE',
\XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT',
\XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF',
\XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY',
\XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF',
\XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY',
\XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF',
\XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF',
\XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF',
\XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI',
\XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING',
\XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING',
\XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION',
\XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING',
];
public static function castXml($h, array $a, Stub $stub, $isNested)
{
$a['current_byte_index'] = xml_get_current_byte_index($h);
$a['current_column_number'] = xml_get_current_column_number($h);
$a['current_line_number'] = xml_get_current_line_number($h);
$a['error_code'] = xml_get_error_code($h);
if (isset(self::XML_ERRORS[$a['error_code']])) {
$a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']);
}
return $a;
}
}

View File

@@ -0,0 +1,377 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
/**
* AbstractCloner implements a generic caster mechanism for objects and resources.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
abstract class AbstractCloner implements ClonerInterface
{
public static $defaultCasters = [
'__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'],
'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'],
'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'],
'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'],
'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'],
'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'],
'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'],
'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'],
'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'],
'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'],
'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'],
'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'],
'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'],
'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'],
'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'],
'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'],
'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'],
'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'],
'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'],
'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'],
'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'],
'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'],
'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'],
'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'],
'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'],
'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'],
'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'],
'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'],
'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'],
'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'],
'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'],
'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'],
'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'],
'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'],
'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'],
'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'],
'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'],
'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'],
'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'],
'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],
'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],
'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'],
'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'],
'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'],
'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'],
'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'],
'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'],
'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'],
'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'],
'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'],
'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'],
'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'],
'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'],
'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'],
'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'],
'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'],
'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'],
'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'],
'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'],
'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'],
'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'],
'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'],
'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'],
'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'],
'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'],
'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'],
'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'],
'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'],
'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'],
'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'],
'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'],
'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'],
'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'],
'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'],
'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'],
'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'],
'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'],
'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'],
'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'],
'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'],
'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'],
'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'],
'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'],
'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'],
':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'],
':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],
':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],
'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],
':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],
':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'],
':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'],
':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],
':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],
':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'],
':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'],
':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],
'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],
':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],
':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],
':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'],
'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],
':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],
];
protected $maxItems = 2500;
protected $maxString = -1;
protected $minDepth = 1;
private $casters = [];
private $prevErrorHandler;
private $classInfo = [];
private $filter = 0;
/**
* @param callable[]|null $casters A map of casters
*
* @see addCasters
*/
public function __construct(array $casters = null)
{
if (null === $casters) {
$casters = static::$defaultCasters;
}
$this->addCasters($casters);
}
/**
* Adds casters for resources and objects.
*
* Maps resources or objects types to a callback.
* Types are in the key, with a callable caster for value.
* Resource types are to be prefixed with a `:`,
* see e.g. static::$defaultCasters.
*
* @param callable[] $casters A map of casters
*/
public function addCasters(array $casters)
{
foreach ($casters as $type => $callback) {
$this->casters[$type][] = $callback;
}
}
/**
* Sets the maximum number of items to clone past the minimum depth in nested structures.
*
* @param int $maxItems
*/
public function setMaxItems($maxItems)
{
$this->maxItems = (int) $maxItems;
}
/**
* Sets the maximum cloned length for strings.
*
* @param int $maxString
*/
public function setMaxString($maxString)
{
$this->maxString = (int) $maxString;
}
/**
* Sets the minimum tree depth where we are guaranteed to clone all the items. After this
* depth is reached, only setMaxItems items will be cloned.
*
* @param int $minDepth
*/
public function setMinDepth($minDepth)
{
$this->minDepth = (int) $minDepth;
}
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable
* @param int $filter A bit field of Caster::EXCLUDE_* constants
*
* @return Data The cloned variable represented by a Data object
*/
public function cloneVar($var, $filter = 0)
{
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) {
if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) {
// Cloner never dies
throw new \ErrorException($msg, 0, $type, $file, $line);
}
if ($this->prevErrorHandler) {
return ($this->prevErrorHandler)($type, $msg, $file, $line, $context);
}
return false;
});
$this->filter = $filter;
if ($gc = gc_enabled()) {
gc_disable();
}
try {
return new Data($this->doClone($var));
} finally {
if ($gc) {
gc_enable();
}
restore_error_handler();
$this->prevErrorHandler = null;
}
}
/**
* Effectively clones the PHP variable.
*
* @param mixed $var Any PHP variable
*
* @return array The cloned variable represented in an array
*/
abstract protected function doClone($var);
/**
* Casts an object to an array representation.
*
* @param bool $isNested True if the object is nested in the dumped structure
*
* @return array The object casted as array
*/
protected function castObject(Stub $stub, $isNested)
{
$obj = $stub->value;
$class = $stub->class;
if (\PHP_VERSION_ID < 80000 ? "\0" === ($class[15] ?? null) : str_contains($class, "@anonymous\0")) {
$stub->class = get_debug_type($obj);
}
if (isset($this->classInfo[$class])) {
[$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class];
} else {
$i = 2;
$parents = [$class];
$hasDebugInfo = method_exists($class, '__debugInfo');
foreach (class_parents($class) as $p) {
$parents[] = $p;
++$i;
}
foreach (class_implements($class) as $p) {
$parents[] = $p;
++$i;
}
$parents[] = '*';
$r = new \ReflectionClass($class);
$fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
];
$this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo];
}
$stub->attr += $fileInfo;
$a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class);
try {
while ($i--) {
if (!empty($this->casters[$p = $parents[$i]])) {
foreach ($this->casters[$p] as $callback) {
$a = $callback($obj, $a, $stub, $isNested, $this->filter);
}
}
}
} catch (\Exception $e) {
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
}
return $a;
}
/**
* Casts a resource to an array representation.
*
* @param bool $isNested True if the object is nested in the dumped structure
*
* @return array The resource casted as array
*/
protected function castResource(Stub $stub, $isNested)
{
$a = [];
$res = $stub->value;
$type = $stub->class;
try {
if (!empty($this->casters[':'.$type])) {
foreach ($this->casters[':'.$type] as $callback) {
$a = $callback($res, $a, $stub, $isNested, $this->filter);
}
}
} catch (\Exception $e) {
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
}
return $a;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
interface ClonerInterface
{
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable
*
* @return Data The cloned variable represented by a Data object
*/
public function cloneVar($var);
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
/**
* Represents the current state of a dumper while dumping.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Cursor
{
public const HASH_INDEXED = Stub::ARRAY_INDEXED;
public const HASH_ASSOC = Stub::ARRAY_ASSOC;
public const HASH_OBJECT = Stub::TYPE_OBJECT;
public const HASH_RESOURCE = Stub::TYPE_RESOURCE;
public $depth = 0;
public $refIndex = 0;
public $softRefTo = 0;
public $softRefCount = 0;
public $softRefHandle = 0;
public $hardRefTo = 0;
public $hardRefCount = 0;
public $hardRefHandle = 0;
public $hashType;
public $hashKey;
public $hashKeyIsBinary;
public $hashIndex = 0;
public $hashLength = 0;
public $hashCut = 0;
public $stop = false;
public $attr = [];
public $skipChildren = false;
}

View File

@@ -0,0 +1,470 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class Data implements \ArrayAccess, \Countable, \IteratorAggregate
{
private $data;
private $position = 0;
private $key = 0;
private $maxDepth = 20;
private $maxItemsPerDepth = -1;
private $useRefHandles = -1;
private $context = [];
/**
* @param array $data An array as returned by ClonerInterface::cloneVar()
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* @return string|null The type of the value
*/
public function getType()
{
$item = $this->data[$this->position][$this->key];
if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
$item = $item->value;
}
if (!$item instanceof Stub) {
return \gettype($item);
}
if (Stub::TYPE_STRING === $item->type) {
return 'string';
}
if (Stub::TYPE_ARRAY === $item->type) {
return 'array';
}
if (Stub::TYPE_OBJECT === $item->type) {
return $item->class;
}
if (Stub::TYPE_RESOURCE === $item->type) {
return $item->class.' resource';
}
return null;
}
/**
* @param array|bool $recursive Whether values should be resolved recursively or not
*
* @return string|int|float|bool|array|Data[]|null A native representation of the original value
*/
public function getValue($recursive = false)
{
$item = $this->data[$this->position][$this->key];
if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
$item = $item->value;
}
if (!($item = $this->getStub($item)) instanceof Stub) {
return $item;
}
if (Stub::TYPE_STRING === $item->type) {
return $item->value;
}
$children = $item->position ? $this->data[$item->position] : [];
foreach ($children as $k => $v) {
if ($recursive && !($v = $this->getStub($v)) instanceof Stub) {
continue;
}
$children[$k] = clone $this;
$children[$k]->key = $k;
$children[$k]->position = $item->position;
if ($recursive) {
if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) {
$recursive = (array) $recursive;
if (isset($recursive[$v->position])) {
continue;
}
$recursive[$v->position] = true;
}
$children[$k] = $children[$k]->getValue($recursive);
}
}
return $children;
}
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return \count($this->getValue());
}
/**
* @return \Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
if (!\is_array($value = $this->getValue())) {
throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, \gettype($value)));
}
yield from $value;
}
public function __get($key)
{
if (null !== $data = $this->seek($key)) {
$item = $this->getStub($data->data[$data->position][$data->key]);
return $item instanceof Stub || [] === $item ? $data : $item;
}
return null;
}
/**
* @return bool
*/
public function __isset($key)
{
return null !== $this->seek($key);
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($key)
{
return $this->__isset($key);
}
/**
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->__get($key);
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($key, $value)
{
throw new \BadMethodCallException(self::class.' objects are immutable.');
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($key)
{
throw new \BadMethodCallException(self::class.' objects are immutable.');
}
/**
* @return string
*/
public function __toString()
{
$value = $this->getValue();
if (!\is_array($value)) {
return (string) $value;
}
return sprintf('%s (count=%d)', $this->getType(), \count($value));
}
/**
* Returns a depth limited clone of $this.
*
* @param int $maxDepth The max dumped depth level
*
* @return static
*/
public function withMaxDepth($maxDepth)
{
$data = clone $this;
$data->maxDepth = (int) $maxDepth;
return $data;
}
/**
* Limits the number of elements per depth level.
*
* @param int $maxItemsPerDepth The max number of items dumped per depth level
*
* @return static
*/
public function withMaxItemsPerDepth($maxItemsPerDepth)
{
$data = clone $this;
$data->maxItemsPerDepth = (int) $maxItemsPerDepth;
return $data;
}
/**
* Enables/disables objects' identifiers tracking.
*
* @param bool $useRefHandles False to hide global ref. handles
*
* @return static
*/
public function withRefHandles($useRefHandles)
{
$data = clone $this;
$data->useRefHandles = $useRefHandles ? -1 : 0;
return $data;
}
/**
* @return static
*/
public function withContext(array $context)
{
$data = clone $this;
$data->context = $context;
return $data;
}
/**
* Seeks to a specific key in nested data structures.
*
* @param string|int $key The key to seek to
*
* @return static|null Null if the key is not set
*/
public function seek($key)
{
$item = $this->data[$this->position][$this->key];
if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
$item = $item->value;
}
if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) {
return null;
}
$keys = [$key];
switch ($item->type) {
case Stub::TYPE_OBJECT:
$keys[] = Caster::PREFIX_DYNAMIC.$key;
$keys[] = Caster::PREFIX_PROTECTED.$key;
$keys[] = Caster::PREFIX_VIRTUAL.$key;
$keys[] = "\0$item->class\0$key";
// no break
case Stub::TYPE_ARRAY:
case Stub::TYPE_RESOURCE:
break;
default:
return null;
}
$data = null;
$children = $this->data[$item->position];
foreach ($keys as $key) {
if (isset($children[$key]) || \array_key_exists($key, $children)) {
$data = clone $this;
$data->key = $key;
$data->position = $item->position;
break;
}
}
return $data;
}
/**
* Dumps data with a DumperInterface dumper.
*/
public function dump(DumperInterface $dumper)
{
$refs = [0];
$cursor = new Cursor();
if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
$cursor->attr['if_links'] = true;
$cursor->hashType = -1;
$dumper->dumpScalar($cursor, 'default', '^');
$cursor->attr = ['if_links' => true];
$dumper->dumpScalar($cursor, 'default', ' ');
$cursor->hashType = 0;
}
$this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
}
/**
* Depth-first dumping of items.
*
* @param mixed $item A Stub object or the original value being dumped
*/
private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item)
{
$cursor->refIndex = 0;
$cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
$cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
$firstSeen = true;
if (!$item instanceof Stub) {
$cursor->attr = [];
$type = \gettype($item);
if ($item && 'array' === $type) {
$item = $this->getStub($item);
}
} elseif (Stub::TYPE_REF === $item->type) {
if ($item->handle) {
if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) {
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
} else {
$firstSeen = false;
}
$cursor->hardRefTo = $refs[$r];
$cursor->hardRefHandle = $this->useRefHandles & $item->handle;
$cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0;
}
$cursor->attr = $item->attr;
$type = $item->class ?: \gettype($item->value);
$item = $this->getStub($item->value);
}
if ($item instanceof Stub) {
if ($item->refCount) {
if (!isset($refs[$r = $item->handle])) {
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
} else {
$firstSeen = false;
}
$cursor->softRefTo = $refs[$r];
}
$cursor->softRefHandle = $this->useRefHandles & $item->handle;
$cursor->softRefCount = $item->refCount;
$cursor->attr = $item->attr;
$cut = $item->cut;
if ($item->position && $firstSeen) {
$children = $this->data[$item->position];
if ($cursor->stop) {
if ($cut >= 0) {
$cut += \count($children);
}
$children = [];
}
} else {
$children = [];
}
switch ($item->type) {
case Stub::TYPE_STRING:
$dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
break;
case Stub::TYPE_ARRAY:
$item = clone $item;
$item->type = $item->class;
$item->class = $item->value;
// no break
case Stub::TYPE_OBJECT:
case Stub::TYPE_RESOURCE:
$withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
$dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
if ($withChildren) {
if ($cursor->skipChildren) {
$withChildren = false;
$cut = -1;
} else {
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
}
} elseif ($children && 0 <= $cut) {
$cut += \count($children);
}
$cursor->skipChildren = false;
$dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
break;
default:
throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type));
}
} elseif ('array' === $type) {
$dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
$dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
} elseif ('string' === $type) {
$dumper->dumpString($cursor, $item, false, 0);
} else {
$dumper->dumpScalar($cursor, $type, $item);
}
}
/**
* Dumps children of hash structures.
*
* @return int The final number of removed items
*/
private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int
{
$cursor = clone $parentCursor;
++$cursor->depth;
$cursor->hashType = $hashType;
$cursor->hashIndex = 0;
$cursor->hashLength = \count($children);
$cursor->hashCut = $hashCut;
foreach ($children as $key => $child) {
$cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key);
$cursor->hashKey = $dumpKeys ? $key : null;
$this->dumpItem($dumper, $cursor, $refs, $child);
if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
$parentCursor->stop = true;
return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
}
}
return $hashCut;
}
private function getStub($item)
{
if (!$item || !\is_array($item)) {
return $item;
}
$stub = new Stub();
$stub->type = Stub::TYPE_ARRAY;
foreach ($item as $stub->class => $stub->position) {
}
if (isset($item[0])) {
$stub->cut = $item[0];
}
$stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0);
return $stub;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
/**
* DumperInterface used by Data objects.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface DumperInterface
{
/**
* Dumps a scalar value.
*
* @param string $type The PHP type of the value being dumped
* @param string|int|float|bool $value The scalar value being dumped
*/
public function dumpScalar(Cursor $cursor, $type, $value);
/**
* Dumps a string.
*
* @param string $str The string being dumped
* @param bool $bin Whether $str is UTF-8 or binary encoded
* @param int $cut The number of characters $str has been cut by
*/
public function dumpString(Cursor $cursor, $str, $bin, $cut);
/**
* Dumps while entering an hash.
*
* @param int $type A Cursor::HASH_* const for the type of hash
* @param string|int $class The object class, resource type or array count
* @param bool $hasChild When the dump of the hash has child item
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild);
/**
* Dumps while leaving an hash.
*
* @param int $type A Cursor::HASH_* const for the type of hash
* @param string|int $class The object class, resource type or array count
* @param bool $hasChild When the dump of the hash has child item
* @param int $cut The number of items the hash has been cut by
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
/**
* Represents the main properties of a PHP variable.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Stub
{
public const TYPE_REF = 1;
public const TYPE_STRING = 2;
public const TYPE_ARRAY = 3;
public const TYPE_OBJECT = 4;
public const TYPE_RESOURCE = 5;
public const STRING_BINARY = 1;
public const STRING_UTF8 = 2;
public const ARRAY_ASSOC = 1;
public const ARRAY_INDEXED = 2;
public $type = self::TYPE_REF;
public $class = '';
public $value;
public $cut = 0;
public $handle = 0;
public $refCount = 0;
public $position = 0;
public $attr = [];
private static $defaultProperties = [];
/**
* @internal
*/
public function __sleep(): array
{
$properties = [];
if (!isset(self::$defaultProperties[$c = static::class])) {
self::$defaultProperties[$c] = get_class_vars($c);
foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) {
unset(self::$defaultProperties[$c][$k]);
}
}
foreach (self::$defaultProperties[$c] as $k => $v) {
if ($this->$k !== $v) {
$properties[] = $k;
}
}
return $properties;
}
}

View File

@@ -0,0 +1,324 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Cloner;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class VarCloner extends AbstractCloner
{
private static $gid;
private static $arrayCache = [];
/**
* {@inheritdoc}
*/
protected function doClone($var)
{
$len = 1; // Length of $queue
$pos = 0; // Number of cloned items past the minimum depth
$refsCounter = 0; // Hard references counter
$queue = [[$var]]; // This breadth-first queue is the return value
$indexedArrays = []; // Map of queue indexes that hold numerically indexed arrays
$hardRefs = []; // Map of original zval ids to stub objects
$objRefs = []; // Map of original object handles to their stub object counterpart
$objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning
$resRefs = []; // Map of original resource handles to their stub object counterpart
$values = []; // Map of stub objects' ids to original values
$maxItems = $this->maxItems;
$maxString = $this->maxString;
$minDepth = $this->minDepth;
$currentDepth = 0; // Current tree depth
$currentDepthFinalIndex = 0; // Final $queue index for current tree depth
$minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached
$cookie = (object) []; // Unique object used to detect hard references
$a = null; // Array cast for nested structures
$stub = null; // Stub capturing the main properties of an original item value
// or null if the original value is used directly
if (!$gid = self::$gid) {
$gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable
}
$arrayStub = new Stub();
$arrayStub->type = Stub::TYPE_ARRAY;
$fromObjCast = false;
for ($i = 0; $i < $len; ++$i) {
// Detect when we move on to the next tree depth
if ($i > $currentDepthFinalIndex) {
++$currentDepth;
$currentDepthFinalIndex = $len - 1;
if ($currentDepth >= $minDepth) {
$minimumDepthReached = true;
}
}
$refs = $vals = $queue[$i];
if (\PHP_VERSION_ID < 70200 && empty($indexedArrays[$i])) {
// see https://wiki.php.net/rfc/convert_numeric_keys_in_object_array_casts
foreach ($vals as $k => $v) {
if (\is_int($k)) {
continue;
}
foreach ([$k => true] as $gk => $gv) {
}
if ($gk !== $k) {
$fromObjCast = true;
$refs = $vals = array_values($queue[$i]);
break;
}
}
}
foreach ($vals as $k => $v) {
// $v is the original value or a stub object in case of hard references
if (\PHP_VERSION_ID >= 70400) {
$zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null;
} else {
$refs[$k] = $cookie;
$zvalRef = $vals[$k] === $cookie;
}
if ($zvalRef) {
$vals[$k] = &$stub; // Break hard references to make $queue completely
unset($stub); // independent from the original structure
if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) {
if (\PHP_VERSION_ID >= 70400) {
$v = $vals[$k];
} else {
$refs[$k] = $vals[$k] = $v;
}
if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) {
++$v->value->refCount;
}
++$v->refCount;
continue;
}
$vals[$k] = new Stub();
$vals[$k]->value = $v;
$vals[$k]->handle = ++$refsCounter;
if (\PHP_VERSION_ID >= 70400) {
$hardRefs[$zvalRef] = $vals[$k];
} else {
$refs[$k] = $vals[$k];
$h = spl_object_id($refs[$k]);
$hardRefs[$h] = &$refs[$k];
$values[$h] = $v;
}
}
// Create $stub when the original value $v can not be used directly
// If $v is a nested structure, put that structure in array $a
switch (true) {
case null === $v:
case \is_bool($v):
case \is_int($v):
case \is_float($v):
continue 2;
case \is_string($v):
if ('' === $v) {
continue 2;
}
if (!preg_match('//u', $v)) {
$stub = new Stub();
$stub->type = Stub::TYPE_STRING;
$stub->class = Stub::STRING_BINARY;
if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) {
$stub->cut = $cut;
$stub->value = substr($v, 0, -$cut);
} else {
$stub->value = $v;
}
} elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) {
$stub = new Stub();
$stub->type = Stub::TYPE_STRING;
$stub->class = Stub::STRING_UTF8;
$stub->cut = $cut;
$stub->value = mb_substr($v, 0, $maxString, 'UTF-8');
} else {
continue 2;
}
$a = null;
break;
case \is_array($v):
if (!$v) {
continue 2;
}
$stub = $arrayStub;
$stub->class = Stub::ARRAY_INDEXED;
$j = -1;
foreach ($v as $gk => $gv) {
if ($gk !== ++$j) {
$stub->class = Stub::ARRAY_ASSOC;
break;
}
}
$a = $v;
if (Stub::ARRAY_ASSOC === $stub->class) {
// Copies of $GLOBALS have very strange behavior,
// let's detect them with some black magic
if (\PHP_VERSION_ID < 80100 && ($a[$gid] = true) && isset($v[$gid])) {
unset($v[$gid]);
$a = [];
foreach ($v as $gk => &$gv) {
if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) {
unset($v);
$v = new Stub();
$v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0];
$v->handle = -1;
if (\PHP_VERSION_ID >= 70400) {
$gv = &$a[$gk];
$hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv;
} else {
$gv = &$hardRefs[spl_object_id($v)];
}
$gv = $v;
}
$a[$gk] = &$gv;
}
unset($gv);
} else {
$a = $v;
}
} elseif (\PHP_VERSION_ID < 70200) {
$indexedArrays[$len] = true;
}
break;
case \is_object($v):
case $v instanceof \__PHP_Incomplete_Class:
if (empty($objRefs[$h = spl_object_id($v)])) {
$stub = new Stub();
$stub->type = Stub::TYPE_OBJECT;
$stub->class = \get_class($v);
$stub->value = $v;
$stub->handle = $h;
$a = $this->castObject($stub, 0 < $i);
if ($v !== $stub->value) {
if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
break;
}
$stub->handle = $h = spl_object_id($stub->value);
}
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
$stub->cut = \count($a);
$a = null;
}
}
if (empty($objRefs[$h])) {
$objRefs[$h] = $stub;
$objects[] = $v;
} else {
$stub = $objRefs[$h];
++$stub->refCount;
$a = null;
}
break;
default: // resource
if (empty($resRefs[$h = (int) $v])) {
$stub = new Stub();
$stub->type = Stub::TYPE_RESOURCE;
if ('Unknown' === $stub->class = @get_resource_type($v)) {
$stub->class = 'Closed';
}
$stub->value = $v;
$stub->handle = $h;
$a = $this->castResource($stub, 0 < $i);
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
$stub->cut = \count($a);
$a = null;
}
}
if (empty($resRefs[$h])) {
$resRefs[$h] = $stub;
} else {
$stub = $resRefs[$h];
++$stub->refCount;
$a = null;
}
break;
}
if ($a) {
if (!$minimumDepthReached || 0 > $maxItems) {
$queue[$len] = $a;
$stub->position = $len++;
} elseif ($pos < $maxItems) {
if ($maxItems < $pos += \count($a)) {
$a = \array_slice($a, 0, $maxItems - $pos, true);
if ($stub->cut >= 0) {
$stub->cut += $pos - $maxItems;
}
}
$queue[$len] = $a;
$stub->position = $len++;
} elseif ($stub->cut >= 0) {
$stub->cut += \count($a);
$stub->position = 0;
}
}
if ($arrayStub === $stub) {
if ($arrayStub->cut) {
$stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position];
$arrayStub->cut = 0;
} elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) {
$stub = self::$arrayCache[$arrayStub->class][$arrayStub->position];
} else {
self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position];
}
}
if (!$zvalRef) {
$vals[$k] = $stub;
} elseif (\PHP_VERSION_ID >= 70400) {
$hardRefs[$zvalRef]->value = $stub;
} else {
$refs[$k]->value = $stub;
}
}
if ($fromObjCast) {
$fromObjCast = false;
$refs = $vals;
$vals = [];
$j = -1;
foreach ($queue[$i] as $k => $v) {
foreach ([$k => true] as $gk => $gv) {
}
if ($gk !== $k) {
$vals = (object) $vals;
$vals->{$k} = $refs[++$j];
$vals = (array) $vals;
} else {
$vals[$k] = $refs[++$j];
}
}
}
$queue[$i] = $vals;
}
foreach ($values as $h => $v) {
$hardRefs[$h] = $v;
}
return $queue;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Command\Descriptor;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\CliDumper;
/**
* Describe collected data clones for cli output.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
class CliDescriptor implements DumpDescriptorInterface
{
private $dumper;
private $lastIdentifier;
private $supportsHref;
public function __construct(CliDumper $dumper)
{
$this->dumper = $dumper;
$this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref');
}
public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void
{
$io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output);
$this->dumper->setColors($output->isDecorated());
$rows = [['date', date('r', (int) $context['timestamp'])]];
$lastIdentifier = $this->lastIdentifier;
$this->lastIdentifier = $clientId;
$section = "Received from client #$clientId";
if (isset($context['request'])) {
$request = $context['request'];
$this->lastIdentifier = $request['identifier'];
$section = sprintf('%s %s', $request['method'], $request['uri']);
if ($controller = $request['controller']) {
$rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")];
}
} elseif (isset($context['cli'])) {
$this->lastIdentifier = $context['cli']['identifier'];
$section = '$ '.$context['cli']['command_line'];
}
if ($this->lastIdentifier !== $lastIdentifier) {
$io->section($section);
}
if (isset($context['source'])) {
$source = $context['source'];
$sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']);
$fileLink = $source['file_link'] ?? null;
if ($this->supportsHref && $fileLink) {
$sourceInfo = sprintf('<href=%s>%s</>', $fileLink, $sourceInfo);
}
$rows[] = ['source', $sourceInfo];
$file = $source['file_relative'] ?? $source['file'];
$rows[] = ['file', $file];
}
$io->table([], $rows);
if (!$this->supportsHref && isset($fileLink)) {
$io->writeln(['<info>Open source in your IDE/browser:</info>', $fileLink]);
$io->newLine();
}
$this->dumper->dump($data);
$io->newLine();
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Command\Descriptor;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
interface DumpDescriptorInterface
{
public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void;
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Command\Descriptor;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
/**
* Describe collected data clones for html output.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
class HtmlDescriptor implements DumpDescriptorInterface
{
private $dumper;
private $initialized = false;
public function __construct(HtmlDumper $dumper)
{
$this->dumper = $dumper;
}
public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void
{
if (!$this->initialized) {
$styles = file_get_contents(__DIR__.'/../../Resources/css/htmlDescriptor.css');
$scripts = file_get_contents(__DIR__.'/../../Resources/js/htmlDescriptor.js');
$output->writeln("<style>$styles</style><script>$scripts</script>");
$this->initialized = true;
}
$title = '-';
if (isset($context['request'])) {
$request = $context['request'];
$controller = "<span class='dumped-tag'>{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}</span>";
$title = sprintf('<code>%s</code> <a href="%s">%s</a>', $request['method'], $uri = $request['uri'], $uri);
$dedupIdentifier = $request['identifier'];
} elseif (isset($context['cli'])) {
$title = '<code>$ </code>'.$context['cli']['command_line'];
$dedupIdentifier = $context['cli']['identifier'];
} else {
$dedupIdentifier = uniqid('', true);
}
$sourceDescription = '';
if (isset($context['source'])) {
$source = $context['source'];
$projectDir = $source['project_dir'] ?? null;
$sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']);
if (isset($source['file_link'])) {
$sourceDescription = sprintf('<a href="%s">%s</a>', $source['file_link'], $sourceDescription);
}
}
$isoDate = $this->extractDate($context, 'c');
$tags = array_filter([
'controller' => $controller ?? null,
'project dir' => $projectDir ?? null,
]);
$output->writeln(<<<HTML
<article data-dedup-id="$dedupIdentifier">
<header>
<div class="row">
<h2 class="col">$title</h2>
<time class="col text-small" title="$isoDate" datetime="$isoDate">
{$this->extractDate($context)}
</time>
</div>
{$this->renderTags($tags)}
</header>
<section class="body">
<p class="text-small">
$sourceDescription
</p>
{$this->dumper->dump($data, true)}
</section>
</article>
HTML
);
}
private function extractDate(array $context, string $format = 'r'): string
{
return date($format, (int) $context['timestamp']);
}
private function renderTags(array $tags): string
{
if (!$tags) {
return '';
}
$renderedTags = '';
foreach ($tags as $key => $value) {
$renderedTags .= sprintf('<li><span class="badge">%s</span>%s</li>', $key, $value);
}
return <<<HTML
<div class="row">
<ul class="tags">
$renderedTags
</ul>
</div>
HTML;
}
}

View File

@@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor;
use Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface;
use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Server\DumpServer;
/**
* Starts a dump server to collect and output dumps on a single place with multiple formats support.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
class ServerDumpCommand extends Command
{
protected static $defaultName = 'server:dump';
private $server;
/** @var DumpDescriptorInterface[] */
private $descriptors;
public function __construct(DumpServer $server, array $descriptors = [])
{
$this->server = $server;
$this->descriptors = $descriptors + [
'cli' => new CliDescriptor(new CliDumper()),
'html' => new HtmlDescriptor(new HtmlDumper()),
];
parent::__construct();
}
protected function configure()
{
$availableFormats = implode(', ', array_keys($this->descriptors));
$this
->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', $availableFormats), 'cli')
->setDescription('Start a dump server that collects and displays dumps in a single place')
->setHelp(<<<'EOF'
<info>%command.name%</info> starts a dump server that collects and displays
dumps in a single place for debugging you application:
<info>php %command.full_name%</info>
You can consult dumped data in HTML format in your browser by providing the <comment>--format=html</comment> option
and redirecting the output to a file:
<info>php %command.full_name% --format="html" > dump.html</info>
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$format = $input->getOption('format');
if (!$descriptor = $this->descriptors[$format] ?? null) {
throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format));
}
$errorIo = $io->getErrorStyle();
$errorIo->title('Symfony Var Dumper Server');
$this->server->start();
$errorIo->success(sprintf('Server listening on %s', $this->server->getHost()));
$errorIo->comment('Quit the server with CONTROL-C.');
$this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) {
$descriptor->describe($io, $data, $context, $clientId);
});
return 0;
}
}

View File

@@ -0,0 +1,210 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Dumper;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\DumperInterface;
/**
* Abstract mechanism for dumping a Data object.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
abstract class AbstractDumper implements DataDumperInterface, DumperInterface
{
public const DUMP_LIGHT_ARRAY = 1;
public const DUMP_STRING_LENGTH = 2;
public const DUMP_COMMA_SEPARATOR = 4;
public const DUMP_TRAILING_COMMA = 8;
public static $defaultOutput = 'php://output';
protected $line = '';
protected $lineDumper;
protected $outputStream;
protected $decimalPoint; // This is locale dependent
protected $indentPad = ' ';
protected $flags;
private $charset = '';
/**
* @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput
* @param string|null $charset The default character encoding to use for non-UTF8 strings
* @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation
*/
public function __construct($output = null, string $charset = null, int $flags = 0)
{
$this->flags = $flags;
$this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8');
$this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point'];
$this->setOutput($output ?: static::$defaultOutput);
if (!$output && \is_string(static::$defaultOutput)) {
static::$defaultOutput = $this->outputStream;
}
}
/**
* Sets the output destination of the dumps.
*
* @param callable|resource|string $output A line dumper callable, an opened stream or an output path
*
* @return callable|resource|string The previous output destination
*/
public function setOutput($output)
{
$prev = $this->outputStream ?? $this->lineDumper;
if (\is_callable($output)) {
$this->outputStream = null;
$this->lineDumper = $output;
} else {
if (\is_string($output)) {
$output = fopen($output, 'w');
}
$this->outputStream = $output;
$this->lineDumper = [$this, 'echoLine'];
}
return $prev;
}
/**
* Sets the default character encoding to use for non-UTF8 strings.
*
* @param string $charset The default character encoding to use for non-UTF8 strings
*
* @return string The previous charset
*/
public function setCharset($charset)
{
$prev = $this->charset;
$charset = strtoupper($charset);
$charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset;
$this->charset = $charset;
return $prev;
}
/**
* Sets the indentation pad string.
*
* @param string $pad A string that will be prepended to dumped lines, repeated by nesting level
*
* @return string The previous indent pad
*/
public function setIndentPad($pad)
{
$prev = $this->indentPad;
$this->indentPad = $pad;
return $prev;
}
/**
* Dumps a Data object.
*
* @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump
*
* @return string|null The dump as string when $output is true
*/
public function dump(Data $data, $output = null)
{
$this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point'];
if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(\LC_NUMERIC, 0) : null) {
setlocale(\LC_NUMERIC, 'C');
}
if ($returnDump = true === $output) {
$output = fopen('php://memory', 'r+');
}
if ($output) {
$prevOutput = $this->setOutput($output);
}
try {
$data->dump($this);
$this->dumpLine(-1);
if ($returnDump) {
$result = stream_get_contents($output, -1, 0);
fclose($output);
return $result;
}
} finally {
if ($output) {
$this->setOutput($prevOutput);
}
if ($locale) {
setlocale(\LC_NUMERIC, $locale);
}
}
return null;
}
/**
* Dumps the current line.
*
* @param int $depth The recursive depth in the dumped structure for the line being dumped,
* or -1 to signal the end-of-dump to the line dumper callable
*/
protected function dumpLine($depth)
{
($this->lineDumper)($this->line, $depth, $this->indentPad);
$this->line = '';
}
/**
* Generic line dumper callback.
*
* @param string $line The line to write
* @param int $depth The recursive depth in the dumped structure
* @param string $indentPad The line indent pad
*/
protected function echoLine($line, $depth, $indentPad)
{
if (-1 !== $depth) {
fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n");
}
}
/**
* Converts a non-UTF-8 string to UTF-8.
*
* @param string|null $s The non-UTF-8 string to convert
*
* @return string|null The string converted to UTF-8
*/
protected function utf8Encode($s)
{
if (null === $s || preg_match('//u', $s)) {
return $s;
}
if (!\function_exists('iconv')) {
throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
}
if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) {
return $c;
}
if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) {
return $c;
}
return iconv('CP850', 'UTF-8', $s);
}
}

Some files were not shown because too many files have changed in this diff Show More