d94eaae42c3b240925d53634c1bd2d46eaf32410
[Packages/TYPO3.CMS.git] / typo3 / classes / class.typo3ajax.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2008-2009 Benjamin Mack <mack@xnos.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * class to hold all the information about an AJAX call and send
30 * the right headers for the request type
31 *
32 * @author Benjamin Mack <mack@xnos.org>
33 * @package TYPO3
34 * @subpackage core
35 */
36 class TYPO3AJAX {
37 protected $ajaxId = null;
38 protected $errorMessage = null;
39 protected $isError = false;
40 protected $content = array();
41 protected $contentFormat = 'plain';
42 protected $charset = 'utf-8';
43 protected $requestCharset = 'utf-8';
44
45 /**
46 * sets the charset and the ID for the AJAX call
47 * due some charset limitations in Javascript (prototype uses encodeURIcomponent, which converts
48 * all data to utf-8), we need to detect if the encoding of the request differs from the
49 * backend encoding (e.g. forceCharset), and then convert all incoming data (_GET and _POST)
50 * in the expected backend encoding.
51 *
52 * @param string the AJAX id
53 * @return void
54 */
55 public function __construct($ajaxId) {
56
57 if ($GLOBALS['LANG']->charSet != $this->charset) {
58 $this->charset = $GLOBALS['LANG']->charSet;
59 }
60
61 // get charset from current AJAX request (which is expected to be utf-8)
62 preg_match('/;\s*charset\s*=\s*([a-zA-Z0-9_-]*)/i', $_SERVER['CONTENT_TYPE'], $contenttype);
63 $charset = $GLOBALS['LANG']->csConvObj->parse_charset($contenttype[1]);
64 if ($charset && $charset != $this->requestCharset) {
65 $this->requestCharset = $charset;
66 }
67
68 // if the AJAX request does not have the same encoding like the backend
69 // we need to convert the POST and GET parameters in the right charset
70 if ($this->charset != $this->requestCharset) {
71 $GLOBALS['LANG']->csConvObj->convArray($_POST, $this->requestCharset, $this->charset);
72 $GLOBALS['LANG']->csConvObj->convArray($_GET, $this->requestCharset, $this->charset);
73 }
74
75 $this->ajaxId = $ajaxId;
76 }
77
78
79 /**
80 * returns the ID for the AJAX call
81 *
82 * @return string the AJAX id
83 */
84 public function getAjaxID() {
85 return $this->ajaxId;
86 }
87
88
89 /**
90 * overwrites the existing content with the first parameter
91 *
92 * @param array the new content
93 * @return mixed the old content as array; if the new content was not an array, false is returned
94 */
95 public function setContent($content) {
96 $oldcontent = false;
97 if (is_array($content)) {
98 $oldcontent = $this->content;
99 $this->content = $content;
100 }
101 return $oldcontent;
102 }
103
104
105 /**
106 * adds new content
107 *
108 * @param string the new content key where the content should be added in the content array
109 * @param string the new content to add
110 * @return mixed the old content; if the old content didn't exist before, false is returned
111 */
112 public function addContent($key, $content) {
113 $oldcontent = false;
114 if (array_key_exists($key, $this->content)) {
115 $oldcontent = $this->content[$key];
116 }
117 if (!isset($content) || empty($content)) {
118 unset($this->content[$key]);
119 } elseif (!isset($key) || empty($key)) {
120 $this->content[] = $content;
121 } else {
122 $this->content[$key] = $content;
123 }
124 return $oldcontent;
125 }
126
127
128 /**
129 * returns the content for the ajax call
130 *
131 * @return mixed the content for a specific key or the whole content
132 */
133 public function getContent($key = '') {
134 return ($key && array_key_exists($key, $this->content) ? $this->content[$key] : $this->content);
135 }
136
137
138 /**
139 * sets the content format for the ajax call
140 *
141 * @param string can be one of 'plain' (default), 'xml', 'json', 'jsonbody' or 'jsonhead'
142 * @return void
143 */
144 public function setContentFormat($format) {
145 if (t3lib_div::inArray(array('plain', 'xml', 'json', 'jsonhead', 'jsonbody', 'javascript'), $format)) {
146 $this->contentFormat = $format;
147 }
148 }
149
150
151 /**
152 * sets an error message and the error flag
153 *
154 * @param string the error message
155 * @return void
156 */
157 public function setError($errorMsg = '') {
158 $this->errorMessage = $errorMsg;
159 $this->isError = true;
160 }
161
162
163 /**
164 * checks whether an error occured during the execution or not
165 *
166 * @return boolean whether this AJAX call had errors
167 */
168 public function isError() {
169 return $this->isError;
170 }
171
172
173 /**
174 * renders the AJAX call based on the $contentFormat variable and exits the request
175 *
176 * @return void
177 */
178 public function render() {
179 if ($this->isError) {
180 $this->renderAsError();
181 exit;
182 }
183 switch ($this->contentFormat) {
184 case 'jsonhead':
185 case 'jsonbody':
186 case 'json':
187 $this->renderAsJSON();
188 break;
189 case 'javascript':
190 $this->renderAsJavascript();
191 break;
192 case 'xml':
193 $this->renderAsXML();
194 break;
195 default:
196 $this->renderAsPlain();
197 }
198 exit;
199 }
200
201
202 /**
203 * renders the AJAX call in XML error style to handle with JS
204 * the "responseXML" of the transport object will be filled with the error message then
205 *
206 * @return void
207 */
208 protected function renderAsError() {
209 header(t3lib_utility_Http::HTTP_STATUS_500 . ' (AJAX)');
210 header('Content-type: text/xml; charset='.$this->charset);
211 header('X-JSON: false');
212 die('<t3err>'.htmlspecialchars($this->errorMessage).'</t3err>');
213 }
214
215
216 /**
217 * renders the AJAX call with text/html headers
218 * the content will be available in the "responseText" value of the transport object
219 *
220 * @return void
221 */
222 protected function renderAsPlain() {
223 header('Content-type: text/html; charset='.$this->charset);
224 header('X-JSON: true');
225 echo implode('', $this->content);
226 }
227
228
229 /**
230 * renders the AJAX call with text/xml headers
231 * the content will be available in the "responseXML" value of the transport object
232 *
233 * @return void
234 */
235 protected function renderAsXML() {
236 header('Content-type: text/xml; charset='.$this->charset);
237 header('X-JSON: true');
238 echo implode('', $this->content);
239 }
240
241
242 /**
243 * renders the AJAX call with JSON evaluated headers
244 * note that you need to have requestHeaders: {Accept: 'application/json'},
245 * in your AJAX options of your AJAX request object in JS
246 *
247 * the content will be available
248 * - in the second parameter of the onSuccess / onComplete callback (except when contentFormat = 'jsonbody')
249 * - and in the xhr.responseText as a string (except when contentFormat = 'jsonhead')
250 * you can evaluate this in JS with xhr.responseText.evalJSON();
251 *
252 * @return void
253 */
254 protected function renderAsJSON() {
255 // if the backend does not run in UTF-8 then we need to convert it to unicode as
256 // the json_encode method will return empty otherwise
257 if ($this->charset != $this->requestCharset) {
258 $GLOBALS['LANG']->csConvObj->convArray($this->content, $this->charset, $this->requestCharset);
259 }
260
261 $content = json_encode($this->content);
262
263 header('Content-type: application/json; charset='.$this->requestCharset);
264 header('X-JSON: '.($this->contentFormat != 'jsonbody' ? $content : true));
265
266 // bring content in xhr.responseText except when in "json head only" mode
267 if ($this->contentFormat != 'jsonhead') {
268 echo $content;
269 }
270 }
271
272 /**
273 * Renders the AJAX call as inline JSON inside a script tag. This is useful
274 * when an iframe is used as the AJAX transport.
275 *
276 * @return void
277 */
278 protected function renderAsJavascript() {
279 // if the backend does not run in UTF-8 then we need to convert it to unicode as
280 // the json_encode method will return empty otherwise
281 if ($this->charset != $this->requestCharset) {
282 $GLOBALS['LANG']->csConvObj->convArray($this->content, $this->charset, $this->requestCharset);
283 }
284
285 $content = '<script type="text/javascript">
286 /*<![CDATA[*/
287
288 response = ' . json_encode($this->content) . ';
289
290 /*]]>*/
291 </script>';
292
293 header('Content-type: text/html; charset=' . $this->requestCharset);
294 echo $content;
295 }
296 }
297
298
299 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/classes/class.typo3ajax.php']) {
300 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/classes/class.typo3ajax.php']);
301 }
302
303 ?>