fix: preserve invalid metadata payloads

This commit is contained in:
Keith Solomon
2026-04-26 14:55:07 -05:00
parent 3b09c3f410
commit 4cfc1036bb
2 changed files with 88 additions and 14 deletions
+43 -14
View File
@@ -25,12 +25,19 @@ final class MetadataUrlTransformer {
return $value;
}
if ( $this->isSerialized( $value ) ) {
// phpcs:ignore -- Required to transform serialized metadata while preserving valid string lengths.
$unserialized = unserialize( $value, array( 'allowed_classes' => false ) );
if ( $this->looksSerialized( trim( $value ) ) && trim( $value ) !== $value ) {
return $value;
}
if ( $this->looksSerialized( $value ) ) {
$unserialized = $this->unserializeValue( $value );
if ( ! $unserialized['valid'] || is_object( $unserialized['value'] ) ) {
return $value;
}
// phpcs:ignore -- Required to reserialize metadata with updated string lengths.
return serialize( $this->transformValue( $unserialized, $mappings ) );
return serialize( $this->transformValue( $unserialized['value'], $mappings ) );
}
if ( $this->isJsonObjectOrArray( $value ) ) {
@@ -43,6 +50,8 @@ final class MetadataUrlTransformer {
return $encoded;
}
}
return $value;
}
return $this->url_transformer->transformString( $value, $mappings );
@@ -65,23 +74,43 @@ final class MetadataUrlTransformer {
return $transformed;
}
private function isSerialized( string $value ): bool {
$trimmed = trim( $value );
private function looksSerialized( string $value ): bool {
return 'N;' === $value || 'b:0;' === $value || 1 === preg_match( '/^(?:a|O|s|i|d|b):/', $value );
}
if ( 'N;' === $trimmed ) {
return true;
/**
* @return array{valid: bool, value: mixed}
*/
private function unserializeValue( string $value ): array {
if ( 'N;' === $value ) {
return array(
'valid' => true,
'value' => null,
);
}
if ( 'b:0;' === $trimmed ) {
return true;
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize -- Metadata may be stored in PHP serialized format.
$unserialized = @unserialize( $value, array( 'allowed_classes' => false ) );
if ( false === $unserialized && 'b:0;' !== $value ) {
return array(
'valid' => false,
'value' => null,
);
}
if ( ! preg_match( '/^(?:a|O|s|i|d|b):/', $trimmed ) ) {
return false;
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- Strict validation avoids transforming malformed serialized-looking strings.
if ( serialize( $unserialized ) !== $value ) {
return array(
'valid' => false,
'value' => null,
);
}
// phpcs:ignore -- Validation must parse PHP serialized metadata.
return false !== @unserialize( $trimmed, array( 'allowed_classes' => false ) );
return array(
'valid' => true,
'value' => $unserialized,
);
}
private function isJsonObjectOrArray( string $value ): bool {