-
Notifications
You must be signed in to change notification settings - Fork 32
/
ajax.php
367 lines (325 loc) · 13.1 KB
/
ajax.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
<?php
////////////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2016 Phorum Development Team //
// http://www.phorum.org //
// //
// This program is free software. You can redistribute it and/or modify //
// it under the terms of either the current Phorum License (viewable at //
// phorum.org) or the Phorum License that was distributed with this file //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY, without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
// //
// You should have received a copy of the Phorum License //
// along with this program. //
// //
////////////////////////////////////////////////////////////////////////////////
// This script is used for handling Ajax calls to the Phorum system.
// Ajax calls can either be implemented as scripts files in
// "./include/ajax/call.<callname>.php" or through modules that implement
// the "ajax_<call>" hook.
define('phorum_page', 'ajax');
require_once './common.php';
require_once PHORUM_PATH.'/include/api/json.php';
// Registration of some language strings that can be used by Ajax clients.
// We put them in here, so the language tool can find them.
// $PHORUM['DATA']['LANG']['ActionPending']
// $PHORUM['DATA']['LANG']['ActionsPending']
// ----------------------------------------------------------------------
// Client JavaScript library
// ----------------------------------------------------------------------
if (isset($PHORUM['args'][0]) && $PHORUM['args'][0] == 'client') {
phorum_api_redirect(PHORUM_JAVASCRIPT_URL);
}
// ----------------------------------------------------------------------
// Show examples page.
// ----------------------------------------------------------------------
if (isset($PHORUM['args'][0]) && $PHORUM['args'][0] == 'examples') {
include './include/ajax/examples.php';
exit;
}
// ----------------------------------------------------------------------
// Dispatch Ajax calls
// ----------------------------------------------------------------------
$PHORUM['ajax_args'] = array();
// Check if this is a JSONP request.
$PHORUM['ajax_jsonp'] = NULL;
if (isset($PHORUM['args']['callback'])) {
$PHORUM['ajax_jsonp'] = $PHORUM['args']['callback'];
}
// JSON data based request (stored in a POST or PUT request body)
if ($_SERVER['REQUEST_METHOD']=='POST' || $_SERVER['REQUEST_METHOD']=='PUT')
{
// Get the POST body.
$body = trim(file_get_contents('php://input'));
if ($body == '') phorum_ajax_error('Ajax POST request misses body');
// Set the Ajax arguments.
$PHORUM["ajax_args"] = phorum_api_json_decode($body);
if ($PHORUM["ajax_args"] == NULL) phorum_ajax_error(
'Ajax POST request body does not seem to be JSON data'
);
}
// GET based request.
elseif (isset($_GET['call']))
{
// Set the Ajax arguments.
$PHORUM['ajax_args'] = $_GET;
}
// Phorum argument based request.
elseif (isset($PHORUM['args']['call']))
{
// Set the Ajax arguments.
$PHORUM['ajax_args'] = $PHORUM['args'];
}
// Check if we got a valid Ajax request. The request should contain at
// least a "call" field in the Ajax arguments.
if (empty($PHORUM['ajax_args']) || !isset($PHORUM['ajax_args']['call'])) {
phorum_ajax_error('Illegal Ajax request');
}
$ajax_call = basename($PHORUM['ajax_args']['call']);
// try to get some session-id if there isn't already a user loaded through
// the regular ways
if(empty($PHORUM['user']['user_id'])) {
// check if we got a session-id in the ajax args and if we got one
// try to load a user with that data
$ajax_session_id = phorum_ajax_getarg(PHORUM_SESSION_LONG_TERM,'string',0);
if(!empty($ajax_session_id)) {
$PHORUM['use_cookies']=PHORUM_USE_COOKIES;
$PHORUM['args'][PHORUM_SESSION_LONG_TERM]=$ajax_session_id;
phorum_api_user_session_restore(PHORUM_FORUM_SESSION);
}
}
/**
* [hook]
* ajax_<call>
*
* [availability]
* Phorum 5 >= 5.2.8
*
* [description]
* This hook allows module writers to implement calls for the
* Phorum Ajax layer.<sbr/>
* <sbr/>
* The "call" argument from the Ajax argument array is used to
* construct the name of the hook that will be called. For example
* for the call "sayhello" the called hook will be
* <literal>call_sayhello</literal><sbr/>
* <sbr/>
* A call implementation should always be using
* the provided functions <literal>phorum_ajax_return()</literal>
* and <literal>phorum_ajax_error()</literal> to return data to the
* client. Because these functions will call <literal>exit</literal>
* after they are done, hook functions that implement an Ajax call stop
* page execution and do not return like other hook functions.
* Only if the hook function decides for some reason that the Ajax call
* is not to be handled by the module, it can return the Ajax argument
* array.
*
* [category]
* Miscellaneous
*
* [when]
* Just before ajax.php tries to find a built-in handler script
* for an Ajax call. Therefore, this hook can also be used to
* override core Ajax call implementations. We strongly
* discourage doing so though.
*
* [input]
* The Ajax argument array
*
* [output]
* The same array as the one that was used for the hook call argument.
*
* [example]
* <hookcode>
* function phorum_mod_foo_ajax_sayhello($ajax_args)
* {
* // An optional name=.... argument can be used in the request.
* $name = phorum_ajax_getarg('name', 'string', 'Anonymous Person');
*
* // This will return a JSON encoded string to the client.
* phorum_ajax_return("Hello, $name");
* }
* </hookcode>
*
* For this hook implementation, a GET based URL to fire this
* Ajax call could look like
* <literal>http://example.com/ajax.php?call=sayhello,name=JohnDoe</literal>.
*/
$call_hook = 'ajax_' . $ajax_call;
if (isset($PHORUM['hooks'][$call_hook])) {
phorum_api_hook($call_hook, $PHORUM['ajax_args']);
}
// Check if the Ajax call has a core handler script.
if (file_exists("./include/ajax/call.$ajax_call.php")) {
include "./include/ajax/call.$ajax_call.php";
exit();
}
// No handler script available. Bail out.
phorum_ajax_error('Unknown call "'.$ajax_call.'" in Ajax POST request');
// ----------------------------------------------------------------------
// Utility functions that can be used by Ajax call implementations
// ----------------------------------------------------------------------
/**
* Return an Ajax error to the caller.
*
* This will send an error (500 HTTP status code) message to the client,
* using UTF-8 as the character set.
*
* When JSONP is used for communicating to Phorum's Ajax script, then
* a JSONP callback is done with {error: "error message"} as the
* response data. The calling client will have to handle this error.
*
* @param string $message
* The error message to return.
*/
function phorum_ajax_error($message)
{
global $PHORUM;
if ($PHORUM['ajax_jsonp'] === NULL) {
header("HTTP/1.1 500 Phorum Ajax error");
header("Status: 500 Phorum Ajax error");
header("Content-Type: text/plain; charset=UTF-8");
print phorum_api_charset_convert_to_utf8($message);
} else {
$return = phorum_api_json_encode(array('error' => $message));
print $PHORUM['ajax_jsonp'] . "($return);";
}
exit(1);
}
/**
* Return an Ajax result to the caller.
*
* The data will be sent to the client in the JSON encoding format,
* using UTF-8 as the character set.
*
* When JSONP is used for communicating to Phorum's Ajax script, then
* a JSONP callback is done with the JSON encoded $data as the response data.
*
* @param mixed $data
* The data to return in the body.
*/
function phorum_ajax_return($data)
{
global $PHORUM;
header("Content-Type: text/plain; charset=UTF-8");
$return = phorum_api_json_encode($data);
if ($PHORUM['ajax_jsonp'] === NULL) {
print $return;
} else {
print $PHORUM['ajax_jsonp'] . "($return);";
}
exit(0);
}
/**
* Retrieve an argument from the call arguments.
*
* The Ajax call arguments are stored in the array $PHORUM['ajax_args'].
* his function can be used to retrieve a single argument from this array.
*
* It can check the argument type by providing the $type parameter.
* Also, a default value can be supplied, which will be used in case the
* requested argument wasn't included in the call data.
*
* If an argument is invalid or missing without providing a default value,
* then an Ajax error will be returned.
*
* @param string $arg
* The name of the argument to retrieve.
*
* @param mixed $type
*
* The type of data to retrieve. Options are: "int", "int>0", "int>=0",
* "string", "boolean". These types can be prefixed with "array:" to
* indicate that an array of those types has to be returned. If the input
* argument is not an array in this case, then this function will
* convert it to a single item array.
*
* The type can also be NULL, in which case the argument is not checked
* at all. This is useful for more complex data types, which need to be
* checked by the function that uses them.
*
* @param mixed $default
* The default value for the argument or NULL if no default is available.
*
* @return $value - The value for the argument.
*/
function phorum_ajax_getarg($arg, $type = NULL, $default = NULL)
{
global $PHORUM;
// Fetch the argument from the Ajax request data.
if (! isset($PHORUM["ajax_args"][$arg])) {
if (! is_null($default)) {
return $default;
} else phorum_ajax_error(
"missing Ajax argument: ".htmlspecialchars($arg)
);
}
$value = $PHORUM["ajax_args"][$arg];
// Handle JSON decoding if the value was JSON encoded.
// This is determined by the magic marker $JSON$ that can be
// prefixed to an argument. This encoding method is used
// for handling arrays in JSONP call parameters from the
// Phorum JavaScript library.
if (strlen($value) > 6 && substr($value, 0, 6) == '$JSON$') {
$value = phorum_api_json_decode(substr($value, 6));
}
// Return immediately, if we don't need to do type checking.
if (is_null($type)) {
return $value;
}
// Check if an array should be returned.
$array = FALSE;
if (substr($type, 0, 6) == 'array:') {
$type = substr($type, 6);
$array = TRUE;
}
if ($array && !is_array($value)) phorum_ajax_error(
"illegal argument: argument \"$arg\" should be an array ($type)");
if (!$array && is_array($value)) phorum_ajax_error(
"illegal argument: argument \"$arg\" should not be an array ($type)");
if (!is_array($value)) $value = array(0 => $value);
// Check the argument's data type.
switch ($type)
{
case 'string':
break;
case 'int>0':
case 'int>=0':
case 'int':
foreach ($value as $k => $v) {
if (!preg_match('/^[-+]?\d+$/', $v)) phorum_ajax_error(
"illegal argument: argument \"$arg\" must contain " .
($array ? "only integer values" : "an integer value"));
if ($type == 'int>0' && $v <= 0) phorum_ajax_error(
"illegal argument: argument \"$arg\" must contain " .
($array ? "only integer values" : "an integer value") .
", larger than zero");
if ($type == 'int>=0' && $v < 0) phorum_ajax_error(
"illegal argument: argument \"$arg\" must contain " .
($array ? "only integer values" : "an integer value") .
", larger than or equal to zero");
}
break;
case 'boolean':
foreach ($value as $k => $v) {
$val = strtolower($v);
if ($v == '1' || $v == 'yes' || $v == 'true') {
$value[$k] = TRUE;
} elseif ($v == '0' || $v == 'no' || $v == 'false') {
$value[$k] = FALSE;
} else phorum_ajax_error(
"illegal argument: argument \"$arg\" must contain " .
($array ? "only boolean values" : "a boolean value") .
" (0, 1, \"yes\", \"no\", \"true\" or \"false\")");
}
break;
default:
phorum_ajax_error("Internal error: illegal argument type: " .
($array ? "array:" : "") . $type);
}
return $array ? $value : $value[0];
}
?>