From 96c6bbf836ac37c58100a54212f1f0d6aff088ad Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 16:51:41 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Implement?= =?UTF-8?q?=20requested=20code=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inc/duplication/data.php | 4 +-- .../WP_Ultimo/Duplication/MUCD_Data_Test.php | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/inc/duplication/data.php b/inc/duplication/data.php index fc3c3997..f55af382 100644 --- a/inc/duplication/data.php +++ b/inc/duplication/data.php @@ -450,7 +450,7 @@ public static function try_replace($row, $field, $from_string, $to_string) { if (is_serialized($row[ $field ])) { $double_serialize = false; $original_value = $row[ $field ]; - $row[ $field ] = @unserialize($row[ $field ]); + $row[ $field ] = @unserialize($row[ $field ], ['allowed_classes' => false]); // Safety: if unserialize failed, return the original value // instead of re-serializing false — which would destroy the data. @@ -460,7 +460,7 @@ public static function try_replace($row, $field, $from_string, $to_string) { // FOR SERIALISED OPTIONS, like in wp_carousel plugin if (is_serialized($row[ $field ])) { - $inner_unserialized = @unserialize($row[ $field ]); + $inner_unserialized = @unserialize($row[ $field ], ['allowed_classes' => false]); if (false === $inner_unserialized && 'b:0;' !== $row[ $field ]) { // Inner unserialize failed — fall back to single-serialized handling. diff --git a/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php b/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php index 1bb61afa..5b51f18e 100644 --- a/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php +++ b/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php @@ -327,10 +327,33 @@ public function test_try_replace_preserves_incomplete_serialized_object() { $this->assertStringContainsString($old_url, $result); } + /** + * Test try_replace does not instantiate objects from known classes. + * + * Both unserialize() calls must use allowed_classes: false so that + * __wakeup() / __destruct() side-effects are never triggered, even for + * classes that happen to be available in the duplication runtime. Any + * serialized object must be returned verbatim (same as an incomplete class). + */ + public function test_try_replace_does_not_instantiate_known_class_objects() { + // stdClass is always available; without allowed_classes: false it would + // be instantiated and processed by the object-mutation branch. + $obj = new \stdClass(); + $obj->url = 'https://example.com/old/page'; + $serialized = serialize($obj); + $row = ['meta_value' => $serialized]; + + $result = \MUCD_Data::try_replace($row, 'meta_value', 'example.com/old', 'example.com/new'); + + // With allowed_classes: false the object becomes __PHP_Incomplete_Class + // and the guard returns the original serialized value unchanged. + $this->assertSame($serialized, $result); + } + /** * Test try_replace with Elementor Kit-like serialized page settings. * - * Simulates the _elementor_page_settings structure for a Kit post. + * After URL replacement, all non-URL settings must be preserved * exactly and the result must be valid serialized data. */