1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Elgg page handler functions |
4
|
|
|
* |
5
|
|
|
* @package Elgg.Core |
6
|
|
|
* @subpackage Routing |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Register a new route |
11
|
|
|
* |
12
|
|
|
* Route paths can contain wildcard segments, i.e. /blog/owner/{username} |
13
|
|
|
* To make a certain wildcard segment optional, add ? to its name, |
14
|
|
|
* i.e. /blog/owner/{username?} |
15
|
|
|
* |
16
|
|
|
* Wildcard requirements for common named variables such as 'guid' and 'username' |
17
|
|
|
* will be set automatically. |
18
|
|
|
* |
19
|
|
|
* @warning If you are registering a route in the path of a route registered by |
20
|
|
|
* deprecated {@link elgg_register_page_handler}, your registration must |
21
|
|
|
* preceed the call to elgg_register_page_handler() in the boot sequence. |
22
|
|
|
* |
23
|
|
|
* @param string $name Unique route name |
24
|
|
|
* This name can later be used to generate route URLs |
25
|
|
|
* @param array $params Route parameters |
26
|
|
|
* - path : path of the route |
27
|
|
|
* - resource : name of the resource view |
28
|
|
|
* - defaults : default values of wildcard segments |
29
|
|
|
* - requirements : regex patterns for wildcard segment requirements |
30
|
|
|
* - methods : HTTP methods |
31
|
|
|
* |
32
|
|
|
* @return \Elgg\Router\Route |
33
|
|
|
*/ |
34
|
|
|
function elgg_register_route($name, array $params = []) { |
35
|
112 |
|
return _elgg_services()->router->registerRoute($name, $params); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Unregister a route by its name |
40
|
|
|
* |
41
|
|
|
* @param string $name Name of the route |
42
|
|
|
* |
43
|
|
|
* @return void |
44
|
|
|
*/ |
45
|
|
|
function elgg_unregister_route($name) { |
46
|
19 |
|
_elgg_services()->router->unregisterRoute($name); |
47
|
19 |
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Generate a URL for named route |
51
|
|
|
* |
52
|
|
|
* @param string $name Route name |
53
|
|
|
* @param array $parameters Parameters |
54
|
|
|
* |
55
|
|
|
* @return string |
56
|
|
|
*/ |
57
|
|
|
function elgg_generate_url($name, array $parameters = []) { |
58
|
32 |
|
return _elgg_services()->router->generateUrl($name, $parameters); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Generate entity URL from a named route |
63
|
|
|
* |
64
|
|
|
* This function is intended to generate URLs from registered named routes that depend on entity type and subtype. |
65
|
|
|
* It will first try to detect routes that contain both type and subtype in the name, and will then fallback to |
66
|
|
|
* route names without the subtype, e.g. 'view:object:blog:attachments' and 'view:object:attachments' |
67
|
|
|
* |
68
|
|
|
* @tip Route segments will be automatically resolved from entity attributes and metadata, |
69
|
|
|
* so given the path `/blog/view/{guid}/{title}/{status}` the path will be |
70
|
|
|
* be resolved from entity guid, URL-friendly title and status metadata. |
71
|
|
|
* |
72
|
|
|
* @tip Parameters that do not have matching segment names in the route path, will be added to the URL as query elements. |
73
|
|
|
* |
74
|
|
|
* |
75
|
|
|
* @param ElggEntity $entity Entity |
76
|
|
|
* @param string $resource Resource name |
77
|
|
|
* @param string $subresource Subresource name |
78
|
|
|
* @param array $parameters URL query elements |
79
|
|
|
* |
80
|
|
|
* @return string |
81
|
|
|
*/ |
82
|
|
|
function elgg_generate_entity_url(ElggEntity $entity, $resource = 'view', $subresource = null, $parameters = []) { |
83
|
|
|
|
84
|
|
|
$make_route_name = function ($type, $subtype) use ($resource, $subresource) { |
85
|
|
|
$route_parts = [ |
86
|
|
|
$resource, |
87
|
|
|
$type, |
88
|
|
|
$subtype, |
89
|
|
|
$subresource, |
90
|
|
|
]; |
91
|
|
|
|
92
|
|
|
return implode(':', array_filter($route_parts)); |
93
|
|
|
}; |
94
|
|
|
|
95
|
|
|
$pairs = [ |
96
|
|
|
[$entity->type, $entity->subtype], |
97
|
|
|
[$entity->type, null], |
98
|
|
|
]; |
99
|
|
|
|
100
|
|
|
$route = false; |
101
|
|
|
$route_name = ''; |
102
|
|
|
|
103
|
|
|
foreach ($pairs as $pair) { |
104
|
|
|
$route_name = $make_route_name($pair[0], $pair[1]); |
105
|
|
|
$route = _elgg_services()->routeCollection->get($route_name); |
106
|
|
|
if ($route) { |
107
|
|
|
break; |
108
|
|
|
} |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
if (!$route) { |
112
|
|
|
return; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$requirements = $route->getRequirements(); |
116
|
|
|
$defaults = $route->getDefaults(); |
117
|
|
|
|
118
|
|
|
$props = array_merge(array_keys($requirements), array_keys($defaults)); |
119
|
|
|
|
120
|
|
|
foreach ($props as $prop) { |
121
|
|
|
if (substr($prop, 0, 1) === '_') { |
122
|
|
|
continue; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
if (isset($parameters[$prop])) { |
126
|
|
|
continue; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
switch ($prop) { |
130
|
|
|
case 'title' : |
131
|
|
|
case 'name' : |
132
|
|
|
$parameters[$prop] = elgg_get_friendly_title($entity->getDisplayName()); |
133
|
|
|
break; |
134
|
|
|
|
135
|
|
|
default : |
136
|
|
|
$parameters[$prop] = $entity->$prop; |
137
|
|
|
break; |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
return elgg_generate_url($route_name, $parameters); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Generate an action URL |
146
|
|
|
* |
147
|
|
|
* @param string $action Action name |
148
|
|
|
* @param array $query Query elements |
149
|
|
|
* @param bool $add_csrf_tokens Add tokens |
150
|
|
|
* |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
|
|
function elgg_generate_action_url($action, array $query = [], $add_csrf_tokens = true) { |
154
|
|
|
|
155
|
|
|
$url = "action/$action"; |
156
|
|
|
$url = elgg_http_add_url_query_elements($url, $query); |
157
|
|
|
$url = elgg_normalize_url($url); |
158
|
|
|
|
159
|
|
|
if ($add_csrf_tokens) { |
160
|
|
|
$url = elgg_add_action_tokens_to_url($url); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $url; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Used at the top of a page to mark it as logged in users only. |
168
|
|
|
* |
169
|
|
|
* @return void |
170
|
|
|
* @throws \Elgg\GatekeeperException |
171
|
|
|
* @since 1.9.0 |
172
|
|
|
*/ |
173
|
|
|
function elgg_gatekeeper() { |
174
|
|
|
if (!elgg_is_logged_in()) { |
175
|
|
|
_elgg_services()->redirects->setLastForwardFrom(); |
176
|
|
|
|
177
|
|
|
$msg = elgg_echo('loggedinrequired'); |
178
|
|
|
throw new \Elgg\GatekeeperException($msg); |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Used at the top of a page to mark it as admin only. |
184
|
|
|
* |
185
|
|
|
* @return void |
186
|
|
|
* @throws \Elgg\GatekeeperException |
187
|
|
|
* @since 1.9.0 |
188
|
|
|
*/ |
189
|
|
|
function elgg_admin_gatekeeper() { |
190
|
|
|
elgg_gatekeeper(); |
191
|
|
|
|
192
|
|
|
if (!elgg_is_admin_logged_in()) { |
193
|
|
|
_elgg_services()->redirects->setLastForwardFrom(); |
194
|
|
|
|
195
|
|
|
$msg = elgg_echo('adminrequired'); |
196
|
|
|
throw new \Elgg\GatekeeperException($msg); |
197
|
|
|
} |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* May the current user access item(s) on this page? If the page owner is a group, |
203
|
|
|
* membership, visibility, and logged in status are taken into account. |
204
|
|
|
* |
205
|
|
|
* @param bool $forward If set to true (default), will forward the page; |
206
|
|
|
* if set to false, will return true or false. |
207
|
|
|
* |
208
|
|
|
* @param int $group_guid The group that owns the page. If not set, this |
209
|
|
|
* will be pulled from elgg_get_page_owner_guid(). |
210
|
|
|
* |
211
|
|
|
* @return bool Will return if $forward is set to false. |
212
|
|
|
* @throws InvalidParameterException |
213
|
|
|
* @throws SecurityException |
214
|
|
|
* @since 1.9.0 |
215
|
|
|
*/ |
216
|
|
|
function elgg_group_gatekeeper($forward = true, $group_guid = null) { |
217
|
|
|
if (null === $group_guid) { |
218
|
|
|
$group_guid = elgg_get_page_owner_guid(); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
if (!$group_guid) { |
222
|
17 |
|
return true; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// this handles non-groups and invisible groups |
226
|
17 |
|
$visibility = \Elgg\GroupItemVisibility::factory($group_guid); |
227
|
|
|
|
228
|
|
|
if (!$visibility->shouldHideItems) { |
229
|
|
|
return true; |
230
|
|
|
} |
231
|
|
|
if ($forward) { |
232
|
|
|
// only forward to group if user can see it |
233
|
|
|
$group = get_entity($group_guid); |
234
|
|
|
$forward_url = $group ? $group->getURL() : ''; |
235
|
|
|
|
236
|
|
|
if (!elgg_is_logged_in()) { |
237
|
|
|
_elgg_services()->redirects->setLastForwardFrom(); |
238
|
|
|
$forward_reason = 'login'; |
239
|
|
|
} else { |
240
|
|
|
$forward_reason = 'member'; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$msg_keys = [ |
244
|
70 |
|
'non_member' => 'membershiprequired', |
245
|
8 |
|
'logged_out' => 'loggedinrequired', |
246
|
|
|
'no_access' => 'noaccess', |
247
|
|
|
]; |
248
|
70 |
|
register_error(elgg_echo($msg_keys[$visibility->reasonHidden])); |
249
|
|
|
forward($forward_url, $forward_reason); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
return false; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Can the viewer see this entity? |
257
|
|
|
* |
258
|
|
|
* Tests if the entity exists and whether the viewer has access to the entity |
259
|
|
|
* if it does. If the viewer cannot view this entity, it forwards to an |
260
|
|
|
* appropriate page. |
261
|
|
|
* |
262
|
|
|
* @param int $guid Entity GUID |
263
|
|
|
* @param string $type Optional required entity type |
264
|
|
|
* @param string $subtype Optional required entity subtype |
265
|
|
|
* @param bool $forward If set to true (default), will forward the page; |
266
|
|
|
* if set to false, will return true or false. |
267
|
|
|
* |
268
|
|
|
* @return bool Will return if $forward is set to false. |
269
|
36 |
|
* @throws \Elgg\BadRequestException |
270
|
32 |
|
* @throws \Elgg\EntityNotFoundException |
271
|
|
|
* @throws \Elgg\EntityPermissionsException |
272
|
|
|
* @throws \Elgg\GatekeeperException |
273
|
36 |
|
* @since 1.9.0 |
274
|
|
|
*/ |
275
|
|
|
function elgg_entity_gatekeeper($guid, $type = null, $subtype = null, $forward = true) { |
276
|
|
|
$entity = get_entity($guid); |
277
|
|
|
if (!$entity && $forward) { |
278
|
|
|
if (!elgg_entity_exists($guid)) { |
279
|
|
|
// entity doesn't exist |
280
|
|
|
throw new \Elgg\EntityNotFoundException(); |
281
|
|
|
} else if (!elgg_is_logged_in()) { |
282
|
|
|
// entity requires at least a logged in user |
283
|
|
|
elgg_gatekeeper(); |
284
|
|
|
} else { |
285
|
|
|
// user is logged in but still does not have access to it |
286
|
|
|
$msg = elgg_echo('limited_access'); |
287
|
|
|
throw new \Elgg\GatekeeperException($msg); |
288
|
|
|
} |
289
|
|
|
} else if (!$entity) { |
290
|
|
|
return false; |
291
|
6 |
|
} |
292
|
|
|
|
293
|
|
|
if ($type && !elgg_instanceof($entity, $type, $subtype)) { |
|
|
|
|
294
|
|
|
// entity is of wrong type/subtype |
295
|
|
|
if ($forward) { |
296
|
|
|
throw new \Elgg\BadRequestException(); |
297
|
|
|
} else { |
298
|
|
|
return false; |
299
|
|
|
} |
300
|
18 |
|
} |
301
|
|
|
|
302
|
|
|
$hook_type = "{$entity->getType()}:{$entity->getSubtype()}"; |
303
|
|
|
$hook_params = [ |
304
|
|
|
'entity' => $entity, |
305
|
|
|
'forward' => $forward, |
306
|
|
|
]; |
307
|
|
|
if (!elgg_trigger_plugin_hook('gatekeeper', $hook_type, $hook_params, true)) { |
308
|
|
|
if ($forward) { |
309
|
|
|
throw new \Elgg\EntityPermissionsException(); |
310
|
|
|
} else { |
311
|
|
|
return false; |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
return true; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* Require that the current request be an XHR. If not, execution of the current function |
320
|
|
|
* will end and a 400 response page will be sent. |
321
|
|
|
* |
322
|
|
|
* @return void |
323
|
|
|
* @throws \Elgg\BadRequestException |
324
|
|
|
* @since 1.12.0 |
325
|
|
|
*/ |
326
|
|
|
function elgg_ajax_gatekeeper() { |
327
|
|
|
if (!elgg_is_xhr()) { |
328
|
|
|
$msg = elgg_echo('ajax:not_is_xhr'); |
329
|
|
|
throw new \Elgg\BadRequestException($msg); |
330
|
|
|
} |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* Prepares a successful response to be returned by a page or an action handler |
335
|
|
|
* |
336
|
|
|
* @param mixed $content Response content |
337
|
|
|
* In page handlers, response content should contain an HTML string |
338
|
|
|
* In action handlers, response content can contain either a JSON string or an array of data |
339
|
|
|
* @param string $message System message visible to the client |
340
|
|
|
* Can be used by handlers to display a system message |
341
|
|
|
* @param string $forward_url Forward URL |
342
|
|
|
* Can be used by handlers to redirect the client on non-ajax requests |
343
|
|
|
* @param int $status_code HTTP status code |
344
|
|
|
* Status code of the HTTP response (defaults to 200) |
345
|
|
|
* |
346
|
|
|
* @return \Elgg\Http\OkResponse |
347
|
|
|
*/ |
348
|
|
|
function elgg_ok_response($content = '', $message = '', $forward_url = null, $status_code = ELGG_HTTP_OK) { |
349
|
|
|
if ($message) { |
350
|
|
|
system_message($message); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
return new \Elgg\Http\OkResponse($content, $status_code, $forward_url); |
354
|
|
|
|
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* Prepare an error response to be returned by a page or an action handler |
359
|
|
|
* |
360
|
|
|
* @param string $error Error message |
361
|
|
|
* Can be used by handlers to display an error message |
362
|
|
|
* For certain requests this error message will also be used as the response body |
363
|
|
|
* @param string $forward_url URL to redirect the client to |
364
|
|
|
* Can be used by handlers to redirect the client on non-ajax requests |
365
|
|
|
* @param int $status_code HTTP status code |
366
|
|
|
* Status code of the HTTP response |
367
|
|
|
* For BC reasons and due to the logic in the client-side AJAX API, |
368
|
|
|
* this defaults to 200. Note that the Router and AJAX API will |
369
|
|
|
* treat these responses as error in spite of the HTTP code assigned |
370
|
|
|
* |
371
|
|
|
* @return \Elgg\Http\ErrorResponse |
372
|
|
|
*/ |
373
|
|
|
function elgg_error_response($error = '', $forward_url = REFERRER, $status_code = ELGG_HTTP_OK) { |
374
|
|
|
if ($error) { |
375
|
|
|
register_error($error); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
return new \Elgg\Http\ErrorResponse($error, $status_code, $forward_url); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Prepare a silent redirect response to be returned by a page or an action handler |
383
|
|
|
* |
384
|
|
|
* @param string $forward_url Redirection URL |
385
|
|
|
* Relative or absolute URL to redirect the client to |
386
|
|
|
* @param int $status_code HTTP status code |
387
|
|
|
* Status code of the HTTP response |
388
|
|
|
* Note that the Router and AJAX API will treat these responses |
389
|
|
|
* as redirection in spite of the HTTP code assigned |
390
|
|
|
* Note that non-redirection HTTP codes will throw an exception |
391
|
|
|
* |
392
|
|
|
* @return \Elgg\Http\RedirectResponse |
393
|
|
|
* @throws \InvalidArgumentException |
394
|
|
|
*/ |
395
|
|
|
function elgg_redirect_response($forward_url = REFERRER, $status_code = ELGG_HTTP_FOUND) { |
396
|
|
|
return new Elgg\Http\RedirectResponse($forward_url, $status_code); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* @see \Elgg\Application::loadCore Do not do work here. Just register for events. |
402
|
|
|
*/ |
403
|
|
|
return function (\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
|
|
|
|
404
|
|
|
|
405
|
|
|
}; |
406
|
|
|
|
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: