1<?php 2 3declare(strict_types = 1); 4 5namespace Elasticsearch\Serializers; 6 7use Elasticsearch\Common\Exceptions; 8use Elasticsearch\Common\Exceptions\Serializer\JsonErrorException; 9 10if (!defined('JSON_INVALID_UTF8_SUBSTITUTE')) { 11 //PHP < 7.2 Define it as 0 so it does nothing 12 define('JSON_INVALID_UTF8_SUBSTITUTE', 0); 13} 14 15/** 16 * Class SmartSerializer 17 * 18 * @category Elasticsearch 19 * @package Elasticsearch\Serializers\JSONSerializer 20 * @author Zachary Tong <zach@elastic.co> 21 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache2 22 * @link http://elastic.co 23 */ 24class SmartSerializer implements SerializerInterface 25{ 26 /** 27 * {@inheritdoc} 28 */ 29 public function serialize($data): string 30 { 31 if (is_string($data) === true) { 32 return $data; 33 } else { 34 $data = json_encode($data, JSON_PRESERVE_ZERO_FRACTION + JSON_INVALID_UTF8_SUBSTITUTE); 35 if ($data === false) { 36 throw new Exceptions\RuntimeException("Failed to JSON encode: ".json_last_error()); 37 } 38 if ($data === '[]') { 39 return '{}'; 40 } else { 41 return $data; 42 } 43 } 44 } 45 46 /** 47 * {@inheritdoc} 48 */ 49 public function deserialize(?string $data, array $headers) 50 { 51 if (isset($headers['content_type']) === true) { 52 if (strpos($headers['content_type'], 'json') !== false) { 53 return $this->decode($data); 54 } else { 55 //Not json, return as string 56 return $data; 57 } 58 } else { 59 //No content headers, assume json 60 return $this->decode($data); 61 } 62 } 63 64 /** 65 * @todo For 2.0, remove the E_NOTICE check before raising the exception. 66 * 67 * @param string|null $data 68 * 69 * @return array 70 * @throws JsonErrorException 71 */ 72 private function decode(?string $data): array 73 { 74 if ($data === null || strlen($data) === 0) { 75 return []; 76 } 77 78 if (version_compare(PHP_VERSION, '7.3.0') >= 0) { 79 try { 80 $result = json_decode($data, true, 512, JSON_THROW_ON_ERROR); 81 return $result; 82 } catch (\JsonException $e) { 83 $result = $result ?? []; 84 throw new JsonErrorException($e->getMessage(), $data, $result); 85 } 86 } 87 88 $result = @json_decode($data, true); 89 // Throw exception only if E_NOTICE is on to maintain backwards-compatibility on systems that silently ignore E_NOTICEs. 90 if (json_last_error() !== JSON_ERROR_NONE && (error_reporting() & E_NOTICE) === E_NOTICE) { 91 throw new JsonErrorException(json_last_error(), $data, $result); 92 } 93 return $result; 94 } 95} 96