diff --git a/UPGRADE-7.3.md b/UPGRADE-7.3.md index 3824b8b24e139..be95a6611bd24 100644 --- a/UPGRADE-7.3.md +++ b/UPGRADE-7.3.md @@ -18,3 +18,9 @@ Serializer ---------- * Deprecate the `CompiledClassMetadataFactory` and `CompiledClassMetadataCacheWarmer` classes + +VarDumper +--------- + + * Deprecate `ResourceCaster::castCurl()`, `ResourceCaster::castGd()` and `ResourceCaster::castOpensslX509()` + * Mark all casters as `@internal` diff --git a/src/Symfony/Component/VarDumper/CHANGELOG.md b/src/Symfony/Component/VarDumper/CHANGELOG.md index e47de40cc219f..bb63a98547184 100644 --- a/src/Symfony/Component/VarDumper/CHANGELOG.md +++ b/src/Symfony/Component/VarDumper/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +7.3 +--- + + * Add casters for `Dba\Connection`, `SQLite3Result`, `OpenSSLAsymmetricKey` and `OpenSSLCertificateSigningRequest` + * Deprecate `ResourceCaster::castCurl()`, `ResourceCaster::castGd()` and `ResourceCaster::castOpensslX509()` + * Mark all casters as `@internal` + 7.2 --- diff --git a/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php b/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php index 4ef58960bba44..f341c688f6ff2 100644 --- a/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php @@ -15,6 +15,8 @@ /** * @author Nicolas Grekas + * + * @internal since Symfony 7.3 */ final class AddressInfoCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php index 68b1a65ff385b..ff56288bdf51d 100644 --- a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php @@ -19,6 +19,8 @@ * @author Grégoire Pineau * * @final + * + * @internal since Symfony 7.3 */ class AmqpCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index cc213ab59197e..c3bc54e3ac00b 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -46,6 +46,8 @@ class Caster * Casts objects to arrays and adds the dynamic property prefix. * * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not + * + * @internal since Symfony 7.3 */ public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, ?string $debugClass = null): array { @@ -162,6 +164,9 @@ public static function filter(array $a, int $filter, array $listedProperties = [ return $a; } + /** + * @internal since Symfony 7.3 + */ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array { if (isset($a['__PHP_Incomplete_Class_Name'])) { diff --git a/src/Symfony/Component/VarDumper/Caster/CurlCaster.php b/src/Symfony/Component/VarDumper/Caster/CurlCaster.php new file mode 100644 index 0000000000000..fe4ec525c4619 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/CurlCaster.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class CurlCaster +{ + public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNested): array + { + foreach (curl_getinfo($h) as $key => $val) { + $a[Caster::PREFIX_VIRTUAL.$key] = $val; + } + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php index fa58ec4c340c9..e16b33d42a385 100644 --- a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class DOMCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/DateCaster.php b/src/Symfony/Component/VarDumper/Caster/DateCaster.php index f6c35f2b5c1d4..453d0cb90e733 100644 --- a/src/Symfony/Component/VarDumper/Caster/DateCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DateCaster.php @@ -19,6 +19,8 @@ * @author Dany Maillard * * @final + * + * @internal since Symfony 7.3 */ class DateCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php b/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php index 74c06a416c27c..b963112fc4b1e 100644 --- a/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php @@ -22,6 +22,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class DoctrineCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index fb67a704f0f14..4473bdc8dfdd9 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -22,6 +22,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ExceptionCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/GdCaster.php b/src/Symfony/Component/VarDumper/Caster/GdCaster.php new file mode 100644 index 0000000000000..db87653e78d93 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/GdCaster.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class GdCaster +{ + public static function castGd(\GdImage $gd, array $a, Stub $stub, bool $isNested): array + { + $a[Caster::PREFIX_VIRTUAL.'size'] = imagesx($gd).'x'.imagesy($gd); + $a[Caster::PREFIX_VIRTUAL.'trueColor'] = imageistruecolor($gd); + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Caster/GmpCaster.php b/src/Symfony/Component/VarDumper/Caster/GmpCaster.php index b018cc7f87f2e..325d2e904bb5a 100644 --- a/src/Symfony/Component/VarDumper/Caster/GmpCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/GmpCaster.php @@ -20,6 +20,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class GmpCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/ImagineCaster.php b/src/Symfony/Component/VarDumper/Caster/ImagineCaster.php index d1289da3370f3..0fb2a9033c236 100644 --- a/src/Symfony/Component/VarDumper/Caster/ImagineCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ImagineCaster.php @@ -16,6 +16,8 @@ /** * @author Grégoire Pineau + * + * @internal since Symfony 7.3 */ final class ImagineCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/IntlCaster.php b/src/Symfony/Component/VarDumper/Caster/IntlCaster.php index f386c7215117b..529c8f76cd0d7 100644 --- a/src/Symfony/Component/VarDumper/Caster/IntlCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/IntlCaster.php @@ -18,6 +18,8 @@ * @author Jan Schädlich * * @final + * + * @internal since Symfony 7.3 */ class IntlCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/MemcachedCaster.php b/src/Symfony/Component/VarDumper/Caster/MemcachedCaster.php index 740785cea6ddb..4e4f611f19e2c 100644 --- a/src/Symfony/Component/VarDumper/Caster/MemcachedCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/MemcachedCaster.php @@ -17,6 +17,8 @@ * @author Jan Schädlich * * @final + * + * @internal since Symfony 7.3 */ class MemcachedCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/OpenSSLCaster.php b/src/Symfony/Component/VarDumper/Caster/OpenSSLCaster.php new file mode 100644 index 0000000000000..4c311ac4ad8e6 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/OpenSSLCaster.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * @author Alexandre Daubois + * + * @internal + */ +final class OpenSSLCaster +{ + public static function castOpensslX509(\OpenSSLCertificate $h, array $a, Stub $stub, bool $isNested): array + { + $stub->cut = -1; + $info = openssl_x509_parse($h, false); + + $pin = openssl_pkey_get_public($h); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + $a += [ + Caster::PREFIX_VIRTUAL.'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), + Caster::PREFIX_VIRTUAL.'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), + Caster::PREFIX_VIRTUAL.'expiry' => new ConstStub(date(\DateTimeInterface::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), + Caster::PREFIX_VIRTUAL.'fingerprint' => new EnumStub([ + 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), + 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), + 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), + 'pin-sha256' => new ConstStub($pin), + ]), + ]; + + return $a; + } + + public static function castOpensslAsymmetricKey(\OpenSSLAsymmetricKey $key, array $a, Stub $stub, bool $isNested): array + { + foreach (openssl_pkey_get_details($key) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + unset($a[Caster::PREFIX_VIRTUAL.'rsa']); // binary data + + return $a; + } + + public static function castOpensslCsr(\OpenSSLCertificateSigningRequest $csr, array $a, Stub $stub, bool $isNested): array + { + foreach (openssl_csr_get_subject($csr, false) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Caster/PdoCaster.php b/src/Symfony/Component/VarDumper/Caster/PdoCaster.php index 1d364cdf01b25..697e4122f9310 100644 --- a/src/Symfony/Component/VarDumper/Caster/PdoCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/PdoCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class PdoCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/PgSqlCaster.php b/src/Symfony/Component/VarDumper/Caster/PgSqlCaster.php index 3e759f69b6798..54a19064e0666 100644 --- a/src/Symfony/Component/VarDumper/Caster/PgSqlCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/PgSqlCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class PgSqlCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/ProxyManagerCaster.php b/src/Symfony/Component/VarDumper/Caster/ProxyManagerCaster.php index 736a6e75854f8..0d954f4883922 100644 --- a/src/Symfony/Component/VarDumper/Caster/ProxyManagerCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ProxyManagerCaster.php @@ -18,6 +18,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ProxyManagerCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/RdKafkaCaster.php b/src/Symfony/Component/VarDumper/Caster/RdKafkaCaster.php index 5445b2d4b16a8..bfadef2f95945 100644 --- a/src/Symfony/Component/VarDumper/Caster/RdKafkaCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/RdKafkaCaster.php @@ -28,6 +28,8 @@ * Casts RdKafka related classes to array representation. * * @author Romain Neutron + * + * @internal since Symfony 7.3 */ class RdKafkaCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/RedisCaster.php b/src/Symfony/Component/VarDumper/Caster/RedisCaster.php index 5224bc05da904..a1ed95de5254f 100644 --- a/src/Symfony/Component/VarDumper/Caster/RedisCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/RedisCaster.php @@ -20,6 +20,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class RedisCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index e7bd9a152a006..e7310f404ef4a 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ReflectionCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php index f775f81ca383d..5613c5534cd5f 100644 --- a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php @@ -19,16 +19,31 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ResourceCaster { + /** + * @deprecated since Symfony 7.3 + */ public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNested): array { - return curl_getinfo($h); + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__, CurlCaster::class); + + return CurlCaster::castCurl($h, $a, $stub, $isNested); } - public static function castDba($dba, array $a, Stub $stub, bool $isNested): array + /** + * @param resource|\Dba\Connection $dba + */ + public static function castDba(mixed $dba, array $a, Stub $stub, bool $isNested): array { + if (\PHP_VERSION_ID < 80402 && !\is_resource($dba)) { + // @see https://github.com/php/php-src/issues/16990 + return $a; + } + $list = dba_list(); $a['file'] = $list[(int) $dba]; @@ -55,37 +70,23 @@ public static function castStreamContext($stream, array $a, Stub $stub, bool $is return @stream_context_get_params($stream) ?: $a; } - public static function castGd($gd, array $a, Stub $stub, bool $isNested): array + /** + * @deprecated since Symfony 7.3 + */ + public static function castGd(\GdImage $gd, array $a, Stub $stub, bool $isNested): array { - $a['size'] = imagesx($gd).'x'.imagesy($gd); - $a['trueColor'] = imageistruecolor($gd); + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__, GdCaster::class); - return $a; + return GdCaster::castGd($gd, $a, $stub, $isNested); } - public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested): array + /** + * @deprecated since Symfony 7.3 + */ + public static function castOpensslX509(\OpenSSLCertificate $h, array $a, Stub $stub, bool $isNested): array { - $stub->cut = -1; - $info = openssl_x509_parse($h, false); - - $pin = openssl_pkey_get_public($h); - $pin = openssl_pkey_get_details($pin)['key']; - $pin = \array_slice(explode("\n", $pin), 1, -2); - $pin = base64_decode(implode('', $pin)); - $pin = base64_encode(hash('sha256', $pin, true)); - - $a += [ - 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), - 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), - 'expiry' => new ConstStub(date(\DateTimeInterface::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), - 'fingerprint' => new EnumStub([ - 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), - 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), - 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), - 'pin-sha256' => new ConstStub($pin), - ]), - ]; + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__, OpenSSLCaster::class); - return $a; + return OpenSSLCaster::castOpensslX509($h, $a, $stub, $isNested); } } diff --git a/src/Symfony/Component/VarDumper/Caster/SocketCaster.php b/src/Symfony/Component/VarDumper/Caster/SocketCaster.php index 98af209e5623e..6b95cd10ed0e1 100644 --- a/src/Symfony/Component/VarDumper/Caster/SocketCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SocketCaster.php @@ -15,16 +15,38 @@ /** * @author Nicolas Grekas + * @author Alexandre Daubois + * + * @internal */ final class SocketCaster { - public static function castSocket(\Socket $h, array $a, Stub $stub, bool $isNested): array + public static function castSocket(\Socket $socket, array $a, Stub $stub, bool $isNested): array { - if (\PHP_VERSION_ID >= 80300 && socket_atmark($h)) { - $a[Caster::PREFIX_VIRTUAL.'atmark'] = true; + socket_getsockname($socket, $addr, $port); + $info = stream_get_meta_data(socket_export_stream($socket)); + + if (\PHP_VERSION_ID >= 80300) { + $uri = ($info['uri'] ?? '//'); + if (str_starts_with($uri, 'unix://')) { + $uri .= $addr; + } else { + $uri .= \sprintf(str_contains($addr, ':') ? '[%s]:%s' : '%s:%s', $addr, $port); + } + + $a[Caster::PREFIX_VIRTUAL.'uri'] = $uri; + + if (@socket_atmark($socket)) { + $a[Caster::PREFIX_VIRTUAL.'atmark'] = true; + } } - if (!$lastError = socket_last_error($h)) { + $a += [ + Caster::PREFIX_VIRTUAL.'timed_out' => $info['timed_out'], + Caster::PREFIX_VIRTUAL.'blocked' => $info['blocked'], + ]; + + if (!$lastError = socket_last_error($socket)) { return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/SplCaster.php b/src/Symfony/Component/VarDumper/Caster/SplCaster.php index bd2bcc048630f..31f4b11cc5b7d 100644 --- a/src/Symfony/Component/VarDumper/Caster/SplCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SplCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class SplCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/SqliteCaster.php b/src/Symfony/Component/VarDumper/Caster/SqliteCaster.php new file mode 100644 index 0000000000000..25d47ac481928 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/SqliteCaster.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Alexandre Daubois + * + * @internal + */ +final class SqliteCaster +{ + public static function castSqlite3Result(\SQLite3Result $result, array $a, Stub $stub, bool $isNested): array + { + $numColumns = $result->numColumns(); + for ($i = 0; $i < $numColumns; ++$i) { + $a[Caster::PREFIX_VIRTUAL.'columnNames'][$i] = $result->columnName($i); + } + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Caster/StubCaster.php b/src/Symfony/Component/VarDumper/Caster/StubCaster.php index 56742b018dd33..85cf99731345c 100644 --- a/src/Symfony/Component/VarDumper/Caster/StubCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/StubCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class StubCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php index d8422e0558048..42dc901a5f293 100644 --- a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php @@ -19,6 +19,8 @@ /** * @final + * + * @internal since Symfony 7.3 */ class SymfonyCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/UuidCaster.php b/src/Symfony/Component/VarDumper/Caster/UuidCaster.php index b102774571f34..732ad7ccf232e 100644 --- a/src/Symfony/Component/VarDumper/Caster/UuidCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/UuidCaster.php @@ -16,6 +16,8 @@ /** * @author Grégoire Pineau + * + * @internal since Symfony 7.3 */ final class UuidCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php index 672fec68fd4e8..00420c79ff3fa 100644 --- a/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php @@ -19,6 +19,8 @@ * @author Baptiste Clavié * * @final + * + * @internal since Symfony 7.3 */ class XmlReaderCaster { diff --git a/src/Symfony/Component/VarDumper/Caster/XmlResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/XmlResourceCaster.php index fd3d3a2abe40f..f6b08965b0816 100644 --- a/src/Symfony/Component/VarDumper/Caster/XmlResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/XmlResourceCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class XmlResourceCaster { diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 1fe4bd2939b0c..9038d2c04e8a5 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -177,29 +177,33 @@ abstract class AbstractCloner implements ClonerInterface 'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'], - 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\CurlCaster', 'castCurl'], + 'Dba\Connection' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], 'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], - ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], - ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], - ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], - ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], - ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], + 'SQLite3Result' => ['Symfony\Component\VarDumper\Caster\SqliteCaster', 'castSqlite3Result'], + + 'PgSql\Lob' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], + 'PgSql\Connection' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + 'PgSql\Result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], + ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], - 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], - ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + 'OpenSSLAsymmetricKey' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslAsymmetricKey'], + 'OpenSSLCertificateSigningRequest' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslCsr'], + 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslX509'], ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], 'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], - ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + + 'Socket' => ['Symfony\Component\VarDumper\Caster\SocketCaster', 'castSocket'], 'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'], 'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'], diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/CurlCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/CurlCasterTest.php new file mode 100644 index 0000000000000..40d4e64e4a0a8 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/CurlCasterTest.php @@ -0,0 +1,39 @@ + + * + * 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; + +/** + * @requires extension curl + */ +class CurlCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testCastCurl() + { + $ch = curl_init('http://example.com'); + curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true); + curl_exec($ch); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +CurlHandle { + url: "http://example.com/" + content_type: "text/html; charset=UTF-8" + http_code: 200%A +} +EODUMP, $ch); + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/OpenSSLCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/OpenSSLCasterTest.php new file mode 100644 index 0000000000000..188228b8fbf7e --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/OpenSSLCasterTest.php @@ -0,0 +1,83 @@ + + * + * 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; + +/** + * @requires extension openssl + */ +class OpenSSLCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testAsymmetricKey() + { + $key = openssl_pkey_new([ + 'private_key_bits' => 1024, + 'private_key_type' => \OPENSSL_KEYTYPE_RSA, + ]); + + if (false === $key) { + $this->markTestSkipped('Unable to generate a key pair'); + } + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +OpenSSLAsymmetricKey { + bits: 1024 + key: """ + -----BEGIN PUBLIC KEY-----\n + %A + %A + %A + %A + -----END PUBLIC KEY-----\n + """ + type: 0 +} +EODUMP, $key); + } + + public function testOpensslCsr() + { + $dn = [ + 'countryName' => 'FR', + 'stateOrProvinceName' => 'Ile-de-France', + 'localityName' => 'Paris', + 'organizationName' => 'Symfony', + 'organizationalUnitName' => 'Security', + 'commonName' => 'symfony.com', + 'emailAddress' => 'test@symfony.com', + ]; + $privkey = openssl_pkey_new(); + $csr = openssl_csr_new($dn, $privkey); + + if (false === $csr) { + $this->markTestSkipped('Unable to generate a CSR'); + } + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +OpenSSLCertificateSigningRequest { + countryName: "FR" + stateOrProvinceName: "Ile-de-France" + localityName: "Paris" + organizationName: "Symfony" + organizationalUnitName: "Security" + commonName: "symfony.com" + emailAddress: "test@symfony.com" +} +EODUMP, $csr); + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ResourceCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ResourceCasterTest.php new file mode 100644 index 0000000000000..a438f7fa4ad98 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ResourceCasterTest.php @@ -0,0 +1,107 @@ + + * + * 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\Bridge\PhpUnit\ExpectDeprecationTrait; +use Symfony\Component\VarDumper\Caster\ResourceCaster; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +class ResourceCasterTest extends TestCase +{ + use ExpectDeprecationTrait; + use VarDumperTestTrait; + + /** + * @group legacy + * + * @requires extension curl + */ + public function testCastCurlIsDeprecated() + { + $ch = curl_init('http://example.com'); + curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true); + curl_exec($ch); + + $this->expectDeprecation('Since symfony/var-dumper 7.3: The "Symfony\Component\VarDumper\Caster\ResourceCaster::castCurl()" method is deprecated without replacement.'); + + ResourceCaster::castCurl($ch, [], new Stub(), false); + } + + /** + * @group legacy + * + * @requires extension gd + */ + public function testCastGdIsDeprecated() + { + $gd = imagecreate(1, 1); + + $this->expectDeprecation('Since symfony/var-dumper 7.3: The "Symfony\Component\VarDumper\Caster\ResourceCaster::castGd()" method is deprecated without replacement.'); + + ResourceCaster::castGd($gd, [], new Stub(), false); + } + + /** + * @requires PHP < 8.4 + * @requires extension dba + */ + public function testCastDbaPriorToPhp84() + { + $dba = dba_open(sys_get_temp_dir().'/test.db', 'c'); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +dba resource { + file: %s +} +EODUMP, $dba); + } + + /** + * @requires PHP 8.4 + */ + public function testCastDba() + { + if (\PHP_VERSION_ID < 80402) { + $this->markTestSkipped('The test cannot be run on PHP 8.4.0 and PHP 8.4.1, see https://github.com/php/php-src/issues/16990'); + } + + $dba = dba_open(sys_get_temp_dir().'/test.db', 'c'); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Dba\Connection { + +file: %s +} +EODUMP, $dba); + } + + /** + * @requires PHP 8.4 + */ + public function testCastDbaOnBuggyPhp84() + { + if (\PHP_VERSION_ID >= 80402) { + $this->markTestSkipped('The test can only be run on PHP 8.4.0 and 8.4.1, see https://github.com/php/php-src/issues/16990'); + } + + $dba = dba_open(sys_get_temp_dir().'/test.db', 'c'); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Dba\Connection { +} +EODUMP, $dba); + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/SocketCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/SocketCasterTest.php new file mode 100644 index 0000000000000..741a9ddd5f92e --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/SocketCasterTest.php @@ -0,0 +1,132 @@ + + * + * 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; + +/** + * @requires extension sockets + */ +class SocketCasterTest extends TestCase +{ + use VarDumperTestTrait; + + /** + * @requires PHP 8.3 + */ + public function testCastSocket() + { + $socket = socket_create(\AF_INET, \SOCK_DGRAM, \SOL_UDP); + @socket_connect($socket, '127.0.0.1', 80); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + uri: "udp://127.0.0.1:%d" + timed_out: false + blocked: true%A +} +EODUMP, $socket); + } + + /** + * @requires PHP < 8.3 + */ + public function testCastSocketPriorToPhp83() + { + $socket = socket_create(\AF_INET, \SOCK_DGRAM, \SOL_UDP); + @socket_connect($socket, '127.0.0.1', 80); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + timed_out: false + blocked: true +} +EODUMP, $socket); + } + + /** + * @requires PHP 8.3 + */ + public function testCastSocketIpV6() + { + $socket = socket_create(\AF_INET6, \SOCK_STREAM, \SOL_TCP); + @socket_connect($socket, '::1', 80); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + uri: "tcp://[%A]:%d" + timed_out: false + blocked: true + last_error: SOCKET_ECONNREFUSED +} +EODUMP, $socket); + } + + /** + * @requires PHP < 8.3 + */ + public function testCastSocketIpV6PriorToPhp83() + { + $socket = socket_create(\AF_INET6, \SOCK_STREAM, \SOL_TCP); + @socket_connect($socket, '::1', 80); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + timed_out: false + blocked: true + last_error: SOCKET_ECONNREFUSED +} +EODUMP, $socket); + } + + /** + * @requires PHP 8.3 + */ + public function testCastUnixSocket() + { + $socket = socket_create(\AF_UNIX, \SOCK_STREAM, 0); + @socket_connect($socket, '/tmp/socket.sock'); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + uri: "unix://" + timed_out: false + blocked: true + last_error: SOCKET_ENOENT +} +EODUMP, $socket); + } + + /** + * @requires PHP < 8.3 + */ + public function testCastUnixSocketPriorToPhp83() + { + $socket = socket_create(\AF_UNIX, \SOCK_STREAM, 0); + @socket_connect($socket, '/tmp/socket.sock'); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +Socket { + timed_out: false + blocked: true + last_error: SOCKET_ENOENT +} +EODUMP, $socket); + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/SqliteCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/SqliteCasterTest.php new file mode 100644 index 0000000000000..d616d2f0655be --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/SqliteCasterTest.php @@ -0,0 +1,42 @@ + + * + * 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; + +/** + * @requires extension sqlite3 + */ +class SqliteCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testSqlite3Result() + { + $db = new \SQLite3(':memory:'); + $db->exec('CREATE TABLE foo (id INTEGER PRIMARY KEY, bar TEXT)'); + $db->exec('INSERT INTO foo (bar) VALUES ("baz")'); + $stmt = $db->prepare('SELECT id, bar FROM foo'); + $result = $stmt->execute(); + + $this->assertDumpMatchesFormat( + <<<'EODUMP' +SQLite3Result { + columnNames: array:2 [ + 0 => "id" + 1 => "bar" + ] +} +EODUMP, $result); + } +} diff --git a/src/Symfony/Component/VarDumper/composer.json b/src/Symfony/Component/VarDumper/composer.json index eaba033e14885..ed312c5288b88 100644 --- a/src/Symfony/Component/VarDumper/composer.json +++ b/src/Symfony/Component/VarDumper/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": {