1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Core\Http; 17 18/** 19 * Standard values for a JSON response 20 * 21 * Highly inspired by ZF zend-diactoros 22 * 23 * @internal Note that this is not public API yet. 24 */ 25class JsonResponse extends Response 26{ 27 /** 28 * Default flags for json_encode; value of: 29 * 30 * <code> 31 * JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES 32 * </code> 33 * 34 * @var int 35 */ 36 const DEFAULT_JSON_FLAGS = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES; 37 38 /** 39 * Create a JSON response with the given data. 40 * 41 * Default JSON encoding is performed with the following options, which 42 * produces RFC4627-compliant JSON, capable of embedding into HTML. 43 * 44 * - JSON_HEX_TAG 45 * - JSON_HEX_APOS 46 * - JSON_HEX_AMP 47 * - JSON_HEX_QUOT 48 * - JSON_UNESCAPED_SLASHES 49 * 50 * @param mixed $data Data to convert to JSON. 51 * @param int $status Integer status code for the response; 200 by default. 52 * @param array $headers Array of headers to use at initialization. 53 * @param int $encodingOptions JSON encoding options to use. 54 */ 55 public function __construct( 56 $data = [], 57 $status = 200, 58 array $headers = [], 59 $encodingOptions = self::DEFAULT_JSON_FLAGS 60 ) { 61 $body = new Stream('php://temp', 'wb+'); 62 parent::__construct($body, $status, $headers); 63 64 if (!empty($data)) { 65 $this->setPayload($data, $encodingOptions); 66 } 67 68 // Ensure that application/json header is set, if Content-Type was not set before 69 if (!$this->hasHeader('Content-Type')) { 70 $this->headers['Content-Type'][] = 'application/json; charset=utf-8'; 71 $this->lowercasedHeaderNames['content-type'] = 'Content-Type'; 72 } 73 } 74 75 /** 76 * Overrides the exiting content, takes an array as input 77 * 78 * @param array $data 79 * @param int $encodingOptions 80 * @return $this 81 */ 82 public function setPayload(array $data = [], $encodingOptions = self::DEFAULT_JSON_FLAGS): JsonResponse 83 { 84 $this->body->write($this->jsonEncode($data, $encodingOptions)); 85 $this->body->rewind(); 86 return $this; 87 } 88 89 /** 90 * Encode the provided data to JSON. 91 * 92 * @param mixed $data 93 * @param int $encodingOptions 94 * @return string 95 * @throws \InvalidArgumentException if unable to encode the $data to JSON. 96 */ 97 private function jsonEncode($data, $encodingOptions) 98 { 99 if (is_resource($data)) { 100 throw new \InvalidArgumentException('Cannot JSON encode resources', 1504972433); 101 } 102 // Clear json_last_error() 103 json_encode(null); 104 $json = json_encode($data, $encodingOptions); 105 if (JSON_ERROR_NONE !== json_last_error()) { 106 throw new \InvalidArgumentException(sprintf( 107 'Unable to encode data to JSON in %s: %s', 108 __CLASS__, 109 json_last_error_msg() 110 ), 1504972434); 111 } 112 return $json; 113 } 114} 115