[TASK] Re-work/simplify copyright header in PHP files - Part 3
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Http / AjaxRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Core\Http;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 /**
17 * Class to hold all the information about an AJAX call and send
18 * the right headers for the request type
19 *
20 * @author Benjamin Mack <mack@xnos.org>
21 */
22 class AjaxRequestHandler {
23
24 protected $ajaxId = NULL;
25
26 protected $errorMessage = NULL;
27
28 protected $isError = FALSE;
29
30 protected $content = array();
31
32 protected $contentFormat = 'plain';
33
34 protected $charset = 'utf-8';
35
36 protected $requestCharset = 'utf-8';
37
38 protected $javascriptCallbackWrap = '
39 <script type="text/javascript">
40 /*<![CDATA[*/
41 response = |;
42 /*]]>*/
43 </script>
44 ';
45
46 /**
47 * Sets the charset and the ID for the AJAX call
48 * due to some charset limitations in Javascript (prototype uses encodeURIcomponent, which converts
49 * all data to utf-8), we need to detect if the encoding of the request differs from the
50 * backend encoding, and then convert all incoming data (_GET and _POST)
51 * in the expected backend encoding.
52 *
53 * @param string $ajaxId The AJAX id
54 */
55 public function __construct($ajaxId) {
56 // Get charset from current AJAX request (which is expected to be utf-8)
57 preg_match('/;\\s*charset\\s*=\\s*([a-zA-Z0-9_-]*)/i', $_SERVER['CONTENT_TYPE'], $contenttype);
58 $charset = $GLOBALS['LANG']->csConvObj->parse_charset($contenttype[1]);
59 if ($charset && $charset != $this->requestCharset) {
60 $this->requestCharset = $charset;
61 }
62 // If the AJAX request does not have the same encoding like the backend
63 // we need to convert the POST and GET parameters in the right charset
64 if ($this->charset != $this->requestCharset) {
65 $GLOBALS['LANG']->csConvObj->convArray($_POST, $this->requestCharset, $this->charset);
66 $GLOBALS['LANG']->csConvObj->convArray($_GET, $this->requestCharset, $this->charset);
67 }
68 $this->ajaxId = $ajaxId;
69 }
70
71 /**
72 * Returns the ID for the AJAX call
73 *
74 * @return string The AJAX id
75 */
76 public function getAjaxID() {
77 return $this->ajaxId;
78 }
79
80 /**
81 * Overwrites the existing content with the first parameter
82 *
83 * @param array $content The new content
84 * @return mixed The old content as array; if the new content was not an array, FALSE is returned
85 */
86 public function setContent($content) {
87 $oldcontent = FALSE;
88 if (is_array($content)) {
89 $oldcontent = $this->content;
90 $this->content = $content;
91 }
92 return $oldcontent;
93 }
94
95 /**
96 * Adds new content
97 *
98 * @param string $key The new content key where the content should be added in the content array
99 * @param string $content The new content to add
100 * @return mixed The old content; if the old content didn't exist before, FALSE is returned
101 */
102 public function addContent($key, $content) {
103 $oldcontent = FALSE;
104 if (array_key_exists($key, $this->content)) {
105 $oldcontent = $this->content[$key];
106 }
107 if (!isset($content) || empty($content)) {
108 unset($this->content[$key]);
109 } elseif (!isset($key) || empty($key)) {
110 $this->content[] = $content;
111 } else {
112 $this->content[$key] = $content;
113 }
114 return $oldcontent;
115 }
116
117 /**
118 * Returns the content for the ajax call
119 *
120 * @return mixed The content for a specific key or the whole content
121 */
122 public function getContent($key = '') {
123 return $key && array_key_exists($key, $this->content) ? $this->content[$key] : $this->content;
124 }
125
126 /**
127 * Sets the content format for the ajax call
128 *
129 * @param string $format Can be one of 'plain' (default), 'xml', 'json', 'javascript', 'jsonbody' or 'jsonhead'
130 * @return void
131 */
132 public function setContentFormat($format) {
133 if (\TYPO3\CMS\Core\Utility\GeneralUtility::inArray(array('plain', 'xml', 'json', 'jsonhead', 'jsonbody', 'javascript'), $format)) {
134 $this->contentFormat = $format;
135 }
136 }
137
138 /**
139 * Specifies the wrap to be used if contentFormat is "javascript".
140 * The wrap used by default stores the results in a variable "response" and
141 * adds <script>-Tags around it.
142 *
143 * @param string $javascriptCallbackWrap The javascript callback wrap to be used
144 * @return void
145 */
146 public function setJavascriptCallbackWrap($javascriptCallbackWrap) {
147 $this->javascriptCallbackWrap = $javascriptCallbackWrap;
148 }
149
150 /**
151 * Sets an error message and the error flag
152 *
153 * @param string $errorMsg The error message
154 * @return void
155 */
156 public function setError($errorMsg = '') {
157 $this->errorMessage = $errorMsg;
158 $this->isError = TRUE;
159 }
160
161 /**
162 * Checks whether an error occurred during the execution or not
163 *
164 * @return boolean Whether this AJAX call had errors
165 */
166 public function isError() {
167 return $this->isError;
168 }
169
170 /**
171 * Renders the AJAX call based on the $contentFormat variable and exits the request
172 *
173 * @return void
174 */
175 public function render() {
176 if ($this->isError) {
177 $this->renderAsError();
178 die;
179 }
180 switch ($this->contentFormat) {
181 case 'jsonhead':
182
183 case 'jsonbody':
184
185 case 'json':
186 $this->renderAsJSON();
187 break;
188 case 'javascript':
189 $this->renderAsJavascript();
190 break;
191 case 'xml':
192 $this->renderAsXML();
193 break;
194 default:
195 $this->renderAsPlain();
196 }
197 die;
198 }
199
200 /**
201 * Renders the AJAX call in XML error style to handle with JS
202 * the "responseXML" of the transport object will be filled with the error message then
203 *
204 * @return void
205 */
206 protected function renderAsError() {
207 header(\TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_500 . ' (AJAX)');
208 header('Content-type: text/xml; charset=' . $this->charset);
209 header('X-JSON: false');
210 die('<t3err>' . htmlspecialchars($this->errorMessage) . '</t3err>');
211 }
212
213 /**
214 * Renders the AJAX call with text/html headers
215 * the content will be available in the "responseText" value of the transport object
216 *
217 * @return void
218 */
219 protected function renderAsPlain() {
220 header('Content-type: text/html; charset=' . $this->charset);
221 header('X-JSON: true');
222 echo implode('', $this->content);
223 }
224
225 /**
226 * Renders the AJAX call with text/xml headers
227 * the content will be available in the "responseXML" value of the transport object
228 *
229 * @return void
230 */
231 protected function renderAsXML() {
232 header('Content-type: text/xml; charset=' . $this->charset);
233 header('X-JSON: true');
234 echo implode('', $this->content);
235 }
236
237 /**
238 * Renders the AJAX call with JSON evaluated headers
239 * note that you need to have requestHeaders: {Accept: 'application/json'},
240 * in your AJAX options of your AJAX request object in JS
241 *
242 * the content will be available
243 * - in the second parameter of the onSuccess / onComplete callback (except when contentFormat = 'jsonbody')
244 * - and in the xhr.responseText as a string (except when contentFormat = 'jsonhead')
245 * you can evaluate this in JS with xhr.responseText.evalJSON();
246 *
247 * @return void
248 */
249 protected function renderAsJSON() {
250 // If the backend does not run in UTF-8 then we need to convert it to unicode as
251 // the json_encode method will return empty otherwise
252 if ($this->charset != $this->requestCharset) {
253 $GLOBALS['LANG']->csConvObj->convArray($this->content, $this->charset, $this->requestCharset);
254 }
255 $content = json_encode($this->content);
256 header('Content-type: application/json; charset=' . $this->requestCharset);
257 header('X-JSON: ' . ($this->contentFormat != 'jsonbody' ? $content : TRUE));
258 // Bring content in xhr.responseText except when in "json head only" mode
259 if ($this->contentFormat != 'jsonhead') {
260 echo $content;
261 }
262 }
263
264 /**
265 * Renders the AJAX call as inline JSON inside a script tag. This is useful
266 * when an iframe is used as the AJAX transport.
267 *
268 * @return void
269 */
270 protected function renderAsJavascript() {
271 // If the backend does not run in UTF-8 then we need to convert it to unicode as
272 // the json_encode method will return empty otherwise
273 if ($this->charset != $this->requestCharset) {
274 $GLOBALS['LANG']->csConvObj->convArray($this->content, $this->charset, $this->requestCharset);
275 }
276 $content = str_replace('|', json_encode($this->content), $this->javascriptCallbackWrap);
277 header('Content-type: text/html; charset=' . $this->requestCharset);
278 echo $content;
279 }
280
281 }