From 7836651f84380abf85204f876264593ce05b6054 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Tue, 27 Jul 2021 09:51:38 +0200 Subject: [PATCH 1/2] Fix debug bar for php 8.0 --- htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php b/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php index 98d6e9e51c1..20cc8d08354 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php @@ -291,7 +291,7 @@ class VarCloner extends AbstractCloner if (!empty($frame['line'])) { ob_start(); debug_zval_dump($obj); - self::$hashMask = substr(ob_get_clean(), 17); + self::$hashMask = strlen(substr(ob_get_clean(), 17)); } } From b0133224d89cc8b001452c24489c79fe1b913d87 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Thu, 29 Jul 2021 10:20:01 +0200 Subject: [PATCH 2/2] Update of var_dumper package 3.0 -> 3.2 --- composer.json | 2 +- composer.lock | 4 +- .../symfony/var-dumper/Caster/AmqpCaster.php | 106 +++++--- .../symfony/var-dumper/Caster/ArgsStub.php | 80 ++++++ .../symfony/var-dumper/Caster/Caster.php | 44 ++- .../symfony/var-dumper/Caster/ClassStub.php | 87 ++++++ .../symfony/var-dumper/Caster/ConstStub.php | 5 + .../symfony/var-dumper/Caster/CutStub.php | 5 +- .../symfony/var-dumper/Caster/DOMCaster.php | 6 +- .../symfony/var-dumper/Caster/EnumStub.php | 5 +- .../var-dumper/Caster/ExceptionCaster.php | 186 ++++++++----- .../symfony/var-dumper/Caster/LinkStub.php | 51 ++++ .../symfony/var-dumper/Caster/PdoCaster.php | 6 + .../symfony/var-dumper/Caster/RedisCaster.php | 77 ++++++ .../var-dumper/Caster/ReflectionCaster.php | 92 ++++--- .../var-dumper/Caster/ResourceCaster.php | 9 +- .../symfony/var-dumper/Caster/SplCaster.php | 10 +- .../symfony/var-dumper/Caster/StubCaster.php | 16 +- .../var-dumper/Caster/XmlReaderCaster.php | 77 ++++++ .../var-dumper/Cloner/AbstractCloner.php | 53 ++-- .../var-dumper/Cloner/ClonerInterface.php | 4 +- .../symfony/var-dumper/Cloner/Cursor.php | 1 + .../symfony/var-dumper/Cloner/Data.php | 98 +++++-- .../var-dumper/Cloner/DumperInterface.php | 32 +-- .../symfony/var-dumper/Cloner/Stub.php | 1 + .../symfony/var-dumper/Cloner/VarCloner.php | 82 ++++-- .../var-dumper/Dumper/AbstractDumper.php | 79 ++++-- .../symfony/var-dumper/Dumper/CliDumper.php | 76 ++++-- .../var-dumper/Dumper/DataDumperInterface.php | 2 +- .../symfony/var-dumper/Dumper/HtmlDumper.php | 245 ++++++++++++----- htdocs/includes/symfony/var-dumper/LICENSE | 2 +- htdocs/includes/symfony/var-dumper/README.md | 23 +- .../var-dumper/Test/VarDumperTestTrait.php | 17 +- .../var-dumper/Tests/Caster/CasterTest.php | 3 +- .../Tests/Caster/ExceptionCasterTest.php | 225 ++++++++++++++++ .../var-dumper/Tests/Caster/PdoCasterTest.php | 41 +-- .../Tests/Caster/RedisCasterTest.php | 85 ++++++ .../Tests/Caster/ReflectionCasterTest.php | 101 +++---- .../var-dumper/Tests/Caster/SplCasterTest.php | 39 ++- .../Tests/Caster/StubCasterTest.php | 171 ++++++++++++ .../Tests/Caster/XmlReaderCasterTest.php | 248 +++++++++++++++++ .../var-dumper/Tests/CliDumperTest.php | 251 +++++++++++------- .../Tests/Fixtures/FooInterface.php | 11 + .../Tests/Fixtures/NotLoadableClass.php | 7 + .../var-dumper/Tests/Fixtures/Twig.php | 26 +- .../var-dumper/Tests/Fixtures/xml_reader.xml | 10 + .../var-dumper/Tests/HtmlDumperTest.php | 52 ++-- .../Tests/Test/VarDumperTestTraitTest.php | 3 +- .../var-dumper/Tests/VarClonerTest.php | 109 +++++++- .../includes/symfony/var-dumper/composer.json | 9 +- .../symfony/var-dumper/phpunit.xml.dist | 4 + 51 files changed, 2393 insertions(+), 585 deletions(-) create mode 100644 htdocs/includes/symfony/var-dumper/Caster/ArgsStub.php create mode 100644 htdocs/includes/symfony/var-dumper/Caster/ClassStub.php create mode 100644 htdocs/includes/symfony/var-dumper/Caster/LinkStub.php create mode 100644 htdocs/includes/symfony/var-dumper/Caster/RedisCaster.php create mode 100644 htdocs/includes/symfony/var-dumper/Caster/XmlReaderCaster.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Caster/ExceptionCasterTest.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Caster/RedisCasterTest.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Caster/StubCasterTest.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Caster/XmlReaderCasterTest.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Fixtures/FooInterface.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Fixtures/NotLoadableClass.php create mode 100644 htdocs/includes/symfony/var-dumper/Tests/Fixtures/xml_reader.xml diff --git a/composer.json b/composer.json index 130fda34945..8d82f530df8 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "nnnick/chartjs" : "^2.9", "stripe/stripe-php" : "6.43.1", "maximebf/debugbar" : "1.15.1", - "symfony/var-dumper" : "3" + "symfony/var-dumper" : "3.2" }, "require-dev" : { "php-parallel-lint/php-parallel-lint" : "^0", diff --git a/composer.lock b/composer.lock index 3e867f8f186..5f761cb63fe 100644 --- a/composer.lock +++ b/composer.lock @@ -591,7 +591,7 @@ }, { "name": "symfony/var-dumper", - "version": "v3.0.0", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", @@ -616,7 +616,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } }, "autoload": { diff --git a/htdocs/includes/symfony/var-dumper/Caster/AmqpCaster.php b/htdocs/includes/symfony/var-dumper/Caster/AmqpCaster.php index 4e9b351c181..655262f4065 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/AmqpCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/AmqpCaster.php @@ -48,7 +48,16 @@ class AmqpCaster { $prefix = Caster::PREFIX_VIRTUAL; - // BC layer in the ampq lib + $a += array( + $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 { @@ -56,13 +65,13 @@ class AmqpCaster } $a += array( - $prefix.'isConnected' => $c->isConnected(), + $prefix.'is_connected' => $c->isConnected(), $prefix.'login' => $c->getLogin(), $prefix.'password' => $c->getPassword(), $prefix.'host' => $c->getHost(), - $prefix.'port' => $c->getPort(), $prefix.'vhost' => $c->getVhost(), - $prefix.'readTimeout' => $timeout, + $prefix.'port' => $c->getPort(), + $prefix.'read_timeout' => $timeout, ); return $a; @@ -73,11 +82,19 @@ class AmqpCaster $prefix = Caster::PREFIX_VIRTUAL; $a += array( - $prefix.'isConnected' => $c->isConnected(), - $prefix.'channelId' => $c->getChannelId(), - $prefix.'prefetchSize' => $c->getPrefetchSize(), - $prefix.'prefetchCount' => $c->getPrefetchCount(), + $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 += array( $prefix.'connection' => $c->getConnection(), + $prefix.'prefetch_size' => $c->getPrefetchSize(), + $prefix.'prefetch_count' => $c->getPrefetchCount(), ); return $a; @@ -88,11 +105,19 @@ class AmqpCaster $prefix = Caster::PREFIX_VIRTUAL; $a += array( - $prefix.'name' => $c->getName(), $prefix.'flags' => self::extractFlags($c->getFlags()), - $prefix.'arguments' => $c->getArguments(), + ); + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPQueue\x00name"])) { + return $a; + } + + $a += array( $prefix.'connection' => $c->getConnection(), $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'arguments' => $c->getArguments(), ); return $a; @@ -103,12 +128,24 @@ class AmqpCaster $prefix = Caster::PREFIX_VIRTUAL; $a += array( - $prefix.'name' => $c->getName(), $prefix.'flags' => self::extractFlags($c->getFlags()), - $prefix.'type' => isset(self::$exchangeTypes[$c->getType()]) ? new ConstStub(self::$exchangeTypes[$c->getType()], $c->getType()) : $c->getType(), - $prefix.'arguments' => $c->getArguments(), - $prefix.'channel' => $c->getChannel(), + ); + + $type = isset(self::$exchangeTypes[$c->getType()]) ? new ConstStub(self::$exchangeTypes[$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 += array( $prefix.'connection' => $c->getConnection(), + $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'type' => $type, + $prefix.'arguments' => $c->getArguments(), ); return $a; @@ -118,28 +155,37 @@ class AmqpCaster { $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 += array($prefix.'body' => $c->getBody()); } $a += array( - $prefix.'routingKey' => $c->getRoutingKey(), - $prefix.'deliveryTag' => $c->getDeliveryTag(), - $prefix.'deliveryMode' => new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()), - $prefix.'exchangeName' => $c->getExchangeName(), - $prefix.'isRedelivery' => $c->isRedelivery(), - $prefix.'contentType' => $c->getContentType(), - $prefix.'contentEncoding' => $c->getContentEncoding(), - $prefix.'type' => $c->getType(), - $prefix.'timestamp' => $c->getTimestamp(), - $prefix.'priority' => $c->getPriority(), - $prefix.'expiration' => $c->getExpiration(), - $prefix.'userId' => $c->getUserId(), - $prefix.'appId' => $c->getAppId(), - $prefix.'messageId' => $c->getMessageId(), - $prefix.'replyTo' => $c->getReplyTo(), - $prefix.'correlationId' => $c->getCorrelationId(), + $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; diff --git a/htdocs/includes/symfony/var-dumper/Caster/ArgsStub.php b/htdocs/includes/symfony/var-dumper/Caster/ArgsStub.php new file mode 100644 index 00000000000..6675caa0478 --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Caster/ArgsStub.php @@ -0,0 +1,80 @@ + + * + * 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 + */ +class ArgsStub extends EnumStub +{ + private static $parameters = array(); + + public function __construct(array $args, $function, $class) + { + list($variadic, $params) = self::getParameters($function, $class); + + $values = array(); + 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 (array('...') === $params) { + $this->dumpKeys = false; + $this->value = $values[0]->value; + } else { + $this->value = array_combine($params, $values); + } + } + + private static function getParameters($function, $class) + { + 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 array(null, null); + } + + $variadic = '...'; + $params = array(); + foreach ($r->getParameters() as $v) { + $k = '$'.$v->name; + if ($v->isPassedByReference()) { + $k = '&'.$k; + } + if (method_exists($v, 'isVariadic') && $v->isVariadic()) { + $variadic .= $k; + } else { + $params[] = $k; + } + } + + return self::$parameters[$k] = array($variadic, $params); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Caster/Caster.php b/htdocs/includes/symfony/var-dumper/Caster/Caster.php index 23e72e87701..7c7fe00ece4 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/Caster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/Caster.php @@ -11,6 +11,8 @@ namespace Symfony\Component\VarDumper\Caster; +use Symfony\Component\VarDumper\Cloner\Stub; + /** * Helper for filtering out properties in casters. * @@ -36,29 +38,39 @@ class Caster /** * Casts objects to arrays and adds the dynamic property prefix. * - * @param object $obj The object to cast. - * @param \ReflectionClass $reflector The class reflector to use for inspecting the object definition. + * @param object $obj The object to cast + * @param \ReflectionClass $reflector The class reflector to use for inspecting the object definition * - * @return array The array-cast of the object, with prefixed dynamic properties. + * @return array The array-cast of the object, with prefixed dynamic properties */ public static function castObject($obj, \ReflectionClass $reflector) { if ($reflector->hasMethod('__debugInfo')) { $a = $obj->__debugInfo(); + } elseif ($obj instanceof \Closure) { + $a = array(); } else { $a = (array) $obj; } + if ($obj instanceof \__PHP_Incomplete_Class) { + return $a; + } if ($a) { + $combine = false; $p = array_keys($a); foreach ($p as $i => $k) { - if (!isset($k[0]) || ("\0" !== $k[0] && !$reflector->hasProperty($k))) { + if (isset($k[0]) ? "\0" !== $k[0] && !$reflector->hasProperty($k) : \PHP_VERSION_ID >= 70200) { + $combine = true; $p[$i] = self::PREFIX_DYNAMIC.$k; } elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) { + $combine = true; $p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0"); } } - $a = array_combine($p, $a); + if ($combine) { + $a = array_combine($p, $a); + } } return $a; @@ -70,14 +82,17 @@ class Caster * 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 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, $filter, array $listedProperties = array()) + public static function filter(array $a, $filter, array $listedProperties = array(), &$count = 0) { + $count = 0; + foreach ($a as $k => $v) { $type = self::EXCLUDE_STRICT & $filter; @@ -108,9 +123,20 @@ class Caster 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, $isNested) + { + if (isset($a['__PHP_Incomplete_Class_Name'])) { + $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; + unset($a['__PHP_Incomplete_Class_Name']); + } + + return $a; + } } diff --git a/htdocs/includes/symfony/var-dumper/Caster/ClassStub.php b/htdocs/includes/symfony/var-dumper/Caster/ClassStub.php new file mode 100644 index 00000000000..59efecda9eb --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Caster/ClassStub.php @@ -0,0 +1,87 @@ + + * + * 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 PHP class identifier. + * + * @author Nicolas Grekas + */ +class ClassStub extends ConstStub +{ + /** + * Constructor. + * + * @param string A PHP identifier, e.g. a class, method, interface, etc. name + * @param callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier + */ + public function __construct($identifier, $callable = null) + { + $this->value = $identifier; + + if (0 < $i = strrpos($identifier, '\\')) { + $this->attr['ellipsis'] = strlen($identifier) - $i; + } + + try { + if (null !== $callable) { + if ($callable instanceof \Closure) { + $r = new \ReflectionFunction($callable); + } elseif (is_object($callable)) { + $r = array($callable, '__invoke'); + } elseif (is_array($callable)) { + $r = $callable; + } elseif (false !== $i = strpos($callable, '::')) { + $r = array(substr($callable, 0, $i), substr($callable, 2 + $i)); + } else { + $r = new \ReflectionFunction($callable); + } + } elseif (false !== $i = strpos($identifier, '::')) { + $r = array(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]); + } + } + } catch (\ReflectionException $e) { + return; + } + + 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); + } elseif (is_string($callable[0])) { + $callable[0] = new static($callable[0]); + } else { + $callable[1] = new static($callable[1], $callable); + } + + return $callable; + } +} diff --git a/htdocs/includes/symfony/var-dumper/Caster/ConstStub.php b/htdocs/includes/symfony/var-dumper/Caster/ConstStub.php index f20e03cdf0d..26c0010b66a 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/ConstStub.php +++ b/htdocs/includes/symfony/var-dumper/Caster/ConstStub.php @@ -25,4 +25,9 @@ class ConstStub extends Stub $this->class = $name; $this->value = $value; } + + public function __toString() + { + return (string) $this->value; + } } diff --git a/htdocs/includes/symfony/var-dumper/Caster/CutStub.php b/htdocs/includes/symfony/var-dumper/Caster/CutStub.php index 8781f5cf3c6..61140eb361d 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/CutStub.php +++ b/htdocs/includes/symfony/var-dumper/Caster/CutStub.php @@ -39,9 +39,12 @@ class CutStub extends Stub case 'resource': case 'unknown type': + case 'resource (closed)': $this->type = self::TYPE_RESOURCE; $this->handle = (int) $value; - $this->class = @get_resource_type($value); + if ('Unknown' === $this->class = @get_resource_type($value)) { + $this->class = 'Closed'; + } $this->cut = -1; break; diff --git a/htdocs/includes/symfony/var-dumper/Caster/DOMCaster.php b/htdocs/includes/symfony/var-dumper/Caster/DOMCaster.php index e04cf9534b3..3a99865370c 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/DOMCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/DOMCaster.php @@ -107,7 +107,7 @@ class DOMCaster 'namespaceURI' => $dom->namespaceURI, 'prefix' => $dom->prefix, 'localName' => $dom->localName, - 'baseURI' => $dom->baseURI, + 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent), ); @@ -144,7 +144,7 @@ class DOMCaster 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, - 'documentURI' => $dom->documentURI, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, @@ -237,7 +237,7 @@ class DOMCaster 'columnNumber' => $dom->columnNumber, 'offset' => $dom->offset, 'relatedNode' => $dom->relatedNode, - 'uri' => $dom->uri, + 'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri, ); return $a; diff --git a/htdocs/includes/symfony/var-dumper/Caster/EnumStub.php b/htdocs/includes/symfony/var-dumper/Caster/EnumStub.php index 67bb2e16390..3cee23eac20 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/EnumStub.php +++ b/htdocs/includes/symfony/var-dumper/Caster/EnumStub.php @@ -20,8 +20,11 @@ use Symfony\Component\VarDumper\Cloner\Stub; */ class EnumStub extends Stub { - public function __construct(array $values) + public $dumpKeys = true; + + public function __construct(array $values, $dumpKeys = true) { $this->value = $values; + $this->dumpKeys = $dumpKeys; } } diff --git a/htdocs/includes/symfony/var-dumper/Caster/ExceptionCaster.php b/htdocs/includes/symfony/var-dumper/Caster/ExceptionCaster.php index a5a8773e859..8c84137e646 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/ExceptionCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/ExceptionCaster.php @@ -41,6 +41,8 @@ class ExceptionCaster E_STRICT => 'E_STRICT', ); + private static $framesCache = array(); + public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0) { return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); @@ -65,13 +67,9 @@ class ExceptionCaster $prefix = Caster::PREFIX_PROTECTED; $xPrefix = "\0Exception\0"; - if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'])) { + if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace']) && $a[$xPrefix.'previous'] instanceof \Exception) { $b = (array) $a[$xPrefix.'previous']; - array_unshift($b[$xPrefix.'trace'], array( - 'function' => 'new '.get_class($a[$xPrefix.'previous']), - 'file' => $b[$prefix.'file'], - 'line' => $b[$prefix.'line'], - )); + self::traceUnshift($b[$xPrefix.'trace'], get_class($a[$xPrefix.'previous']), $b[$prefix.'file'], $b[$prefix.'line']); $a[$xPrefix.'trace'] = new TraceStub($b[$xPrefix.'trace'], false, 0, -1 - count($a[$xPrefix.'trace']->value)); } @@ -88,6 +86,7 @@ class ExceptionCaster $stub->class = ''; $stub->handle = 0; $frames = $trace->value; + $prefix = Caster::PREFIX_VIRTUAL; $a = array(); $j = count($frames); @@ -97,34 +96,38 @@ class ExceptionCaster if (!isset($trace->value[$i])) { return array(); } - $lastCall = isset($frames[$i]['function']) ? ' ==> '.(isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : ''; + $lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : ''; + $frames[] = array('function' => ''); for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) { - $call = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[$i]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '???'; + $f = $frames[$i]; + $call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'].'()' : '???'; - $a[Caster::PREFIX_VIRTUAL.$j.'. '.$call.$lastCall] = new FrameStub( + $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; + $frame = new FrameStub( array( - 'object' => isset($frames[$i]['object']) ? $frames[$i]['object'] : null, - 'class' => isset($frames[$i]['class']) ? $frames[$i]['class'] : null, - 'type' => isset($frames[$i]['type']) ? $frames[$i]['type'] : null, - 'function' => isset($frames[$i]['function']) ? $frames[$i]['function'] : null, + 'object' => isset($f['object']) ? $f['object'] : null, + 'class' => isset($f['class']) ? $f['class'] : null, + 'type' => isset($f['type']) ? $f['type'] : null, + 'function' => isset($f['function']) ? $f['function'] : null, ) + $frames[$i - 1], - $trace->keepArgs, + false, true ); + $f = self::castFrameStub($frame, array(), $frame, true); + if (isset($f[$prefix.'src'])) { + foreach ($f[$prefix.'src']->value as $label => $frame) { + $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'], isset($f['function']) ? $f['function'] : null, isset($f['class']) ? $f['class'] : null); + } + } + $a[$label] = $frame; - $lastCall = ' ==> '.$call; + $lastCall = $call; } - $a[Caster::PREFIX_VIRTUAL.$j.'. {main}'.$lastCall] = new FrameStub( - array( - 'object' => null, - 'class' => null, - 'type' => null, - 'function' => '{main}', - ) + $frames[$i - 1], - $trace->keepArgs, - true - ); if (null !== $trace->sliceLength) { $a = array_slice($a, 0, $trace->sliceLength, true); } @@ -141,30 +144,52 @@ class ExceptionCaster $prefix = Caster::PREFIX_VIRTUAL; if (isset($f['file'], $f['line'])) { - 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]; - } - if (file_exists($f['file']) && 0 <= self::$srcContext) { - $src[$f['file'].':'.$f['line']] = self::extractSource(explode("\n", file_get_contents($f['file'])), $f['line'], self::$srcContext); + $cacheKey = $f; + unset($cacheKey['object'], $cacheKey['args']); + $cacheKey[] = self::$srcContext; + $cacheKey = implode('-', $cacheKey); - if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) { - $template = isset($f['object']) ? $f['object'] : new $f['class'](new \Twig_Environment(new \Twig_Loader_Filesystem())); + 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]; + } + $caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null; + $src = $f['line']; + $srcKey = $f['file']; + $ellipsis = explode(DIRECTORY_SEPARATOR, $srcKey); + $ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0; - try { - $templateName = $template->getTemplateName(); - $templateSrc = explode("\n", method_exists($template, 'getSource') ? $template->getSource() : $template->getEnvironment()->getLoader()->getSource($templateName)); + 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 = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class'])); + + $ellipsis = 0; + $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); $templateInfo = $template->getDebugInfo(); if (isset($templateInfo[$f['line']])) { - $src[$templateName.':'.$templateInfo[$f['line']]] = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext); + if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) { + $templatePath = null; + } + if ($templateSrc) { + $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath); + $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; + } + } + } + if ($srcKey == $f['file']) { + $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']); + $srcKey .= ':'.$f['line']; + if ($ellipsis) { + $ellipsis += 1 + strlen($f['line']); } - } catch (\Twig_Error_Loader $e) { } } - } else { - $src[$f['file']] = $f['line']; + $srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : ''; + self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src)); } - $a[$prefix.'src'] = new EnumStub($src); } unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']); @@ -176,8 +201,8 @@ class ExceptionCaster unset($a[$k]); } } - if ($frame->keepArgs && isset($f['args'])) { - $a[$prefix.'args'] = $f['args']; + if ($frame->keepArgs && !empty($f['args'])) { + $a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']); } return $a; @@ -193,46 +218,81 @@ class ExceptionCaster } if (!($filter & Caster::EXCLUDE_VERBOSE)) { - array_unshift($trace, array( - 'function' => $xClass ? 'new '.$xClass : null, - 'file' => $a[Caster::PREFIX_PROTECTED.'file'], - 'line' => $a[Caster::PREFIX_PROTECTED.'line'], - )); - $a[$xPrefix.'trace'] = new TraceStub($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[$xPrefix.'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.'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 extractSource(array $srcArray, $line, $srcContext) + private static function traceUnshift(&$trace, $class, $file, $line) { + if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) { + return; + } + array_unshift($trace, array( + 'function' => $class ? 'new '.$class : null, + 'file' => $file, + 'line' => $line, + )); + } + + private static function extractSource($srcLines, $line, $srcContext, $title, $lang, $file = null) + { + $srcLines = explode("\n", $srcLines); $src = array(); for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) { - $src[] = (isset($srcArray[$i]) ? $srcArray[$i] : '')."\n"; + $src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n"; } + $srcLines = array(); $ltrim = 0; - while (' ' === $src[0][$ltrim] || "\t" === $src[0][$ltrim]) { - $i = $srcContext << 1; - while ($i > 0 && $src[0][$ltrim] === $src[$i][$ltrim]) { - --$i; - } - if ($i) { - break; + 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; - } - if ($ltrim) { - foreach ($src as $i => $line) { - $src[$i] = substr($line, $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, $title); + if (null !== $file) { + $c->attr['file'] = $file; + $c->attr['line'] = $line; + } + } + $c->attr['lang'] = $lang; + $srcLines[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c; } - return implode('', $src); + return new EnumStub($srcLines); } } diff --git a/htdocs/includes/symfony/var-dumper/Caster/LinkStub.php b/htdocs/includes/symfony/var-dumper/Caster/LinkStub.php new file mode 100644 index 00000000000..ea39c5b08ee --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Caster/LinkStub.php @@ -0,0 +1,51 @@ + + * + * 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 + */ +class LinkStub extends ConstStub +{ + public function __construct($label, $line = 0, $href = null) + { + $this->value = $label; + + if (null === $href) { + $href = $label; + } + if (is_string($href)) { + if (0 === strpos($href, 'file://')) { + if ($href === $label) { + $label = substr($label, 7); + } + $href = substr($href, 7); + } elseif (false !== strpos($href, '://')) { + $this->attr['href'] = $href; + + return; + } + if (file_exists($href)) { + if ($line) { + $this->attr['line'] = $line; + } + $this->attr['file'] = realpath($href) ?: $href; + + if ($this->attr['file'] === $label && 3 < count($ellipsis = explode(DIRECTORY_SEPARATOR, $href))) { + $this->attr['ellipsis'] = 2 + strlen(implode(array_slice($ellipsis, -2))); + } + } + } + } +} diff --git a/htdocs/includes/symfony/var-dumper/Caster/PdoCaster.php b/htdocs/includes/symfony/var-dumper/Caster/PdoCaster.php index e60b9275fd8..b8667824773 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/PdoCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/PdoCaster.php @@ -77,6 +77,12 @@ class PdoCaster } 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 += array( diff --git a/htdocs/includes/symfony/var-dumper/Caster/RedisCaster.php b/htdocs/includes/symfony/var-dumper/Caster/RedisCaster.php new file mode 100644 index 00000000000..07a3a1b0911 --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Caster/RedisCaster.php @@ -0,0 +1,77 @@ + + * + * 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 + */ +class RedisCaster +{ + private static $serializer = array( + \Redis::SERIALIZER_NONE => 'NONE', + \Redis::SERIALIZER_PHP => 'PHP', + 2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY + ); + + public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if (defined('HHVM_VERSION_ID')) { + if (isset($a[Caster::PREFIX_PROTECTED.'serializer'])) { + $ser = $a[Caster::PREFIX_PROTECTED.'serializer']; + $a[Caster::PREFIX_PROTECTED.'serializer'] = isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser; + } + + return $a; + } + + if (!$connected = $c->isConnected()) { + return $a + array( + $prefix.'isConnected' => $connected, + ); + } + + $ser = $c->getOption(\Redis::OPT_SERIALIZER); + $retry = defined('Redis::OPT_SCAN') ? $c->getOption(\Redis::OPT_SCAN) : 0; + + return $a + array( + $prefix.'isConnected' => $connected, + $prefix.'host' => $c->getHost(), + $prefix.'port' => $c->getPort(), + $prefix.'auth' => $c->getAuth(), + $prefix.'dbNum' => $c->getDbNum(), + $prefix.'timeout' => $c->getTimeout(), + $prefix.'persistentId' => $c->getPersistentID(), + $prefix.'options' => new EnumStub(array( + 'READ_TIMEOUT' => $c->getOption(\Redis::OPT_READ_TIMEOUT), + 'SERIALIZER' => isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser, + 'PREFIX' => $c->getOption(\Redis::OPT_PREFIX), + 'SCAN' => new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry), + )), + ); + } + + public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + return $a + array( + $prefix.'hosts' => $c->_hosts(), + $prefix.'function' => ClassStub::wrapCallable($c->_function()), + ); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Caster/ReflectionCaster.php b/htdocs/includes/symfony/var-dumper/Caster/ReflectionCaster.php index 936e11982ee..dcb5a2f29ca 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/ReflectionCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/ReflectionCaster.php @@ -53,19 +53,32 @@ class ReflectionCaster } if ($f = $c->getFileName()) { - $a[$prefix.'file'] = $f; + $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); } $prefix = Caster::PREFIX_DYNAMIC; - unset($a['name'], $a[$prefix.'0'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']); + unset($a['name'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']); return $a; } public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested) { - return class_exists('ReflectionGenerator', false) ? self::castReflectionGenerator(new \ReflectionGenerator($c), $a, $stub, $isNested) : $a; + if (!class_exists('ReflectionGenerator', false)) { + return $a; + } + + // 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) @@ -73,7 +86,7 @@ class ReflectionCaster $prefix = Caster::PREFIX_VIRTUAL; $a += array( - $prefix.'type' => $c->__toString(), + $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(), $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ); @@ -88,31 +101,33 @@ class ReflectionCaster if ($c->getThis()) { $a[$prefix.'this'] = new CutStub($c->getThis()); } - $x = $c->getFunction(); + $function = $c->getFunction(); $frame = array( - 'class' => isset($x->class) ? $x->class : null, - 'type' => isset($x->class) ? ($x->isStatic() ? '::' : '->') : null, - 'function' => $x->name, + 'class' => isset($function->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)) { - $x = new \ReflectionGenerator($c->getExecutingGenerator()); + $function = new \ReflectionGenerator($c->getExecutingGenerator()); array_unshift($trace, array( 'function' => 'yield', - 'file' => $x->getExecutingFile(), - 'line' => $x->getExecutingLine() - 1, + 'file' => $function->getExecutingFile(), + 'line' => $function->getExecutingLine() - 1, )); $trace[] = $frame; $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); } else { - $x = new FrameStub($frame, false, true); - $x = ExceptionCaster::castFrameStub($x, array(), $x, true); + $function = new FrameStub($frame, false, true); + $function = ExceptionCaster::castFrameStub($function, array(), $function, true); $a[$prefix.'executing'] = new EnumStub(array( - $frame['class'].$frame['type'].$frame['function'].'()' => $x[$prefix.'src'], + $frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'], )); } + $a[Caster::PREFIX_VIRTUAL.'closed'] = false; + return $a; } @@ -157,7 +172,12 @@ class ReflectionCaster )); if (isset($a[$prefix.'returnType'])) { - $a[$prefix.'returnType'] = (string) $a[$prefix.'returnType']; + $v = $a[$prefix.'returnType']; + $v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, array(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']); @@ -165,12 +185,12 @@ class ReflectionCaster foreach ($c->getParameters() as $v) { $k = '$'.$v->name; - if ($v->isPassedByReference()) { - $k = '&'.$k; - } if (method_exists($v, 'isVariadic') && $v->isVariadic()) { $k = '...'.$k; } + if ($v->isPassedByReference()) { + $k = '&'.$k; + } $a[$prefix.'parameters'][$k] = $v; } if (isset($a[$prefix.'parameters'])) { @@ -213,24 +233,22 @@ class ReflectionCaster 'position' => 'getPosition', 'isVariadic' => 'isVariadic', 'byReference' => 'isPassedByReference', + 'allowsNull' => 'allowsNull', )); - try { - if (method_exists($c, 'hasType')) { - if ($c->hasType()) { - $a[$prefix.'typeHint'] = $c->getType()->__toString(); - } - } elseif ($c->isArray()) { - $a[$prefix.'typeHint'] = 'array'; - } elseif (method_exists($c, 'isCallable') && $c->isCallable()) { - $a[$prefix.'typeHint'] = 'callable'; - } elseif ($v = $c->getClass()) { - $a[$prefix.'typeHint'] = $v->name; - } - } catch (\ReflectionException $e) { - if (preg_match('/^Class ([^ ]++) does not exist$/', $e->getMessage(), $m)) { - $a[$prefix.'typeHint'] = $m[1]; + if (method_exists($c, 'getType')) { + if ($v = $c->getType()) { + $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); } + } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) { + $a[$prefix.'typeHint'] = $v[1]; + } + + if (isset($a[$prefix.'typeHint'])) { + $v = $a[$prefix.'typeHint']; + $a[$prefix.'typeHint'] = new ClassStub($v, array(class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '')); + } else { + unset($a[$prefix.'allowsNull']); } try { @@ -238,9 +256,13 @@ class ReflectionCaster if (method_exists($c, 'isDefaultValueConstant') && $c->isDefaultValueConstant()) { $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); } + if (null === $v) { + unset($a[$prefix.'allowsNull']); + } } catch (\ReflectionException $e) { - if (isset($a[$prefix.'typeHint']) && $c->allowsNull()) { + if (isset($a[$prefix.'typeHint']) && $c->allowsNull() && !class_exists('ReflectionNamedType', false)) { $a[$prefix.'default'] = null; + unset($a[$prefix.'allowsNull']); } } @@ -288,7 +310,7 @@ class ReflectionCaster $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : array(); if (method_exists($c, 'getFileName') && $m = $c->getFileName()) { - $x['file'] = $m; + $x['file'] = new LinkStub($m, $c->getStartLine()); $x['line'] = $c->getStartLine().' to '.$c->getEndLine(); } diff --git a/htdocs/includes/symfony/var-dumper/Caster/ResourceCaster.php b/htdocs/includes/symfony/var-dumper/Caster/ResourceCaster.php index 903641f69c6..3cdb27c3087 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/ResourceCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/ResourceCaster.php @@ -40,12 +40,17 @@ class ResourceCaster public static function castStream($stream, array $a, Stub $stub, $isNested) { - return stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); + $a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); + if (isset($a['uri'])) { + $a['uri'] = new LinkStub($a['uri']); + } + + return $a; } public static function castStreamContext($stream, array $a, Stub $stub, $isNested) { - return stream_context_get_params($stream); + return @stream_context_get_params($stream) ?: $a; } public static function castGd($gd, array $a, Stub $stub, $isNested) diff --git a/htdocs/includes/symfony/var-dumper/Caster/SplCaster.php b/htdocs/includes/symfony/var-dumper/Caster/SplCaster.php index 97f21463821..4f23efa52d2 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/SplCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/SplCaster.php @@ -36,7 +36,7 @@ class SplCaster $b = array( $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), - $prefix.'iteratorClass' => $c->getIteratorClass(), + $prefix.'iteratorClass' => new ClassStub($c->getIteratorClass()), $prefix.'storage' => $c->getArrayCopy(), ); @@ -71,7 +71,7 @@ class SplCaster $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE); $a += array( - $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_KEEP) ? 'IT_MODE_KEEP' : 'IT_MODE_DELETE'), $mode), + $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); @@ -115,6 +115,10 @@ class SplCaster } } + if (isset($a[$prefix.'realPath'])) { + $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']); } @@ -180,7 +184,7 @@ class SplCaster $storage = array(); unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 - foreach ($c as $obj) { + foreach (clone $c as $obj) { $storage[spl_object_hash($obj)] = array( 'object' => $obj, 'info' => $c->getInfo(), diff --git a/htdocs/includes/symfony/var-dumper/Caster/StubCaster.php b/htdocs/includes/symfony/var-dumper/Caster/StubCaster.php index ebad5ba9844..2ec096c5a8c 100644 --- a/htdocs/includes/symfony/var-dumper/Caster/StubCaster.php +++ b/htdocs/includes/symfony/var-dumper/Caster/StubCaster.php @@ -28,9 +28,17 @@ class StubCaster $stub->value = $c->value; $stub->handle = $c->handle; $stub->cut = $c->cut; + $stub->attr = $c->attr; - return array(); + 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 = array(); } + + return $a; } public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested) @@ -52,15 +60,17 @@ class StubCaster public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested) { if ($isNested) { - $stub->class = ''; + $stub->class = $c->dumpKeys ? '' : null; $stub->handle = 0; $stub->value = null; + $stub->cut = $c->cut; + $stub->attr = $c->attr; $a = array(); if ($c->value) { foreach (array_keys($c->value) as $k) { - $keys[] = Caster::PREFIX_VIRTUAL.$k; + $keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k; } // Preserve references with array_combine() $a = array_combine($keys, $c->value); diff --git a/htdocs/includes/symfony/var-dumper/Caster/XmlReaderCaster.php b/htdocs/includes/symfony/var-dumper/Caster/XmlReaderCaster.php new file mode 100644 index 00000000000..c371009a17a --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -0,0 +1,77 @@ + + * + * 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é + */ +class XmlReaderCaster +{ + private static $nodeTypes = array( + \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) + { + $props = Caster::PREFIX_VIRTUAL.'parserProperties'; + $info = array( + 'localName' => $reader->localName, + 'prefix' => $reader->prefix, + 'nodeType' => new ConstStub(self::$nodeTypes[$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 => array( + 'LOADDTD' => $reader->getParserProperty(\XmlReader::LOADDTD), + 'DEFAULTATTRS' => $reader->getParserProperty(\XmlReader::DEFAULTATTRS), + 'VALIDATE' => $reader->getParserProperty(\XmlReader::VALIDATE), + 'SUBST_ENTITIES' => $reader->getParserProperty(\XmlReader::SUBST_ENTITIES), + ), + ); + + if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, array(), $count)) { + $info[$props] = new EnumStub($info[$props]); + $info[$props]->cut = $count; + } + + $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, array(), $count); + // +2 because hasValue and hasAttributes are always filtered + $stub->cut += $count + 2; + + return $a + $info; + } +} diff --git a/htdocs/includes/symfony/var-dumper/Cloner/AbstractCloner.php b/htdocs/includes/symfony/var-dumper/Cloner/AbstractCloner.php index 2807ceb935b..437230e24ea 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/AbstractCloner.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/AbstractCloner.php @@ -22,6 +22,8 @@ use Symfony\Component\VarDumper\Exception\ThrowingCasterException; abstract class AbstractCloner implements ClonerInterface { public static $defaultCasters = array( + '__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', @@ -67,6 +69,8 @@ abstract class AbstractCloner implements ClonerInterface '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', @@ -100,6 +104,9 @@ abstract class AbstractCloner implements ClonerInterface 'MongoCursorInterface' => 'Symfony\Component\VarDumper\Caster\MongoCaster::castCursor', + 'Redis' => 'Symfony\Component\VarDumper\Caster\RedisCaster::castRedis', + 'RedisArray' => 'Symfony\Component\VarDumper\Caster\RedisCaster::castRedisArray', + ':curl' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castCurl', ':dba' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba', ':dba persistent' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba', @@ -111,6 +118,7 @@ abstract class AbstractCloner implements ClonerInterface ':pgsql result' => 'Symfony\Component\VarDumper\Caster\PgSqlCaster::castResult', ':process' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castProcess', ':stream' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStream', + ':persistent stream' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStream', ':stream-context' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStreamContext', ':xml' => 'Symfony\Component\VarDumper\Caster\XmlResourceCaster::castXml', ); @@ -125,7 +133,7 @@ abstract class AbstractCloner implements ClonerInterface private $filter = 0; /** - * @param callable[]|null $casters A map of casters. + * @param callable[]|null $casters A map of casters * * @see addCasters */ @@ -146,7 +154,7 @@ abstract class AbstractCloner implements ClonerInterface * Resource types are to be prefixed with a `:`, * see e.g. static::$defaultCasters. * - * @param callable[] $casters A map of casters. + * @param callable[] $casters A map of casters */ public function addCasters(array $casters) { @@ -178,10 +186,10 @@ abstract class AbstractCloner implements ClonerInterface /** * Clones a PHP variable. * - * @param mixed $var Any PHP variable. - * @param int $filter A bit field of Caster::EXCLUDE_* constants. + * @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. + * @return Data The cloned variable represented by a Data object */ public function cloneVar($var, $filter = 0) { @@ -216,19 +224,19 @@ abstract class AbstractCloner implements ClonerInterface /** * Effectively clones the PHP variable. * - * @param mixed $var Any PHP variable. + * @param mixed $var Any PHP variable * - * @return array The cloned variable represented in an array. + * @return array The cloned variable represented in an array */ abstract protected function doClone($var); /** * Casts an object to an array representation. * - * @param Stub $stub The Stub for the casted object. - * @param bool $isNested True if the object is nested in the dumped structure. + * @param Stub $stub The Stub for the casted object + * @param bool $isNested True if the object is nested in the dumped structure * - * @return array The object casted as array. + * @return array The object casted as array */ protected function castObject(Stub $stub, $isNested) { @@ -245,14 +253,15 @@ abstract class AbstractCloner implements ClonerInterface new \ReflectionClass($class), array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')), ); + $classInfo[1] = array_map('strtolower', $classInfo[1]); $this->classInfo[$class] = $classInfo; } - $a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[0], null, $isNested); + $a = Caster::castObject($obj, $classInfo[0]); foreach ($classInfo[1] as $p) { - if (!empty($this->casters[$p = strtolower($p)])) { + if (!empty($this->casters[$p])) { foreach ($this->casters[$p] as $p) { $a = $this->callCaster($p, $obj, $a, $stub, $isNested); } @@ -265,10 +274,10 @@ abstract class AbstractCloner implements ClonerInterface /** * Casts a resource to an array representation. * - * @param Stub $stub The Stub for the casted resource. - * @param bool $isNested True if the object is nested in the dumped structure. + * @param Stub $stub The Stub for the casted resource + * @param bool $isNested True if the object is nested in the dumped structure * - * @return array The resource casted as array. + * @return array The resource casted as array */ protected function castResource(Stub $stub, $isNested) { @@ -288,13 +297,13 @@ abstract class AbstractCloner implements ClonerInterface /** * Calls a custom caster. * - * @param callable $callback The caster. - * @param object|resource $obj The object/resource being casted. - * @param array $a The result of the previous cast for chained casters. - * @param Stub $stub The Stub for the casted object/resource. - * @param bool $isNested True if $obj is nested in the dumped structure. + * @param callable $callback The caster + * @param object|resource $obj The object/resource being casted + * @param array $a The result of the previous cast for chained casters + * @param Stub $stub The Stub for the casted object/resource + * @param bool $isNested True if $obj is nested in the dumped structure * - * @return array The casted object/resource. + * @return array The casted object/resource */ private function callCaster($callback, $obj, $a, $stub, $isNested) { @@ -305,7 +314,7 @@ abstract class AbstractCloner implements ClonerInterface $a = $cast; } } catch (\Exception $e) { - $a[(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠'] = new ThrowingCasterException($e); + $a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a; } return $a; diff --git a/htdocs/includes/symfony/var-dumper/Cloner/ClonerInterface.php b/htdocs/includes/symfony/var-dumper/Cloner/ClonerInterface.php index c1df5933dbf..7ed287a2ddf 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/ClonerInterface.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/ClonerInterface.php @@ -19,9 +19,9 @@ interface ClonerInterface /** * Clones a PHP variable. * - * @param mixed $var Any PHP variable. + * @param mixed $var Any PHP variable * - * @return Data The cloned variable represented by a Data object. + * @return Data The cloned variable represented by a Data object */ public function cloneVar($var); } diff --git a/htdocs/includes/symfony/var-dumper/Cloner/Cursor.php b/htdocs/includes/symfony/var-dumper/Cloner/Cursor.php index 162f3293cf2..9db55992e4a 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/Cursor.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/Cursor.php @@ -38,4 +38,5 @@ class Cursor public $hashLength = 0; public $hashCut = 0; public $stop = false; + public $attr = array(); } diff --git a/htdocs/includes/symfony/var-dumper/Cloner/Data.php b/htdocs/includes/symfony/var-dumper/Cloner/Data.php index 43a7b67971e..22fd2fd1a4a 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/Data.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/Data.php @@ -11,18 +11,22 @@ namespace Symfony\Component\VarDumper\Cloner; +use Symfony\Component\VarDumper\Caster\Caster; + /** * @author Nicolas Grekas */ class Data { private $data; + private $position = 0; + private $key = 0; private $maxDepth = 20; private $maxItemsPerDepth = -1; private $useRefHandles = -1; /** - * @param array $data A array as returned by ClonerInterface::cloneVar(). + * @param array $data A array as returned by ClonerInterface::cloneVar() */ public function __construct(array $data) { @@ -30,7 +34,7 @@ class Data } /** - * @return array The raw data structure. + * @return array The raw data structure */ public function getRawData() { @@ -40,9 +44,9 @@ class Data /** * Returns a depth limited clone of $this. * - * @param int $maxDepth The max dumped depth level. + * @param int $maxDepth The max dumped depth level * - * @return self A clone of $this. + * @return self A clone of $this */ public function withMaxDepth($maxDepth) { @@ -53,11 +57,11 @@ class Data } /** - * Limits the numbers of elements per depth level. + * Limits the number of elements per depth level. * - * @param int $maxItemsPerDepth The max number of items dumped per depth level. + * @param int $maxItemsPerDepth The max number of items dumped per depth level * - * @return self A clone of $this. + * @return self A clone of $this */ public function withMaxItemsPerDepth($maxItemsPerDepth) { @@ -70,9 +74,9 @@ class Data /** * Enables/disables objects' identifiers tracking. * - * @param bool $useRefHandles False to hide global ref. handles. + * @param bool $useRefHandles False to hide global ref. handles * - * @return self A clone of $this. + * @return self A clone of $this */ public function withRefHandles($useRefHandles) { @@ -82,22 +86,66 @@ class Data return $data; } + /** + * Seeks to a specific key in nested data structures. + * + * @param string|int $key The key to seek to + * + * @return self|null A clone of $this of null if the key is not set + */ + public function seek($key) + { + $item = $this->data[$this->position][$this->key]; + + if (!$item instanceof Stub || !$item->position) { + return; + } + $keys = array($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"; + case Stub::TYPE_ARRAY: + case Stub::TYPE_RESOURCE: + break; + default: + return; + } + + $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 = array(0); - $this->dumpItem($dumper, new Cursor(), $refs, $this->data[0][0]); + $this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]); } /** * Depth-first dumping of items. * - * @param DumperInterface $dumper The dumper being used for dumping. - * @param Cursor $cursor A cursor used for tracking dumper state position. - * @param array &$refs A map of all references discovered while dumping. - * @param mixed $item A Stub object or the original value being dumped. + * @param DumperInterface $dumper The dumper being used for dumping + * @param Cursor $cursor A cursor used for tracking dumper state position + * @param array &$refs A map of all references discovered while dumping + * @param mixed $item A Stub object or the original value being dumped */ private function dumpItem($dumper, $cursor, &$refs, $item) { @@ -107,6 +155,7 @@ class Data $firstSeen = true; if (!$item instanceof Stub) { + $cursor->attr = array(); $type = gettype($item); } elseif (Stub::TYPE_REF === $item->type) { if ($item->handle) { @@ -119,6 +168,7 @@ class Data $cursor->hardRefHandle = $this->useRefHandles & $item->handle; $cursor->hardRefCount = $item->refCount; } + $cursor->attr = $item->attr; $type = $item->class ?: gettype($item->value); $item = $item->value; } @@ -133,6 +183,7 @@ class Data } $cursor->softRefHandle = $this->useRefHandles & $item->handle; $cursor->softRefCount = $item->refCount; + $cursor->attr = $item->attr; $cut = $item->cut; if ($item->position && $firstSeen) { @@ -162,7 +213,7 @@ class Data $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth; $dumper->enterHash($cursor, $item->type, $item->class, $withChildren); if ($withChildren) { - $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type); + $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class); } elseif ($children && 0 <= $cut) { $cut += count($children); } @@ -186,15 +237,16 @@ class Data * Dumps children of hash structures. * * @param DumperInterface $dumper - * @param Cursor $parentCursor The cursor of the parent hash. - * @param array &$refs A map of all references discovered while dumping. - * @param array $children The children to dump. - * @param int $hashCut The number of items removed from the original hash. - * @param string $hashType A Cursor::HASH_* const. + * @param Cursor $parentCursor The cursor of the parent hash + * @param array &$refs A map of all references discovered while dumping + * @param array $children The children to dump + * @param int $hashCut The number of items removed from the original hash + * @param string $hashType A Cursor::HASH_* const + * @param bool $dumpKeys Whether keys should be dumped or not * - * @return int The final number of removed items. + * @return int The final number of removed items */ - private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType) + private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType, $dumpKeys) { $cursor = clone $parentCursor; ++$cursor->depth; @@ -204,7 +256,7 @@ class Data $cursor->hashCut = $hashCut; foreach ($children as $key => $child) { $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key); - $cursor->hashKey = $key; + $cursor->hashKey = $dumpKeys ? $key : null; $this->dumpItem($dumper, $cursor, $refs, $child); if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) { $parentCursor->stop = true; diff --git a/htdocs/includes/symfony/var-dumper/Cloner/DumperInterface.php b/htdocs/includes/symfony/var-dumper/Cloner/DumperInterface.php index eba23d42297..cb7981694f9 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/DumperInterface.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/DumperInterface.php @@ -21,40 +21,40 @@ interface DumperInterface /** * Dumps a scalar value. * - * @param Cursor $cursor The Cursor position in the dump. - * @param string $type The PHP type of the value being dumped. - * @param scalar $value The scalar value being dumped. + * @param Cursor $cursor The Cursor position in the dump + * @param string $type The PHP type of the value being dumped + * @param scalar $value The scalar value being dumped */ public function dumpScalar(Cursor $cursor, $type, $value); /** * Dumps a string. * - * @param Cursor $cursor The Cursor position in the dump. - * @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. + * @param Cursor $cursor The Cursor position in the dump + * @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 Cursor $cursor The Cursor position in the dump. - * @param int $type A Cursor::HASH_* const for the type of hash. - * @param string $class The object class, resource type or array count. - * @param bool $hasChild When the dump of the hash has child item. + * @param Cursor $cursor The Cursor position in the dump + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string $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 Cursor $cursor The Cursor position in the dump. - * @param int $type A Cursor::HASH_* const for the type of hash. - * @param string $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. + * @param Cursor $cursor The Cursor position in the dump + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string $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); } diff --git a/htdocs/includes/symfony/var-dumper/Cloner/Stub.php b/htdocs/includes/symfony/var-dumper/Cloner/Stub.php index f58a57a7276..313c591fc83 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/Stub.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/Stub.php @@ -37,4 +37,5 @@ class Stub public $handle = 0; public $refCount = 0; public $position = 0; + public $attr = array(); } diff --git a/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php b/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php index 20cc8d08354..6a3b451bda7 100644 --- a/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php +++ b/htdocs/includes/symfony/var-dumper/Cloner/VarCloner.php @@ -25,10 +25,9 @@ class VarCloner extends AbstractCloner protected function doClone($var) { $useExt = $this->useExt; - $i = 0; // Current iteration position in $queue $len = 1; // Length of $queue $pos = 0; // Number of cloned items past the first level - $refs = 0; // Hard references counter + $refsCounter = 0; // Hard references counter $queue = array(array($var)); // This breadth-first queue is the return value $arrayRefs = array(); // Map of queue indexes to stub array objects $hardRefs = array(); // Map of original zval hashes to stub objects @@ -60,27 +59,32 @@ class VarCloner extends AbstractCloner for ($i = 0; $i < $len; ++$i) { $indexed = true; // Whether the currently iterated array is numerically indexed or not $j = -1; // Position in the currently iterated array - $step = $queue[$i]; // Copy of the currently iterated array used for hard references detection - foreach ($step as $k => $v) { + $fromObjCast = array_keys($queue[$i]); + $fromObjCast = array_keys(array_flip($fromObjCast)) !== $fromObjCast; + $refs = $vals = $fromObjCast ? array_values($queue[$i]) : $queue[$i]; + foreach ($queue[$i] as $k => $v) { // $k is the original key // $v is the original value or a stub object in case of hard references - if ($indexed && $k !== ++$j) { + if ($k !== ++$j) { $indexed = false; } + if ($fromObjCast) { + $k = $j; + } if ($useExt) { - $zval = symfony_zval_info($k, $step); + $zval = symfony_zval_info($k, $refs); } else { - $step[$k] = $cookie; - if ($zval['zval_isref'] = $queue[$i][$k] === $cookie) { + $refs[$k] = $cookie; + if ($zval['zval_isref'] = $vals[$k] === $cookie) { $zval['zval_hash'] = $v instanceof Stub ? spl_object_hash($v) : null; } $zval['type'] = gettype($v); } if ($zval['zval_isref']) { - $queue[$i][$k] = &$stub; // Break hard references to make $queue completely + $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure if (isset($hardRefs[$zval['zval_hash']])) { - $queue[$i][$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($step[$k] = $v); + $vals[$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($refs[$k] = $v); if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } @@ -102,12 +106,12 @@ class VarCloner extends AbstractCloner } else { $stub->value = $v; } - } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = iconv_strlen($v, 'UTF-8') - $maxString) { + } 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 = iconv_substr($v, 0, $maxString, 'UTF-8'); + $stub->value = mb_substr($v, 0, $maxString, 'UTF-8'); } break; @@ -178,10 +182,13 @@ class VarCloner extends AbstractCloner case 'resource': case 'unknown type': + case 'resource (closed)': if (empty($resRefs[$h = (int) $v])) { $stub = new Stub(); $stub->type = Stub::TYPE_RESOURCE; - $stub->class = $zval['resource_type'] ?: get_resource_type($v); + if ('Unknown' === $stub->class = $zval['resource_type'] ?: @get_resource_type($v)) { + $stub->class = 'Closed'; + } $stub->value = $v; $stub->handle = $h; $a = $this->castResource($stub, 0 < $i); @@ -204,18 +211,18 @@ class VarCloner extends AbstractCloner if (isset($stub)) { if ($zval['zval_isref']) { if ($useExt) { - $queue[$i][$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub(); + $vals[$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub(); $v->value = $stub; } else { - $step[$k] = new Stub(); - $step[$k]->value = $stub; - $h = spl_object_hash($step[$k]); - $queue[$i][$k] = $hardRefs[$h] = &$step[$k]; + $refs[$k] = new Stub(); + $refs[$k]->value = $stub; + $h = spl_object_hash($refs[$k]); + $vals[$k] = $hardRefs[$h] = &$refs[$k]; $values[$h] = $v; } - $queue[$i][$k]->handle = ++$refs; + $vals[$k]->handle = ++$refsCounter; } else { - $queue[$i][$k] = $stub; + $vals[$k] = $stub; } if ($a) { @@ -243,19 +250,38 @@ class VarCloner extends AbstractCloner $stub = $a = null; } elseif ($zval['zval_isref']) { if ($useExt) { - $queue[$i][$k] = $hardRefs[$zval['zval_hash']] = new Stub(); - $queue[$i][$k]->value = $v; + $vals[$k] = $hardRefs[$zval['zval_hash']] = new Stub(); + $vals[$k]->value = $v; } else { - $step[$k] = $queue[$i][$k] = new Stub(); - $step[$k]->value = $v; - $h = spl_object_hash($step[$k]); - $hardRefs[$h] = &$step[$k]; + $refs[$k] = $vals[$k] = new Stub(); + $refs[$k]->value = $v; + $h = spl_object_hash($refs[$k]); + $hardRefs[$h] = &$refs[$k]; $values[$h] = $v; } - $queue[$i][$k]->handle = ++$refs; + $vals[$k]->handle = ++$refsCounter; } } + if ($fromObjCast) { + $refs = $vals; + $vals = array(); + $j = -1; + foreach ($queue[$i] as $k => $v) { + foreach (array($k => $v) as $a => $v) { + } + if ($a !== $k) { + $vals = (object) $vals; + $vals->{$k} = $refs[++$j]; + $vals = (array) $vals; + } else { + $vals[$k] = $refs[++$j]; + } + } + } + + $queue[$i] = $vals; + if (isset($arrayRefs[$i])) { if ($indexed) { $arrayRefs[$i]->class = Stub::ARRAY_INDEXED; @@ -291,7 +317,7 @@ class VarCloner extends AbstractCloner if (!empty($frame['line'])) { ob_start(); debug_zval_dump($obj); - self::$hashMask = strlen(substr(ob_get_clean(), 17)); + self::$hashMask = (int) substr(ob_get_clean(), 17); } } diff --git a/htdocs/includes/symfony/var-dumper/Dumper/AbstractDumper.php b/htdocs/includes/symfony/var-dumper/Dumper/AbstractDumper.php index f8b9c107779..12f835b1ffa 100644 --- a/htdocs/includes/symfony/var-dumper/Dumper/AbstractDumper.php +++ b/htdocs/includes/symfony/var-dumper/Dumper/AbstractDumper.php @@ -21,6 +21,9 @@ use Symfony\Component\VarDumper\Cloner\DumperInterface; */ abstract class AbstractDumper implements DataDumperInterface, DumperInterface { + const DUMP_LIGHT_ARRAY = 1; + const DUMP_STRING_LENGTH = 2; + public static $defaultOutput = 'php://output'; protected $line = ''; @@ -28,18 +31,21 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface 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 $charset The default character encoding to use for non-UTF8 strings. + * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput + * @param string $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, $charset = null) + public function __construct($output = null, $charset = null, $flags = 0) { + $this->flags = (int) $flags; $this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'); - $this->decimalPoint = (string) 0.5; - $this->decimalPoint = $this->decimalPoint[1]; + $this->decimalPoint = localeconv(); + $this->decimalPoint = $this->decimalPoint['decimal_point']; $this->setOutput($output ?: static::$defaultOutput); if (!$output && is_string(static::$defaultOutput)) { static::$defaultOutput = $this->outputStream; @@ -49,9 +55,9 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Sets the output destination of the dumps. * - * @param callable|resource|string $output A line dumper callable, an opened stream or an output path. + * @param callable|resource|string $output A line dumper callable, an opened stream or an output path * - * @return callable|resource|string The previous output destination. + * @return callable|resource|string The previous output destination */ public function setOutput($output) { @@ -74,9 +80,9 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Sets the default character encoding to use for non-UTF8 strings. * - * @param string $charset 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. + * @return string The previous charset */ public function setCharset($charset) { @@ -93,9 +99,9 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Sets the indentation pad string. * - * @param string $pad A string the will be prepended to dumped lines, repeated by nesting level. + * @param string $pad A string the will be prepended to dumped lines, repeated by nesting level * - * @return string The indent pad. + * @return string The indent pad */ public function setIndentPad($pad) { @@ -108,33 +114,43 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Dumps a Data object. * - * @param Data $data A Data object. - * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path. + * @param Data $data 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) { - $exception = null; + $this->decimalPoint = localeconv(); + $this->decimalPoint = $this->decimalPoint['decimal_point']; + + if ($returnDump = true === $output) { + $output = fopen('php://memory', 'r+b'); + } if ($output) { $prevOutput = $this->setOutput($output); } try { $data->dump($this); $this->dumpLine(-1); - } catch (\Exception $exception) { - // Re-thrown below - } - if ($output) { - $this->setOutput($prevOutput); - } - if (null !== $exception) { - throw $exception; + + if ($returnDump) { + $result = stream_get_contents($output, -1, 0); + fclose($output); + + return $result; + } + } finally { + if ($output) { + $this->setOutput($prevOutput); + } } } /** * Dumps the current line. * - * @param int $depth The recursive depth in the dumped structure for the line being dumped. + * @param int $depth The recursive depth in the dumped structure for the line being dumped */ protected function dumpLine($depth) { @@ -145,8 +161,9 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Generic line dumper callback. * - * @param string $line The line to write. - * @param int $depth The recursive depth in the dumped structure. + * @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) { @@ -158,12 +175,20 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * Converts a non-UTF-8 string to UTF-8. * - * @param string $s The non-UTF-8 string to convert. + * @param string $s The non-UTF-8 string to convert * - * @return string The string converted to UTF-8. + * @return string The string converted to UTF-8 */ protected function utf8Encode($s) { + if (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; } diff --git a/htdocs/includes/symfony/var-dumper/Dumper/CliDumper.php b/htdocs/includes/symfony/var-dumper/Dumper/CliDumper.php index bca2abcb3d0..540f9245fdf 100644 --- a/htdocs/includes/symfony/var-dumper/Dumper/CliDumper.php +++ b/htdocs/includes/symfony/var-dumper/Dumper/CliDumper.php @@ -54,12 +54,12 @@ class CliDumper extends AbstractDumper /** * {@inheritdoc} */ - public function __construct($output = null, $charset = null) + public function __construct($output = null, $charset = null, $flags = 0) { - parent::__construct($output, $charset); + parent::__construct($output, $charset, $flags); - if ('\\' === DIRECTORY_SEPARATOR && false !== @getenv('ANSICON')) { - // Use only the base 16 xterm colors when using ANSICON + if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) { + // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI $this->setStyles(array( 'default' => '31', 'num' => '1;34', @@ -97,7 +97,7 @@ class CliDumper extends AbstractDumper /** * Configures styles. * - * @param array $styles A map of style names to style definitions. + * @param array $styles A map of style names to style definitions */ public function setStyles(array $styles) { @@ -112,9 +112,13 @@ class CliDumper extends AbstractDumper $this->dumpKey($cursor); $style = 'const'; - $attr = array(); + $attr = $cursor->attr; switch ($type) { + case 'default': + $style = 'default'; + break; + case 'integer': $style = 'num'; break; @@ -123,9 +127,9 @@ class CliDumper extends AbstractDumper $style = 'num'; switch (true) { - case INF === $value: $value = 'INF'; break; + case INF === $value: $value = 'INF'; break; case -INF === $value: $value = '-INF'; break; - case is_nan($value): $value = 'NAN'; break; + case is_nan($value): $value = 'NAN'; break; default: $value = (string) $value; if (false === strpos($value, $this->decimalPoint)) { @@ -144,8 +148,8 @@ class CliDumper extends AbstractDumper break; default: - $attr['value'] = isset($value[0]) && !preg_match('//u', $value) ? $this->utf8Encode($value) : $value; - $value = isset($type[0]) && !preg_match('//u', $type) ? $this->utf8Encode($type) : $type; + $attr += array('value' => $this->utf8Encode($value)); + $value = $this->utf8Encode($type); break; } @@ -160,6 +164,7 @@ class CliDumper extends AbstractDumper public function dumpString(Cursor $cursor, $str, $bin, $cut) { $this->dumpKey($cursor); + $attr = $cursor->attr; if ($bin) { $str = $this->utf8Encode($str); @@ -168,8 +173,8 @@ class CliDumper extends AbstractDumper $this->line .= '""'; $this->dumpLine($cursor->depth, true); } else { - $attr = array( - 'length' => 0 <= $cut ? iconv_strlen($str, 'UTF-8') + $cut : 0, + $attr += array( + 'length' => 0 <= $cut ? mb_strlen($str, 'UTF-8') + $cut : 0, 'binary' => $bin, ); $str = explode("\n", $str); @@ -180,6 +185,9 @@ class CliDumper extends AbstractDumper $m = count($str) - 1; $i = $lineCut = 0; + if (self::DUMP_STRING_LENGTH & $this->flags) { + $this->line .= '('.$attr['length'].') '; + } if ($bin) { $this->line .= 'b'; } @@ -195,8 +203,8 @@ class CliDumper extends AbstractDumper if ($i < $m) { $str .= "\n"; } - if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = iconv_strlen($str, 'UTF-8')) { - $str = iconv_substr($str, 0, $this->maxStringWidth, 'UTF-8'); + if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = mb_strlen($str, 'UTF-8')) { + $str = mb_substr($str, 0, $this->maxStringWidth, 'UTF-8'); $lineCut = $len - $this->maxStringWidth; } if ($m && 0 < $cursor->depth) { @@ -241,15 +249,13 @@ class CliDumper extends AbstractDumper { $this->dumpKey($cursor); - if (!preg_match('//u', $class)) { - $class = $this->utf8Encode($class); - } + $class = $this->utf8Encode($class); if (Cursor::HASH_OBJECT === $type) { $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{'; } elseif (Cursor::HASH_RESOURCE === $type) { $prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' '); } else { - $prefix = $class ? $this->style('note', 'array:'.$class).' [' : '['; + $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; } if ($cursor->softRefCount || 0 < $cursor->softRefHandle) { @@ -280,9 +286,9 @@ class CliDumper extends AbstractDumper /** * Dumps an ellipsis for cut children. * - * @param Cursor $cursor The Cursor position in the dump. - * @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. + * @param Cursor $cursor The Cursor position in the dump + * @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 */ protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut) { @@ -300,7 +306,7 @@ class CliDumper extends AbstractDumper /** * Dumps a key in a hash structure. * - * @param Cursor $cursor The Cursor position in the dump. + * @param Cursor $cursor The Cursor position in the dump */ protected function dumpKey(Cursor $cursor) { @@ -314,6 +320,9 @@ class CliDumper extends AbstractDumper switch ($cursor->hashType) { default: case Cursor::HASH_INDEXED: + if (self::DUMP_LIGHT_ARRAY & $this->flags) { + break; + } $style = 'index'; case Cursor::HASH_ASSOC: if (is_int($key)) { @@ -332,13 +341,17 @@ class CliDumper extends AbstractDumper } elseif (0 < strpos($key, "\0", 1)) { $key = explode("\0", substr($key, 1), 2); - switch ($key[0]) { + switch ($key[0][0]) { case '+': // User inserted keys $attr['dynamic'] = true; $this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": '; break 2; case '~': $style = 'meta'; + if (isset($key[0][1])) { + parse_str(substr($key[0], 1), $attr); + $attr += array('binary' => $cursor->hashKeyIsBinary); + } break; case '*': $style = 'protected'; @@ -368,11 +381,11 @@ class CliDumper extends AbstractDumper /** * Decorates a value with some style. * - * @param string $style The type of style being applied. - * @param string $value The value being styled. - * @param array $attr Optional context information. + * @param string $style The type of style being applied + * @param string $value The value being styled + * @param array $attr Optional context information * - * @return string The value with style decoration. + * @return string The value with style decoration */ protected function style($style, $value, $attr = array()) { @@ -412,7 +425,7 @@ class CliDumper extends AbstractDumper } /** - * @return bool Tells if the current output stream supports ANSI colors or not. + * @return bool Tells if the current output stream supports ANSI colors or not */ protected function supportsColors() { @@ -446,7 +459,12 @@ class CliDumper extends AbstractDumper } if ('\\' === DIRECTORY_SEPARATOR) { - static::$defaultColors = @(false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM')); + static::$defaultColors = @( + '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + ); } elseif (function_exists('posix_isatty')) { $h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null); $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream; diff --git a/htdocs/includes/symfony/var-dumper/Dumper/DataDumperInterface.php b/htdocs/includes/symfony/var-dumper/Dumper/DataDumperInterface.php index ee6060cebf6..2c3d9db850d 100644 --- a/htdocs/includes/symfony/var-dumper/Dumper/DataDumperInterface.php +++ b/htdocs/includes/symfony/var-dumper/Dumper/DataDumperInterface.php @@ -23,7 +23,7 @@ interface DataDumperInterface /** * Dumps a Data object. * - * @param Data $data A Data object. + * @param Data $data A Data object */ public function dump(Data $data); } diff --git a/htdocs/includes/symfony/var-dumper/Dumper/HtmlDumper.php b/htdocs/includes/symfony/var-dumper/Dumper/HtmlDumper.php index 28af8e4cb22..cc0b1ce179c 100644 --- a/htdocs/includes/symfony/var-dumper/Dumper/HtmlDumper.php +++ b/htdocs/includes/symfony/var-dumper/Dumper/HtmlDumper.php @@ -25,13 +25,13 @@ class HtmlDumper extends CliDumper protected $dumpHeader; protected $dumpPrefix = '
';
-    protected $dumpSuffix = '
'; + protected $dumpSuffix = ''; protected $dumpId = 'sf-dump'; protected $colors = true; protected $headerIsDumped = false; protected $lastDepth = -1; protected $styles = array( - 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:100000; word-break: normal', + 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: normal', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', 'str' => 'font-weight:bold; color:#56DB3A', @@ -43,27 +43,24 @@ class HtmlDumper extends CliDumper 'meta' => 'color:#B729D9', 'key' => 'color:#56DB3A', 'index' => 'color:#1299DA', + 'ellipsis' => 'color:#FF8400', ); + private $displayOptions = array( + 'maxDepth' => 1, + 'maxStringLength' => 160, + 'fileLinkFormat' => null, + ); + private $extraDisplayOptions = array(); + /** * {@inheritdoc} */ - public function __construct($output = null, $charset = null) + public function __construct($output = null, $charset = null, $flags = 0) { - AbstractDumper::__construct($output, $charset); + AbstractDumper::__construct($output, $charset, $flags); $this->dumpId = 'sf-dump-'.mt_rand(); - } - - /** - * {@inheritdoc} - */ - public function setOutput($output) - { - if ($output !== $prev = parent::setOutput($output)) { - $this->headerIsDumped = false; - } - - return $prev; + $this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); } /** @@ -75,10 +72,21 @@ class HtmlDumper extends CliDumper $this->styles = $styles + $this->styles; } + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->headerIsDumped = false; + $this->displayOptions = $displayOptions + $this->displayOptions; + } + /** * Sets an HTML header that will be dumped once in the output stream. * - * @param string $header An HTML string. + * @param string $header An HTML string */ public function setDumpHeader($header) { @@ -88,8 +96,8 @@ class HtmlDumper extends CliDumper /** * Sets an HTML prefix and suffix that will encapse every single dump. * - * @param string $prefix The prepended HTML string. - * @param string $suffix The appended HTML string. + * @param string $prefix The prepended HTML string + * @param string $suffix The appended HTML string */ public function setDumpBoundaries($prefix, $suffix) { @@ -100,10 +108,13 @@ class HtmlDumper extends CliDumper /** * {@inheritdoc} */ - public function dump(Data $data, $output = null) + public function dump(Data $data, $output = null, array $extraDisplayOptions = array()) { - parent::dump($data, $output); + $this->extraDisplayOptions = $extraDisplayOptions; + $result = parent::dump($data, $output); $this->dumpId = 'sf-dump-'.mt_rand(); + + return $result; } /** @@ -111,13 +122,13 @@ class HtmlDumper extends CliDumper */ protected function getDumpHeader() { - $this->headerIsDumped = true; + $this->headerIsDumped = null !== $this->outputStream ? $this->outputStream : $this->lineDumper; if (null !== $this->dumpHeader) { return $this->dumpHeader; } - $line = <<<'EOHTML' + $line = str_replace('{$options}', json_encode($this->displayOptions, JSON_FORCE_OBJECT), <<<'EOHTML' -'.$this->dumpHeader; @@ -374,7 +448,7 @@ EOHTML; return ''; } - $v = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); + $v = esc($value); if ('ref' === $style) { if (empty($attr['count'])) { @@ -385,41 +459,47 @@ EOHTML; return sprintf('%s', $this->dumpId, $r, 1 + $attr['count'], $v); } - if ('const' === $style && array_key_exists('value', $attr)) { - $style .= sprintf(' title="%s"', htmlspecialchars(json_encode($attr['value']), ENT_QUOTES, 'UTF-8')); + if ('const' === $style && isset($attr['value'])) { + $style .= sprintf(' title="%s"', esc(is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value']))); } elseif ('public' === $style) { $style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'); } elseif ('str' === $style && 1 < $attr['length']) { - $style .= sprintf(' title="%s%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); + $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); } elseif ('note' === $style && false !== $c = strrpos($v, '\\')) { return sprintf('%s', $v, $style, substr($v, $c + 1)); } elseif ('protected' === $style) { $style .= ' title="Protected property"'; + } elseif ('meta' === $style && isset($attr['title'])) { + $style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title']))); } elseif ('private' === $style) { - $style .= sprintf(' title="Private property defined in class: `%s`"', $attr['class']); + $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); + } + $map = static::$controlCharsMap; + + if (isset($attr['ellipsis'])) { + $label = esc(substr($value, -$attr['ellipsis'])); + $style = str_replace(' title="', " title=\"$v\n", $style); + $v = sprintf('%s%s', substr($v, 0, -strlen($label)), $label); } - $map = static::$controlCharsMap; - $style = ""; - $v = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $style) { - $s = ''; + $v = "".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { + $s = ''; $c = $c[$i = 0]; do { $s .= isset($map[$c[$i]]) ? $map[$c[$i]] : sprintf('\x%02X', ord($c[$i])); } while (isset($c[++$i])); - return $s.$style; - }, $v, -1, $cchrCount); + return $s.''; + }, $v).''; - if ($cchrCount && '<' === $v[0]) { - $v = substr($v, 7); - } else { - $v = $style.$v; + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) { + $attr['href'] = $href; } - if ($cchrCount && '>' === substr($v, -1)) { - $v = substr($v, 0, -strlen($style)); - } else { - $v .= ''; + if (isset($attr['href'])) { + $v = sprintf('%s', esc($this->utf8Encode($attr['href'])), $v); + } + if (isset($attr['lang'])) { + $v = sprintf('%s', esc($attr['lang']), $v); } return $v; @@ -433,12 +513,17 @@ EOHTML; if (-1 === $this->lastDepth) { $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; } - if (!$this->headerIsDumped) { + if ($this->headerIsDumped !== (null !== $this->outputStream ? $this->outputStream : $this->lineDumper)) { $this->line = $this->getDumpHeader().$this->line; } if (-1 === $depth) { - $this->line .= sprintf($this->dumpSuffix, $this->dumpId); + $args = array('"'.$this->dumpId.'"'); + if ($this->extraDisplayOptions) { + $args[] = json_encode($this->extraDisplayOptions, JSON_FORCE_OBJECT); + } + // Replace is for BC + $this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); } $this->lastDepth = $depth; @@ -449,4 +534,20 @@ EOHTML; } AbstractDumper::dumpLine($depth); } + + private function getSourceLink($file, $line) + { + $options = $this->extraDisplayOptions + $this->displayOptions; + + if ($fmt = $options['fileLinkFormat']) { + return is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line); + } + + return false; + } +} + +function esc($str) +{ + return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } diff --git a/htdocs/includes/symfony/var-dumper/LICENSE b/htdocs/includes/symfony/var-dumper/LICENSE index ef1cde91a61..207646a052d 100644 --- a/htdocs/includes/symfony/var-dumper/LICENSE +++ b/htdocs/includes/symfony/var-dumper/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2015 Fabien Potencier +Copyright (c) 2014-2017 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 diff --git a/htdocs/includes/symfony/var-dumper/README.md b/htdocs/includes/symfony/var-dumper/README.md index 71bff335a70..3b5d55f5f5b 100644 --- a/htdocs/includes/symfony/var-dumper/README.md +++ b/htdocs/includes/symfony/var-dumper/README.md @@ -1,14 +1,15 @@ -Symfony mechanism for exploring and dumping PHP variables -========================================================= +VarDumper Component +=================== -This component provides a mechanism that allows exploring then dumping -any PHP variable. +The VarDumper component provides mechanisms for walking through any arbitrary +PHP variable. Built on top, it provides a better `dump()` function that you +can use instead of `var_dump`. -It handles scalars, objects and resources properly, taking hard and soft -references into account. More than being immune to infinite recursion -problems, it allows dumping where references link to each other. -It explores recursive structures using a breadth-first algorithm. +Resources +--------- -The component exposes all the parts involved in the different steps of -cloning then dumping a PHP variable, while applying size limits and having -specialized output formats and methods. + * [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/htdocs/includes/symfony/var-dumper/Test/VarDumperTestTrait.php b/htdocs/includes/symfony/var-dumper/Test/VarDumperTestTrait.php index e5f6bf5b98e..40ec83d1322 100644 --- a/htdocs/includes/symfony/var-dumper/Test/VarDumperTestTrait.php +++ b/htdocs/includes/symfony/var-dumper/Test/VarDumperTestTrait.php @@ -29,17 +29,20 @@ trait VarDumperTestTrait $this->assertStringMatchesFormat(rtrim($dump), $this->getDump($data), $message); } - protected function getDump($data) + protected function getDump($data, $key = null) { - $h = fopen('php://memory', 'r+b'); + $flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0; + $flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0; + $cloner = new VarCloner(); $cloner->setMaxItems(-1); - $dumper = new CliDumper($h); + $dumper = new CliDumper(null, null, $flags); $dumper->setColors(false); - $dumper->dump($cloner->cloneVar($data)->withRefHandles(false)); - $data = stream_get_contents($h, -1, 0); - fclose($h); + $data = $cloner->cloneVar($data)->withRefHandles(false); + if (null !== $key && null === $data = $data->seek($key)) { + return; + } - return rtrim($data); + return rtrim($dumper->dump($data, true)); } } diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/CasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/CasterTest.php index 43d389ce1c0..105d5638ee1 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/Caster/CasterTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/CasterTest.php @@ -11,13 +11,14 @@ namespace Symfony\Component\VarDumper\Tests\Caster; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; /** * @author Nicolas Grekas */ -class CasterTest extends \PHPUnit_Framework_TestCase +class CasterTest extends TestCase { use VarDumperTestTrait; diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/ExceptionCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/ExceptionCasterTest.php new file mode 100644 index 00000000000..e0fb177b4bb --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/ExceptionCasterTest.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Caster\ExceptionCaster; +use Symfony\Component\VarDumper\Caster\FrameStub; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +class ExceptionCasterTest extends TestCase +{ + use VarDumperTestTrait; + + private function getTestException($msg, &$ref = null) + { + return new \Exception(''.$msg); + } + + protected function tearDown() + { + ExceptionCaster::$srcContext = 1; + ExceptionCaster::$traceArgs = true; + } + + public function testDefaultSettings() + { + $ref = array('foo'); + $e = $this->getTestException('foo', $ref); + + $expectedDump = <<<'EODUMP' +Exception { + #message: "foo" + #code: 0 + #file: "%sExceptionCasterTest.php" + #line: 27 + -trace: { + %sExceptionCasterTest.php:27: { + : { + : return new \Exception(''.$msg); + : } + } + %sExceptionCasterTest.php:%d: { + : $ref = array('foo'); + : $e = $this->getTestException('foo', $ref); + : + arguments: { + $msg: "foo" + &$ref: array:1 [ …1] + } + } +%A +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $e); + $this->assertSame(array('foo'), $ref); + } + + public function testSeek() + { + $e = $this->getTestException(2); + + $expectedDump = <<<'EODUMP' +{ + %sExceptionCasterTest.php:27: { + : { + : return new \Exception(''.$msg); + : } + } + %sExceptionCasterTest.php:%d: { + : { + : $e = $this->getTestException(2); + : + arguments: { + $msg: 2 + } + } +%A +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $this->getDump($e, 'trace')); + } + + public function testNoArgs() + { + $e = $this->getTestException(1); + ExceptionCaster::$traceArgs = false; + + $expectedDump = <<<'EODUMP' +Exception { + #message: "1" + #code: 0 + #file: "%sExceptionCasterTest.php" + #line: 27 + -trace: { + %sExceptionCasterTest.php:27: { + : { + : return new \Exception(''.$msg); + : } + } + %sExceptionCasterTest.php:%d: { + : { + : $e = $this->getTestException(1); + : ExceptionCaster::$traceArgs = false; + } +%A +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $e); + } + + public function testNoSrcContext() + { + $e = $this->getTestException(1); + ExceptionCaster::$srcContext = -1; + + $expectedDump = <<<'EODUMP' +Exception { + #message: "1" + #code: 0 + #file: "%sExceptionCasterTest.php" + #line: 27 + -trace: { + %sExceptionCasterTest.php: 27 + %sExceptionCasterTest.php: %d +%A +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $e); + } + + public function testHtmlDump() + { + $e = $this->getTestException(1); + ExceptionCaster::$srcContext = -1; + + $cloner = new VarCloner(); + $cloner->setMaxItems(1); + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $dump = $dumper->dump($cloner->cloneVar($e)->withRefHandles(false), true); + + $expectedDump = <<<'EODUMP' +Exception { + #message: "1" + #code: 0 + #file: "%sTests%eCaster%eExceptionCasterTest.php" + #line: 27 + -trace: { + %sVarDumper%eTests%eCaster%eExceptionCasterTest.php: 27 + …%d + } +} + +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $dump); + } + + /** + * @requires function Twig\Template::getSourceContext + */ + public function testFrameWithTwig() + { + require_once dirname(__DIR__).'/Fixtures/Twig.php'; + + $f = array( + new FrameStub(array( + 'file' => dirname(__DIR__).'/Fixtures/Twig.php', + 'line' => 20, + 'class' => '__TwigTemplate_VarDumperFixture_u75a09', + )), + new FrameStub(array( + 'file' => dirname(__DIR__).'/Fixtures/Twig.php', + 'line' => 21, + 'class' => '__TwigTemplate_VarDumperFixture_u75a09', + 'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, __FILE__), + )), + ); + + $expectedDump = <<<'EODUMP' +array:2 [ + 0 => { + class: "__TwigTemplate_VarDumperFixture_u75a09" + src: { + %sTwig.php:1: { + : + : foo bar + : twig source + } + } + } + 1 => { + class: "__TwigTemplate_VarDumperFixture_u75a09" + object: __TwigTemplate_VarDumperFixture_u75a09 { + %A + } + src: { + %sExceptionCasterTest.php:2: { + : foo bar + : twig source + : + } + } + } +] + +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $f); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/PdoCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/PdoCasterTest.php index faa65341170..000e5feeb12 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/Caster/PdoCasterTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/PdoCasterTest.php @@ -11,14 +11,18 @@ namespace Symfony\Component\VarDumper\Tests\Caster; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Caster\PdoCaster; use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; /** * @author Nicolas Grekas */ -class PdoCasterTest extends \PHPUnit_Framework_TestCase +class PdoCasterTest extends TestCase { + use VarDumperTestTrait; + /** * @requires extension pdo_sqlite */ @@ -36,22 +40,25 @@ class PdoCasterTest extends \PHPUnit_Framework_TestCase $this->assertSame('NATURAL', $attr['CASE']->class); $this->assertSame('BOTH', $attr['DEFAULT_FETCH_MODE']->class); - $xCast = array( - "\0~\0inTransaction" => $pdo->inTransaction(), - "\0~\0attributes" => array( - 'CASE' => $attr['CASE'], - 'ERRMODE' => $attr['ERRMODE'], - 'PERSISTENT' => false, - 'DRIVER_NAME' => 'sqlite', - 'ORACLE_NULLS' => $attr['ORACLE_NULLS'], - 'CLIENT_VERSION' => $pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION), - 'SERVER_VERSION' => $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), - 'STATEMENT_CLASS' => array('PDOStatement'), - 'DEFAULT_FETCH_MODE' => $attr['DEFAULT_FETCH_MODE'], - ), - ); - unset($cast["\0~\0attributes"]['STATEMENT_CLASS'][1]); + $xDump = <<<'EODUMP' +array:2 [ + "\x00~\x00inTransaction" => false + "\x00~\x00attributes" => array:9 [ + "CASE" => NATURAL + "ERRMODE" => SILENT + "PERSISTENT" => false + "DRIVER_NAME" => "sqlite" + "ORACLE_NULLS" => NATURAL + "CLIENT_VERSION" => "%s" + "SERVER_VERSION" => "%s" + "STATEMENT_CLASS" => array:%d [ + 0 => "PDOStatement"%A + ] + "DEFAULT_FETCH_MODE" => BOTH + ] +] +EODUMP; - $this->assertSame($xCast, $cast); + $this->assertDumpMatchesFormat($xDump, $cast); } } diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/RedisCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/RedisCasterTest.php new file mode 100644 index 00000000000..af038192f5c --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/RedisCasterTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +/** + * @author Nicolas Grekas + * @requires extension redis + */ +class RedisCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testNotConnected() + { + $redis = new \Redis(); + + if (defined('HHVM_VERSION_ID')) { + $xCast = <<<'EODUMP' +Redis { + #host: "" +%A +} +EODUMP; + } else { + $xCast = <<<'EODUMP' +Redis { + isConnected: false +} +EODUMP; + } + + $this->assertDumpMatchesFormat($xCast, $redis); + } + + public function testConnected() + { + $redis = new \Redis(); + if (!@$redis->connect('127.0.0.1')) { + $e = error_get_last(); + self::markTestSkipped($e['message']); + } + + if (defined('HHVM_VERSION_ID')) { + $xCast = <<<'EODUMP' +Redis { + #host: "127.0.0.1" +%A +} +EODUMP; + } else { + $xCast = <<<'EODUMP' +Redis { + +"socket": Redis Socket Buffer resource + isConnected: true + host: "127.0.0.1" + port: 6379 + auth: null + dbNum: 0 + timeout: 0.0 + persistentId: null + options: { + READ_TIMEOUT: 0.0 + SERIALIZER: NONE + PREFIX: null + SCAN: NORETRY + } +} +EODUMP; + } + + $this->assertDumpMatchesFormat($xCast, $redis); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/ReflectionCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/ReflectionCasterTest.php index 0d7147fbcd2..5495a78e40f 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/Caster/ReflectionCasterTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/ReflectionCasterTest.php @@ -11,13 +11,15 @@ namespace Symfony\Component\VarDumper\Tests\Caster; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; use Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo; +use Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass; /** * @author Nicolas Grekas */ -class ReflectionCasterTest extends \PHPUnit_Framework_TestCase +class ReflectionCasterTest extends TestCase { use VarDumperTestTrait; @@ -49,7 +51,7 @@ ReflectionClass { "export" => ReflectionMethod { +name: "export" +class: "ReflectionClass" - parameters: { +%A parameters: { $%s: ReflectionParameter { %A position: 0 %A @@ -75,7 +77,7 @@ Closure { \$b: & 123 } file: "%sReflectionCasterTest.php" - line: "65 to 65" + line: "67 to 67" } EOTXT , $var @@ -91,7 +93,7 @@ EOTXT ReflectionParameter { +name: "arg1" position: 0 - typeHint: "Symfony\Component\VarDumper\Tests\Caster\NotExistingClass" + typeHint: "Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass" default: null } EOTXT @@ -146,83 +148,88 @@ EOTXT */ public function testGenerator() { - $g = new GeneratorDemo(); - $g = $g->baz(); - $r = new \ReflectionGenerator($g); + if (extension_loaded('xdebug')) { + $this->markTestSkipped('xdebug is active'); + } - $xDump = <<<'EODUMP' + $generator = new GeneratorDemo(); + $generator = $generator->baz(); + + $expectedDump = <<<'EODUMP' Generator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} executing: { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz(): { - %sGeneratorDemo.php:14: """ - {\n - yield from bar();\n - }\n - """ + %sGeneratorDemo.php:14: { + : { + : yield from bar(); + : } + } } } + closed: false } EODUMP; - $this->assertDumpMatchesFormat($xDump, $g); + $this->assertDumpMatchesFormat($expectedDump, $generator); - foreach ($g as $v) { + foreach ($generator as $v) { break; } - $xDump = <<<'EODUMP' + $expectedDump = <<<'EODUMP' array:2 [ 0 => ReflectionGenerator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} trace: { - 3. Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() ==> yield(): { - src: { - %sGeneratorDemo.php:9: """ - {\n - yield 1;\n - }\n - """ - } + %sGeneratorDemo.php:9: { + : { + : yield 1; + : } } - 2. Symfony\Component\VarDumper\Tests\Fixtures\bar() ==> Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): { - src: { - %sGeneratorDemo.php:20: """ - {\n - yield from GeneratorDemo::foo();\n - }\n - """ - } + %sGeneratorDemo.php:20: { + : { + : yield from GeneratorDemo::foo(); + : } } - 1. Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() ==> Symfony\Component\VarDumper\Tests\Fixtures\bar(): { - src: { - %sGeneratorDemo.php:14: """ - {\n - yield from bar();\n - }\n - """ - } + %sGeneratorDemo.php:14: { + : { + : yield from bar(); + : } } } + closed: false } 1 => Generator { executing: { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): { - %sGeneratorDemo.php:10: """ - yield 1;\n - }\n - \n - """ + %sGeneratorDemo.php:10: { + : yield 1; + : } + : + } } } + closed: false } ] EODUMP; - $this->assertDumpMatchesFormat($xDump, array($r, $r->getExecutingGenerator())); + $r = new \ReflectionGenerator($generator); + $this->assertDumpMatchesFormat($expectedDump, array($r, $r->getExecutingGenerator())); + + foreach ($generator as $v) { + } + + $expectedDump = <<<'EODUMP' +Generator { + closed: true +} +EODUMP; + $this->assertDumpMatchesFormat($expectedDump, $generator); } } -function reflectionParameterFixture(NotExistingClass $arg1 = null, $arg2) +function reflectionParameterFixture(NotLoadableClass $arg1 = null, $arg2) { } diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/SplCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/SplCasterTest.php index 5d71e8d379d..e2181d90b5b 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/Caster/SplCasterTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/SplCasterTest.php @@ -11,12 +11,13 @@ namespace Symfony\Component\VarDumper\Tests\Caster; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; /** * @author Grégoire Pineau */ -class SplCasterTest extends \PHPUnit_Framework_TestCase +class SplCasterTest extends TestCase { use VarDumperTestTrait; @@ -57,12 +58,6 @@ SplFileInfo { pathname: "https://google.com/about" extension: "" realPath: false - writable: false - readable: false - executable: false - file: false - dir: false - link: false %A} EOTXT ), @@ -102,10 +97,10 @@ SplFileObject { file: true dir: false link: false -%AcsvControl: array:2 [ +%AcsvControl: array:%d [ 0 => "," 1 => """ - ] +%A] flags: DROP_NEW_LINE|SKIP_EMPTY maxLineLen: 0 fstat: array:26 [ @@ -123,4 +118,30 @@ SplFileObject { EOTXT; $this->assertDumpMatchesFormat($dump, $var); } + + /** + * @dataProvider provideCastSplDoublyLinkedList + */ + public function testCastSplDoublyLinkedList($modeValue, $modeDump) + { + $var = new \SplDoublyLinkedList(); + $var->setIteratorMode($modeValue); + $dump = <<assertDumpMatchesFormat($dump, $var); + } + + public function provideCastSplDoublyLinkedList() + { + return array( + array(\SplDoublyLinkedList::IT_MODE_FIFO, 'IT_MODE_FIFO | IT_MODE_KEEP'), + array(\SplDoublyLinkedList::IT_MODE_LIFO, 'IT_MODE_LIFO | IT_MODE_KEEP'), + array(\SplDoublyLinkedList::IT_MODE_FIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_FIFO | IT_MODE_DELETE'), + array(\SplDoublyLinkedList::IT_MODE_LIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_LIFO | IT_MODE_DELETE'), + ); + } } diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/StubCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/StubCasterTest.php new file mode 100644 index 00000000000..c626b595f83 --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/StubCasterTest.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Caster\ArgsStub; +use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Component\VarDumper\Caster\LinkStub; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; +use Symfony\Component\VarDumper\Tests\Fixtures\FooInterface; + +class StubCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testArgsStubWithDefaults($foo = 234, $bar = 456) + { + $args = array(new ArgsStub(array(123), __FUNCTION__, __CLASS__)); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => { + $foo: 123 + } +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $args); + } + + public function testArgsStubWithExtraArgs($foo = 234) + { + $args = array(new ArgsStub(array(123, 456), __FUNCTION__, __CLASS__)); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => { + $foo: 123 + ...: { + 456 + } + } +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $args); + } + + public function testArgsStubNoParamWithExtraArgs() + { + $args = array(new ArgsStub(array(123), __FUNCTION__, __CLASS__)); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => { + 123 + } +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $args); + } + + public function testArgsStubWithClosure() + { + $args = array(new ArgsStub(array(123), '{closure}', null)); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => { + 123 + } +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $args); + } + + public function testLinkStub() + { + $var = array(new LinkStub(__CLASS__, 0, __FILE__)); + + $cloner = new VarCloner(); + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $dumper->setDisplayOptions(array('fileLinkFormat' => '%f:%l')); + $dump = $dumper->dump($cloner->cloneVar($var), true); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => "Symfony\Component\VarDumper\Tests\Caster\StubCasterTest" +] + +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $dump); + } + + public function testClassStub() + { + $var = array(new ClassStub('hello', array(FooInterface::class, 'foo'))); + + $cloner = new VarCloner(); + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $dump = $dumper->dump($cloner->cloneVar($var), true, array('fileLinkFormat' => '%f:%l')); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => "hello" +] + +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $dump); + } + + public function testClassStubWithNotExistingClass() + { + $var = array(new ClassStub(NotExisting::class)); + + $cloner = new VarCloner(); + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $dump = $dumper->dump($cloner->cloneVar($var), true); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => "Symfony\Component\VarDumper\Tests\Caster\NotExisting" +] + +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $dump); + } + + public function testClassStubWithNotExistingMethod() + { + $var = array(new ClassStub('hello', array(FooInterface::class, 'missing'))); + + $cloner = new VarCloner(); + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $dump = $dumper->dump($cloner->cloneVar($var), true, array('fileLinkFormat' => '%f:%l')); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => "hello" +] + +EODUMP; + + $this->assertStringMatchesFormat($expectedDump, $dump); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Tests/Caster/XmlReaderCasterTest.php b/htdocs/includes/symfony/var-dumper/Tests/Caster/XmlReaderCasterTest.php new file mode 100644 index 00000000000..374d298af16 --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Tests/Caster/XmlReaderCasterTest.php @@ -0,0 +1,248 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +/** + * @author Baptiste Clavié + */ +class XmlReaderCasterTest extends TestCase +{ + use VarDumperTestTrait; + + /** @var \XmlReader */ + private $reader; + + protected function setUp() + { + $this->reader = new \XmlReader(); + $this->reader->open(__DIR__.'/../Fixtures/xml_reader.xml'); + } + + protected function tearDown() + { + $this->reader->close(); + } + + public function testParserProperty() + { + $this->reader->setParserProperty(\XMLReader::SUBST_ENTITIES, true); + + $expectedDump = <<<'EODUMP' +XMLReader { + +nodeType: NONE + parserProperties: { + SUBST_ENTITIES: true + …3 + } + …12 +} +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $this->reader); + } + + /** + * @dataProvider provideNodes + */ + public function testNodes($seek, $expectedDump) + { + while ($seek--) { + $this->reader->read(); + } + $this->assertDumpMatchesFormat($expectedDump, $this->reader); + } + + public function provideNodes() + { + return array( + array(0, <<<'EODUMP' +XMLReader { + +nodeType: NONE + …13 +} +EODUMP + ), + array(1, <<<'EODUMP' +XMLReader { + +localName: "foo" + +nodeType: ELEMENT + +baseURI: "%sxml_reader.xml" + …11 +} +EODUMP + ), + array(2, <<<'EODUMP' +XMLReader { + +localName: "#text" + +nodeType: SIGNIFICANT_WHITESPACE + +depth: 1 + +value: """ + \n + + """ + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(3, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +baseURI: "%sxml_reader.xml" + …10 +} +EODUMP + ), + array(4, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: END_ELEMENT + +depth: 1 + +baseURI: "%sxml_reader.xml" + …10 +} +EODUMP + ), + array(6, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +isEmptyElement: true + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(9, <<<'EODUMP' +XMLReader { + +localName: "#text" + +nodeType: TEXT + +depth: 2 + +value: "With text" + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(12, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +attributeCount: 2 + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(13, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: END_ELEMENT + +depth: 1 + +baseURI: "%sxml_reader.xml" + …10 +} +EODUMP + ), + array(15, <<<'EODUMP' +XMLReader { + +localName: "bar" + +nodeType: ELEMENT + +depth: 1 + +attributeCount: 1 + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(16, <<<'EODUMP' +XMLReader { + +localName: "#text" + +nodeType: SIGNIFICANT_WHITESPACE + +depth: 2 + +value: """ + \n + + """ + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(17, <<<'EODUMP' +XMLReader { + +localName: "baz" + +prefix: "baz" + +nodeType: ELEMENT + +depth: 2 + +namespaceURI: "http://symfony.com" + +baseURI: "%sxml_reader.xml" + …8 +} +EODUMP + ), + array(18, <<<'EODUMP' +XMLReader { + +localName: "baz" + +prefix: "baz" + +nodeType: END_ELEMENT + +depth: 2 + +namespaceURI: "http://symfony.com" + +baseURI: "%sxml_reader.xml" + …8 +} +EODUMP + ), + array(19, <<<'EODUMP' +XMLReader { + +localName: "#text" + +nodeType: SIGNIFICANT_WHITESPACE + +depth: 2 + +value: """ + \n + + """ + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(21, <<<'EODUMP' +XMLReader { + +localName: "#text" + +nodeType: SIGNIFICANT_WHITESPACE + +depth: 1 + +value: "\n" + +baseURI: "%sxml_reader.xml" + …9 +} +EODUMP + ), + array(22, <<<'EODUMP' +XMLReader { + +localName: "foo" + +nodeType: END_ELEMENT + +baseURI: "%sxml_reader.xml" + …11 +} +EODUMP + ), + ); + } +} diff --git a/htdocs/includes/symfony/var-dumper/Tests/CliDumperTest.php b/htdocs/includes/symfony/var-dumper/Tests/CliDumperTest.php index cd6d64d1c03..1e0809c1fbd 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/CliDumperTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/CliDumperTest.php @@ -11,14 +11,17 @@ namespace Symfony\Component\VarDumper\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; +use Twig\Environment; +use Twig\Loader\FilesystemLoader; /** * @author Nicolas Grekas */ -class CliDumperTest extends \PHPUnit_Framework_TestCase +class CliDumperTest extends TestCase { use VarDumperTestTrait; @@ -62,15 +65,12 @@ array:24 [ 7 => b"é\\x00" "[]" => [] "res" => stream resource {@{$res} - wrapper_type: "plainfile" +%A wrapper_type: "plainfile" stream_type: "STDIO" mode: "r" unread_bytes: 0 seekable: true - timed_out: false - blocked: true - eof: false - options: [] +%A options: [] } "obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d +foo: "foo" @@ -118,7 +118,7 @@ EOTXT $var = xml_parser_create(); $this->assertDumpMatchesFormat( - <<= 70200) { + $this->assertDumpMatchesFormat( + <<<'EOTXT' +array:4 [ + 0 => {} + 1 => &1 null + 2 => &1 null + "" => 2 +] +EOTXT + , + $var + ); + } else { + $this->assertDumpMatchesFormat( + <<<'EOTXT' +array:4 [ + "0" => {} + "1" => &1 null + 0 => &1 null + "" => 2 +] +EOTXT + , + $var + ); + } + } + + public function testObjectCast() + { + $var = (object) array(1 => 1); + $var->{1} = 2; + + if (\PHP_VERSION_ID >= 70200) { + $this->assertDumpMatchesFormat( + <<<'EOTXT' +{ + +"1": 2 +} +EOTXT + , + $var + ); + } else { + $this->assertDumpMatchesFormat( + <<<'EOTXT' +{ + +1: 1 + +"1": 2 +} +EOTXT + , + $var + ); + } + } + public function testClosedResource() { if (defined('HHVM_VERSION') && HHVM_VERSION_ID < 30600) { @@ -152,7 +218,7 @@ EOTXT $this->assertStringMatchesFormat( << 'bar'), + ); + + $this->assertDumpEquals( + << (3) "foo" + 2 => (3) "bar" + ] +] +EOTXT + , + $var + ); + + putenv('DUMP_LIGHT_ARRAY='); + putenv('DUMP_STRING_LENGTH='); + } + + /** + * @requires function Twig\Template::getSourceContext + */ public function testThrowingCaster() { $out = fopen('php://memory', 'r+b'); require_once __DIR__.'/Fixtures/Twig.php'; - $twig = new \__TwigTemplate_VarDumperFixture_u75a09(new \Twig_Environment(new \Twig_Loader_Filesystem())); + $twig = new \__TwigTemplate_VarDumperFixture_u75a09(new Environment(new FilesystemLoader())); $dumper = new CliDumper(); $dumper->setColors(false); @@ -181,96 +282,56 @@ EOTXT ':stream' => eval('return function () use ($twig) { try { $twig->render(array()); - } catch (\Twig_Error_Runtime $e) { + } catch (\Twig\Error\RuntimeError $e) { throw $e->getPrevious(); } };'), )); - $line = __LINE__ - 2; $ref = (int) $out; $data = $cloner->cloneVar($out); $dumper->dump($data, $out); - rewind($out); - $out = stream_get_contents($out); - - if (method_exists($twig, 'getSource')) { - $twig = <<assertStringMatchesFormat( <<doDisplay(\$context, \$blocks); + : } catch (Twig%sError \$e) { + } + %sTemplate.php:%d: { + : { + : \$this->displayWithErrorHandling(\$this->env->mergeGlobals(\$context), array_merge(\$this->blocks, \$blocks)); + : } + } + %sTemplate.php:%d: { + : try { + : \$this->display(\$context); + : } catch (%s \$e) { + } + %sCliDumperTest.php:%d: { +%A + } + } + } +%Awrapper_type: "PHP" stream_type: "MEMORY" mode: "%s+b" unread_bytes: 0 seekable: true uri: "php://memory" - timed_out: false - blocked: true - eof: false - options: [] - ⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r} - #message: "Unexpected Exception thrown from a caster: Foobar" - -trace: { - %d. __TwigTemplate_VarDumperFixture_u75a09->doDisplay() ==> new Exception(): { - src: { - %sTwig.php:19: """ - // line 2\\n - throw new \Exception('Foobar');\\n - }\\n - """ -{$twig} } - } - %d. Twig_Template->displayWithErrorHandling() ==> __TwigTemplate_VarDumperFixture_u75a09->doDisplay(): { - src: { - %sTemplate.php:%d: """ - try {\\n - \$this->doDisplay(\$context, \$blocks);\\n - } catch (Twig_Error \$e) {\\n - """ - } - } - %d. Twig_Template->display() ==> Twig_Template->displayWithErrorHandling(): { - src: { - %sTemplate.php:%d: """ - {\\n - \$this->displayWithErrorHandling(\$this->env->mergeGlobals(\$context), array_merge(\$this->blocks, \$blocks));\\n - }\\n - """ - } - } - %d. Twig_Template->render() ==> Twig_Template->display(): { - src: { - %sTemplate.php:%d: """ - try {\\n - \$this->display(\$context);\\n - } catch (Exception \$e) {\\n - """ - } - } - %d. %slosure%s() ==> Twig_Template->render(): { - src: { - %sCliDumperTest.php:{$line}: """ - }\\n - };'),\\n - ));\\n - """ - } - } - } - } +%Aoptions: [] } EOTXT @@ -288,11 +349,8 @@ EOTXT $dumper->setColors(false); $cloner = new VarCloner(); - $out = fopen('php://memory', 'r+b'); $data = $cloner->cloneVar($var); - $dumper->dump($data, $out); - rewind($out); - $out = stream_get_contents($out); + $out = $dumper->dump($data, true); $r = defined('HHVM_VERSION') ? '' : '#%d'; $this->assertStringMatchesFormat( @@ -318,7 +376,7 @@ EOTXT $var = $this->getSpecialVars(); $this->assertDumpEquals( - << array:1 [ 0 => &1 array:1 [ @@ -364,7 +422,7 @@ EOTXT $dumper->dump($data); $this->assertSame( - << array:1 [ "GLOBALS" => &1 array:1 [ @@ -386,7 +444,7 @@ EOTXT */ public function testBuggyRefs() { - if (PHP_VERSION_ID >= 50600) { + if (\PHP_VERSION_ID >= 50600) { $this->markTestSkipped('PHP 5.6 fixed refs counting'); } @@ -406,7 +464,7 @@ EOTXT }); $this->assertSame( - << array:1 [ 0 => array:1 [ @@ -421,6 +479,21 @@ EOTXT ); } + public function testIncompleteClass() + { + $unserializeCallbackHandler = ini_set('unserialize_callback_func', null); + $var = unserialize('O:8:"Foo\Buzz":0:{}'); + ini_set('unserialize_callback_func', $unserializeCallbackHandler); + + $this->assertDumpMatchesFormat( + <<parent = false; - - $this->blocks = array( - ); + $this->blocks = array(); + $this->path = $path; } protected function doDisplay(array $context, array $blocks = array()) @@ -26,9 +28,11 @@ class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template public function getDebugInfo() { - return array (19 => 2); + return array(20 => 1, 21 => 2); + } + + public function getSourceContext() + { + return new Twig\Source(" foo bar\n twig source\n\n", 'foo.twig', $this->path ?: __FILE__); } } -/* foo bar*/ -/* twig source*/ -/* */ diff --git a/htdocs/includes/symfony/var-dumper/Tests/Fixtures/xml_reader.xml b/htdocs/includes/symfony/var-dumper/Tests/Fixtures/xml_reader.xml new file mode 100644 index 00000000000..740c399fc44 --- /dev/null +++ b/htdocs/includes/symfony/var-dumper/Tests/Fixtures/xml_reader.xml @@ -0,0 +1,10 @@ + + + + + With text + + + + + diff --git a/htdocs/includes/symfony/var-dumper/Tests/HtmlDumperTest.php b/htdocs/includes/symfony/var-dumper/Tests/HtmlDumperTest.php index 3090435c5d4..24b4bf6d283 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/HtmlDumperTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/HtmlDumperTest.php @@ -11,13 +11,14 @@ namespace Symfony\Component\VarDumper\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; /** * @author Nicolas Grekas */ -class HtmlDumperTest extends \PHPUnit_Framework_TestCase +class HtmlDumperTest extends TestCase { public function testGet() { @@ -59,26 +60,24 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase 4 => INF 5 => -INF 6 => {$intMax} - "str" => "d&%s;j&%s;\\n" - 7 => b"&%s;\\x00" + "str" => "d&%s;j&%s;\\n" + 7 => b"&%s;\\x00" "[]" => [] "res" => stream resource @{$res} - wrapper_type: "plainfile" +%A wrapper_type: "plainfile" stream_type: "STDIO" mode: "r" unread_bytes: 0 seekable: true - timed_out: false - blocked: true - eof: false - options: [] +%A options: [] } "obj" => DumbFoo {#%d +foo: "foo" +"bar": "bar" } "closure" => Closure {{$r} - class: "Symfony\Component\VarDumper\Tests\HtmlDumperTest" + class: "Symfony\Component\VarDumper\Tests\HtmlDumperTest" this: HtmlDumperTest {{$r} &%s;} parameters: { \$a: {} @@ -87,7 +86,8 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase default: null } } - file: "{$var['file']}" + file: "%sTests%eFixtures%edumb-var.php" line: "{$var['line']} to {$var['line']}" } "line" => {$var['line']} @@ -123,19 +123,41 @@ EOTXT $cloner = new VarCloner(); $data = $cloner->cloneVar($var); - $out = fopen('php://memory', 'r+b'); - $dumper->dump($data, $out); - rewind($out); - $out = stream_get_contents($out); + $out = $dumper->dump($data, true); $this->assertStringMatchesFormat( - <<b"Словарь" EOTXT , + $out + ); + } + public function testAppend() + { + $out = fopen('php://memory', 'r+b'); + + $dumper = new HtmlDumper(); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $cloner = new VarCloner(); + + $dumper->dump($cloner->cloneVar(123), $out); + $dumper->dump($cloner->cloneVar(456), $out); + + $out = stream_get_contents($out, -1, 0); + + $this->assertSame(<<<'EOTXT' +123 + +456 + + +EOTXT + , $out ); } diff --git a/htdocs/includes/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php b/htdocs/includes/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php index 3295797179c..464d67f6cec 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php @@ -11,9 +11,10 @@ namespace Symfony\Component\VarDumper\Tests\Test; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; -class VarDumperTestTraitTest extends \PHPUnit_Framework_TestCase +class VarDumperTestTraitTest extends TestCase { use VarDumperTestTrait; diff --git a/htdocs/includes/symfony/var-dumper/Tests/VarClonerTest.php b/htdocs/includes/symfony/var-dumper/Tests/VarClonerTest.php index 31e3a40ae04..2181905e4a3 100644 --- a/htdocs/includes/symfony/var-dumper/Tests/VarClonerTest.php +++ b/htdocs/includes/symfony/var-dumper/Tests/VarClonerTest.php @@ -11,12 +11,13 @@ namespace Symfony\Component\VarDumper\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; /** * @author Nicolas Grekas */ -class VarClonerTest extends \PHPUnit_Framework_TestCase +class VarClonerTest extends TestCase { public function testMaxIntBoundary() { @@ -41,6 +42,10 @@ Symfony\Component\VarDumper\Cloner\Data Object [handle] => 0 [refCount] => 0 [position] => 1 + [attr] => Array + ( + ) + ) ) @@ -52,6 +57,8 @@ Symfony\Component\VarDumper\Cloner\Data Object ) + [position:Symfony\Component\VarDumper\Cloner\Data:private] => 0 + [key:Symfony\Component\VarDumper\Cloner\Data:private] => 0 [maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20 [maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1 [useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1 @@ -84,6 +91,10 @@ Symfony\Component\VarDumper\Cloner\Data Object [handle] => %i [refCount] => 0 [position] => 1 + [attr] => Array + ( + ) + ) ) @@ -99,6 +110,10 @@ Symfony\Component\VarDumper\Cloner\Data Object [handle] => %i [refCount] => 0 [position] => 2 + [attr] => Array + ( + ) + ) [\000+\0002] => Symfony\Component\VarDumper\Cloner\Stub Object @@ -110,6 +125,10 @@ Symfony\Component\VarDumper\Cloner\Data Object [handle] => %i [refCount] => 0 [position] => 3 + [attr] => Array + ( + ) + ) ) @@ -126,6 +145,8 @@ Symfony\Component\VarDumper\Cloner\Data Object ) + [position:Symfony\Component\VarDumper\Cloner\Data:private] => 0 + [key:Symfony\Component\VarDumper\Cloner\Data:private] => 0 [maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20 [maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1 [useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1 @@ -135,6 +156,86 @@ EOTXT; $this->assertStringMatchesFormat($expected, print_r($clone, true)); } + public function testJsonCast() + { + if (ini_get('xdebug.overload_var_dump') == 2) { + $this->markTestSkipped('xdebug is active'); + } + + $data = (array) json_decode('{"1":{}}'); + + $cloner = new VarCloner(); + $clone = $cloner->cloneVar($data); + + $expected = <<<'EOTXT' +object(Symfony\Component\VarDumper\Cloner\Data)#%i (6) { + ["data":"Symfony\Component\VarDumper\Cloner\Data":private]=> + array(2) { + [0]=> + array(1) { + [0]=> + object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) { + ["type"]=> + string(5) "array" + ["class"]=> + string(5) "assoc" + ["value"]=> + int(1) + ["cut"]=> + int(0) + ["handle"]=> + int(0) + ["refCount"]=> + int(0) + ["position"]=> + int(1) + ["attr"]=> + array(0) { + } + } + } + [1]=> + array(1) { + ["1"]=> + object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) { + ["type"]=> + string(6) "object" + ["class"]=> + string(8) "stdClass" + ["value"]=> + NULL + ["cut"]=> + int(0) + ["handle"]=> + int(%i) + ["refCount"]=> + int(0) + ["position"]=> + int(0) + ["attr"]=> + array(0) { + } + } + } + } + ["position":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(0) + ["key":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(0) + ["maxDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(20) + ["maxItemsPerDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(-1) + ["useRefHandles":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(-1) +} + +EOTXT; + ob_start(); + var_dump($clone); + $this->assertStringMatchesFormat(\PHP_VERSION_ID >= 70200 ? str_replace('"1"', '1', $expected) : $expected, ob_get_clean()); + } + public function testCaster() { $cloner = new VarCloner(array( @@ -165,6 +266,10 @@ Symfony\Component\VarDumper\Cloner\Data Object [handle] => %i [refCount] => 0 [position] => 1 + [attr] => Array + ( + ) + ) ) @@ -176,6 +281,8 @@ Symfony\Component\VarDumper\Cloner\Data Object ) + [position:Symfony\Component\VarDumper\Cloner\Data:private] => 0 + [key:Symfony\Component\VarDumper\Cloner\Data:private] => 0 [maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20 [maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1 [useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1 diff --git a/htdocs/includes/symfony/var-dumper/composer.json b/htdocs/includes/symfony/var-dumper/composer.json index 05955f69430..44dbdebcce2 100644 --- a/htdocs/includes/symfony/var-dumper/composer.json +++ b/htdocs/includes/symfony/var-dumper/composer.json @@ -20,9 +20,14 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "twig/twig": "~1.20|~2.0" + "ext-iconv": "*", + "twig/twig": "~1.34|~2.4" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" }, "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", "ext-symfony_debug": "" }, "autoload": { @@ -35,7 +40,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } } } diff --git a/htdocs/includes/symfony/var-dumper/phpunit.xml.dist b/htdocs/includes/symfony/var-dumper/phpunit.xml.dist index bb16a3a4ec0..4a25f42db82 100644 --- a/htdocs/includes/symfony/var-dumper/phpunit.xml.dist +++ b/htdocs/includes/symfony/var-dumper/phpunit.xml.dist @@ -5,9 +5,13 @@ backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" + failOnRisky="true" + failOnWarning="true" > + +