diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php index 8882509d..4b6f111a 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php @@ -3,6 +3,7 @@ namespace App\Handlers; use App\Services\CartService; +use App\Support\Utf8Cleaner; use Cart\Cart; use Symfony\Component\HttpFoundation\JsonResponse; use Openguru\OpenCartFramework\Http\Request; @@ -23,7 +24,7 @@ class CartHandler $items = $this->cartService->getCart(); return new JsonResponse([ - 'data' => $items, + 'data' => Utf8Cleaner::clean($items), ]); } @@ -48,7 +49,7 @@ class CartHandler } return new JsonResponse([ - 'data' => $items, + 'data' => Utf8Cleaner::clean($items), ]); } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/OrderHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/OrderHandler.php index f09214dc..6bf2a0d1 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/OrderHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/OrderHandler.php @@ -4,6 +4,7 @@ namespace App\Handlers; use App\Exceptions\OrderValidationFailedException; use App\Services\OrderCreateService; +use App\Support\Utf8Cleaner; use Symfony\Component\HttpFoundation\JsonResponse; use Openguru\OpenCartFramework\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -26,11 +27,11 @@ class OrderHandler ]); return new JsonResponse([ - 'data' => $order, + 'data' => Utf8Cleaner::clean($order), ], Response::HTTP_CREATED); } catch (OrderValidationFailedException $exception) { return new JsonResponse([ - 'data' => $exception->getErrorBag()->firstOfAll(), + 'data' => Utf8Cleaner::clean($exception->getErrorBag()->firstOfAll()), ], Response::HTTP_UNPROCESSABLE_ENTITY); } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Support/Utf8Cleaner.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Support/Utf8Cleaner.php new file mode 100644 index 00000000..70551354 --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Support/Utf8Cleaner.php @@ -0,0 +1,49 @@ + $item) { + $value[$key] = self::clean($item); + } + + return $value; + } + + if (is_object($value)) { + foreach (get_object_vars($value) as $property => $item) { + $value->{$property} = self::clean($item); + } + + return $value; + } + + if (is_string($value)) { + // Попробовать нормализовать строку в UTF-8, подменяя невалидные последовательности. + $converted = @mb_convert_encoding($value, 'UTF-8', 'UTF-8'); + + if ($converted === false) { + // Фолбэк: заменить невалидные байты стандартным алгоритмом json_encode. + $encoded = json_encode($value, JSON_INVALID_UTF8_SUBSTITUTE); + + if ($encoded === false) { + return ''; + } + + // Убираем кавычки, которые добавляет json_encode. + return json_decode($encoded, true) ?? ''; + } + + return $converted; + } + + return $value; + } +} diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/tests/Unit/Support/Utf8CleanerTest.php b/module/oc_telegram_shop/upload/oc_telegram_shop/tests/Unit/Support/Utf8CleanerTest.php new file mode 100644 index 00000000..e1a3357f --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/tests/Unit/Support/Utf8CleanerTest.php @@ -0,0 +1,90 @@ +assertSame(123, Utf8Cleaner::clean(123)); + $this->assertSame(12.3, Utf8Cleaner::clean(12.3)); + $this->assertSame(true, Utf8Cleaner::clean(true)); + $this->assertSame(false, Utf8Cleaner::clean(false)); + $this->assertNull(Utf8Cleaner::clean(null)); + } + + /** @test */ + public function leaves_valid_utf8_strings_unchanged(): void + { + $value = 'Привет, мир! 😀'; + + $this->assertSame($value, Utf8Cleaner::clean($value)); + } + + /** @test */ + public function cleans_strings_with_invalid_utf8_bytes(): void + { + // Строка с заведомо некорректной UTF-8 последовательностью. + $invalid = "\xF0\x28\x8C\x28"; + + $cleaned = Utf8Cleaner::clean($invalid); + + $this->assertIsString($cleaned); + $this->assertNotSame($invalid, $cleaned); + + $json = json_encode($cleaned); + $this->assertNotFalse($json, 'Resulting string must be valid UTF-8 for json_encode'); + } + + /** @test */ + public function cleans_nested_arrays_recursively(): void + { + $invalid = "\xF0\x28\x8C\x28"; + + $data = [ + 'foo' => 'bar', + 'nested' => [ + 'value' => $invalid, + ], + ]; + + $cleaned = Utf8Cleaner::clean($data); + + $this->assertIsArray($cleaned); + $this->assertSame('bar', $cleaned['foo']); + $this->assertIsString($cleaned['nested']['value']); + $this->assertNotSame($invalid, $cleaned['nested']['value']); + + $json = json_encode($cleaned); + $this->assertNotFalse($json); + } + + /** @test */ + public function cleans_objects_recursively(): void + { + $invalid = "\xF0\x28\x8C\x28"; + + $object = new class { + public string $name = 'test'; + public array $meta = []; + }; + + $object->meta['invalid'] = $invalid; + + $cleaned = Utf8Cleaner::clean($object); + + $this->assertSame('test', $cleaned->name); + $this->assertIsString($cleaned->meta['invalid']); + $this->assertNotSame($invalid, $cleaned->meta['invalid']); + + $json = json_encode($cleaned); + $this->assertNotFalse($json); + } +} +