This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Elgg river. |
||
4 | * Activity stream functions. |
||
5 | * |
||
6 | * @package Elgg.Core |
||
7 | * @subpackage River |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * Adds an item to the river. |
||
12 | * |
||
13 | * @tip Read the item like "Lisa (subject) posted (action) |
||
14 | * a comment (object) on John's blog (target)". |
||
15 | * |
||
16 | * @param array $options Array in format: |
||
17 | * |
||
18 | * view => STR The view that will handle the river item (must exist) |
||
19 | * |
||
20 | * action_type => STR An arbitrary string to define the action (eg 'comment', 'create') |
||
21 | * |
||
22 | * subject_guid => INT The GUID of the entity doing the action |
||
23 | * |
||
24 | * object_guid => INT The GUID of the entity being acted upon |
||
25 | * |
||
26 | * target_guid => INT The GUID of the the object entity's container |
||
27 | * |
||
28 | * access_id => INT The access ID of the river item (default: same as the object) |
||
29 | * |
||
30 | * posted => INT The UNIX epoch timestamp of the river item (default: now) |
||
31 | * |
||
32 | * annotation_id INT The annotation ID associated with this river entry |
||
33 | * |
||
34 | * @return int|bool River ID or false on failure |
||
35 | * @since 1.9 |
||
36 | */ |
||
37 | function elgg_create_river_item(array $options = array()) { |
||
38 | $view = elgg_extract('view', $options); |
||
39 | // use default viewtype for when called from web services api |
||
40 | if (empty($view) || !(elgg_view_exists($view, 'default'))) { |
||
41 | return false; |
||
42 | } |
||
43 | |||
44 | $action_type = elgg_extract('action_type', $options); |
||
45 | if (empty($action_type)) { |
||
46 | return false; |
||
47 | } |
||
48 | |||
49 | $subject_guid = elgg_extract('subject_guid', $options, 0); |
||
50 | if (!($subject = get_entity($subject_guid))) { |
||
51 | return false; |
||
52 | } |
||
53 | |||
54 | $object_guid = elgg_extract('object_guid', $options, 0); |
||
55 | if (!($object = get_entity($object_guid))) { |
||
56 | return false; |
||
57 | } |
||
58 | |||
59 | $target_guid = elgg_extract('target_guid', $options, 0); |
||
60 | if ($target_guid) { |
||
61 | // target_guid is not a required parameter so check |
||
62 | // it only if it is included in the parameters |
||
63 | if (!($target = get_entity($target_guid))) { |
||
64 | return false; |
||
65 | } |
||
66 | } |
||
67 | |||
68 | $access_id = elgg_extract('access_id', $options, $object->access_id); |
||
69 | |||
70 | $posted = elgg_extract('posted', $options, time()); |
||
71 | |||
72 | $annotation_id = elgg_extract('annotation_id', $options, 0); |
||
73 | if ($annotation_id) { |
||
74 | if (!elgg_get_annotation_from_id($annotation_id)) { |
||
75 | return false; |
||
76 | } |
||
77 | } |
||
78 | |||
79 | $values = array( |
||
80 | 'type' => $object->getType(), |
||
81 | 'subtype' => $object->getSubtype(), |
||
82 | 'action_type' => $action_type, |
||
83 | 'access_id' => $access_id, |
||
84 | 'view' => $view, |
||
85 | 'subject_guid' => $subject_guid, |
||
86 | 'object_guid' => $object_guid, |
||
87 | 'target_guid' => $target_guid, |
||
88 | 'annotation_id' => $annotation_id, |
||
89 | 'posted' => $posted, |
||
90 | ); |
||
91 | $col_types = array( |
||
92 | 'type' => 'string', |
||
93 | 'subtype' => 'string', |
||
94 | 'action_type' => 'string', |
||
95 | 'access_id' => 'int', |
||
96 | 'view' => 'string', |
||
97 | 'subject_guid' => 'int', |
||
98 | 'object_guid' => 'int', |
||
99 | 'target_guid' => 'int', |
||
100 | 'annotation_id' => 'int', |
||
101 | 'posted' => 'int', |
||
102 | ); |
||
103 | |||
104 | // return false to stop insert |
||
105 | $values = elgg_trigger_plugin_hook('creating', 'river', null, $values); |
||
106 | if ($values == false) { |
||
107 | // inserting did not fail - it was just prevented |
||
108 | return true; |
||
109 | } |
||
110 | |||
111 | $dbprefix = elgg_get_config('dbprefix'); |
||
112 | |||
113 | // escape values array and build INSERT assignments |
||
114 | $assignments = array(); |
||
115 | foreach ($col_types as $name => $type) { |
||
116 | $values[$name] = ($type === 'int') ? (int)$values[$name] : sanitize_string($values[$name]); |
||
117 | $assignments[] = "$name = '{$values[$name]}'"; |
||
118 | } |
||
119 | |||
120 | $id = insert_data("INSERT INTO {$dbprefix}river SET " . implode(',', $assignments)); |
||
121 | |||
122 | // update the entities which had the action carried out on it |
||
123 | // @todo shouldn't this be done elsewhere? Like when an annotation is saved? |
||
124 | if ($id) { |
||
0 ignored issues
–
show
|
|||
125 | update_entity_last_action($values['object_guid'], $values['posted']); |
||
126 | |||
127 | $river_items = elgg_get_river(array('id' => $id)); |
||
128 | if ($river_items) { |
||
129 | elgg_trigger_event('created', 'river', $river_items[0]); |
||
130 | } |
||
131 | return $id; |
||
132 | } else { |
||
133 | return false; |
||
134 | } |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Delete river items |
||
139 | * |
||
140 | * @warning not checking access (should we?) |
||
141 | * |
||
142 | * @param array $options Parameters: |
||
143 | * ids => INT|ARR River item id(s) |
||
144 | * subject_guids => INT|ARR Subject guid(s) |
||
145 | * object_guids => INT|ARR Object guid(s) |
||
146 | * target_guids => INT|ARR Target guid(s) |
||
147 | * annotation_ids => INT|ARR The identifier of the annotation(s) |
||
148 | * action_types => STR|ARR The river action type(s) identifier |
||
149 | * views => STR|ARR River view(s) |
||
150 | * |
||
151 | * types => STR|ARR Entity type string(s) |
||
152 | * subtypes => STR|ARR Entity subtype string(s) |
||
153 | * type_subtype_pairs => ARR Array of type => subtype pairs where subtype |
||
154 | * can be an array of subtype strings |
||
155 | * |
||
156 | * posted_time_lower => INT The lower bound on the time posted |
||
157 | * posted_time_upper => INT The upper bound on the time posted |
||
158 | * |
||
159 | * @return bool |
||
160 | * @since 1.8.0 |
||
161 | */ |
||
162 | function elgg_delete_river(array $options = array()) { |
||
163 | global $CONFIG; |
||
164 | |||
165 | $defaults = array( |
||
166 | 'ids' => ELGG_ENTITIES_ANY_VALUE, |
||
167 | |||
168 | 'subject_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
169 | 'object_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
170 | 'target_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
171 | 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, |
||
172 | |||
173 | 'views' => ELGG_ENTITIES_ANY_VALUE, |
||
174 | 'action_types' => ELGG_ENTITIES_ANY_VALUE, |
||
175 | |||
176 | 'types' => ELGG_ENTITIES_ANY_VALUE, |
||
177 | 'subtypes' => ELGG_ENTITIES_ANY_VALUE, |
||
178 | 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, |
||
179 | |||
180 | 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
||
181 | 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
||
182 | |||
183 | 'wheres' => array(), |
||
184 | 'joins' => array(), |
||
185 | |||
186 | ); |
||
187 | |||
188 | $options = array_merge($defaults, $options); |
||
189 | |||
190 | $singulars = array('id', 'subject_guid', 'object_guid', 'target_guid', 'annotation_id', 'action_type', 'view', 'type', 'subtype'); |
||
191 | $options = _elgg_normalize_plural_options_array($options, $singulars); |
||
192 | |||
193 | $wheres = $options['wheres']; |
||
194 | |||
195 | $wheres[] = _elgg_get_guid_based_where_sql('rv.id', $options['ids']); |
||
196 | $wheres[] = _elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']); |
||
197 | $wheres[] = _elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']); |
||
198 | $wheres[] = _elgg_get_guid_based_where_sql('rv.target_guid', $options['target_guids']); |
||
199 | $wheres[] = _elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']); |
||
200 | $wheres[] = _elgg_river_get_action_where_sql($options['action_types']); |
||
201 | $wheres[] = _elgg_river_get_view_where_sql($options['views']); |
||
202 | $wheres[] = _elgg_get_river_type_subtype_where_sql('rv', $options['types'], |
||
203 | $options['subtypes'], $options['type_subtype_pairs']); |
||
204 | |||
205 | View Code Duplication | if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) { |
|
206 | $wheres[] = "rv.posted >= {$options['posted_time_lower']}"; |
||
207 | } |
||
208 | |||
209 | View Code Duplication | if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) { |
|
210 | $wheres[] = "rv.posted <= {$options['posted_time_upper']}"; |
||
211 | } |
||
212 | |||
213 | // see if any functions failed |
||
214 | // remove empty strings on successful functions |
||
215 | View Code Duplication | foreach ($wheres as $i => $where) { |
|
216 | if ($where === false) { |
||
217 | return false; |
||
218 | } elseif (empty($where)) { |
||
219 | unset($wheres[$i]); |
||
220 | } |
||
221 | } |
||
222 | |||
223 | // remove identical where clauses |
||
224 | $wheres = array_unique($wheres); |
||
225 | |||
226 | $query = "DELETE rv.* FROM {$CONFIG->dbprefix}river rv "; |
||
227 | |||
228 | // remove identical join clauses |
||
229 | $joins = array_unique($options['joins']); |
||
230 | |||
231 | // add joins |
||
232 | foreach ($joins as $j) { |
||
233 | $query .= " $j "; |
||
234 | } |
||
235 | |||
236 | // add wheres |
||
237 | $query .= ' WHERE '; |
||
238 | |||
239 | foreach ($wheres as $w) { |
||
240 | $query .= " $w AND "; |
||
241 | } |
||
242 | $query .= "1=1"; |
||
243 | |||
244 | return delete_data($query); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Get river items |
||
249 | * |
||
250 | * @note If using types and subtypes in a query, they are joined with an AND. |
||
251 | * |
||
252 | * @param array $options Parameters: |
||
253 | * ids => INT|ARR River item id(s) |
||
254 | * subject_guids => INT|ARR Subject guid(s) |
||
255 | * object_guids => INT|ARR Object guid(s) |
||
256 | * target_guids => INT|ARR Target guid(s) |
||
257 | * annotation_ids => INT|ARR The identifier of the annotation(s) |
||
258 | * action_types => STR|ARR The river action type(s) identifier |
||
259 | * posted_time_lower => INT The lower bound on the time posted |
||
260 | * posted_time_upper => INT The upper bound on the time posted |
||
261 | * |
||
262 | * types => STR|ARR Entity type string(s) |
||
263 | * subtypes => STR|ARR Entity subtype string(s) |
||
264 | * type_subtype_pairs => ARR Array of type => subtype pairs where subtype |
||
265 | * can be an array of subtype strings |
||
266 | * |
||
267 | * relationship => STR Relationship identifier |
||
268 | * relationship_guid => INT|ARR Entity guid(s) |
||
269 | * inverse_relationship => BOOL Subject or object of the relationship (false) |
||
270 | * |
||
271 | * limit => INT Number to show per page (20) |
||
272 | * offset => INT Offset in list (0) |
||
273 | * count => BOOL Count the river items? (false) |
||
274 | * order_by => STR Order by clause (rv.posted desc) |
||
275 | * group_by => STR Group by clause |
||
276 | * |
||
277 | * distinct => BOOL If set to false, Elgg will drop the DISTINCT |
||
278 | * clause from the MySQL query, which will improve |
||
279 | * performance in some situations. Avoid setting this |
||
280 | * option without a full understanding of the |
||
281 | * underlying SQL query Elgg creates. (true) |
||
282 | * |
||
283 | * @return array|int |
||
284 | * @since 1.8.0 |
||
285 | */ |
||
286 | function elgg_get_river(array $options = array()) { |
||
287 | global $CONFIG; |
||
288 | |||
289 | $defaults = array( |
||
290 | 'ids' => ELGG_ENTITIES_ANY_VALUE, |
||
291 | |||
292 | 'subject_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
293 | 'object_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
294 | 'target_guids' => ELGG_ENTITIES_ANY_VALUE, |
||
295 | 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, |
||
296 | 'action_types' => ELGG_ENTITIES_ANY_VALUE, |
||
297 | |||
298 | 'relationship' => null, |
||
299 | 'relationship_guid' => null, |
||
300 | 'inverse_relationship' => false, |
||
301 | |||
302 | 'types' => ELGG_ENTITIES_ANY_VALUE, |
||
303 | 'subtypes' => ELGG_ENTITIES_ANY_VALUE, |
||
304 | 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE, |
||
305 | |||
306 | 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE, |
||
307 | 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE, |
||
308 | |||
309 | 'limit' => 20, |
||
310 | 'offset' => 0, |
||
311 | 'count' => false, |
||
312 | 'distinct' => false, |
||
313 | |||
314 | 'order_by' => 'rv.posted desc', |
||
315 | 'group_by' => ELGG_ENTITIES_ANY_VALUE, |
||
316 | |||
317 | 'wheres' => array(), |
||
318 | 'joins' => array(), |
||
319 | ); |
||
320 | |||
321 | $options = array_merge($defaults, $options); |
||
322 | |||
323 | $singulars = array('id', 'subject_guid', 'object_guid', 'target_guid', 'annotation_id', 'action_type', 'type', 'subtype'); |
||
324 | $options = _elgg_normalize_plural_options_array($options, $singulars); |
||
325 | |||
326 | $wheres = $options['wheres']; |
||
327 | |||
328 | $wheres[] = _elgg_get_guid_based_where_sql('rv.id', $options['ids']); |
||
329 | $wheres[] = _elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']); |
||
330 | $wheres[] = _elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']); |
||
331 | $wheres[] = _elgg_get_guid_based_where_sql('rv.target_guid', $options['target_guids']); |
||
332 | $wheres[] = _elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']); |
||
333 | $wheres[] = _elgg_river_get_action_where_sql($options['action_types']); |
||
334 | $wheres[] = _elgg_get_river_type_subtype_where_sql('rv', $options['types'], |
||
335 | $options['subtypes'], $options['type_subtype_pairs']); |
||
336 | |||
337 | View Code Duplication | if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) { |
|
338 | $wheres[] = "rv.posted >= {$options['posted_time_lower']}"; |
||
339 | } |
||
340 | |||
341 | View Code Duplication | if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) { |
|
342 | $wheres[] = "rv.posted <= {$options['posted_time_upper']}"; |
||
343 | } |
||
344 | |||
345 | if (!access_get_show_hidden_status()) { |
||
346 | $wheres[] = "rv.enabled = 'yes'"; |
||
347 | } |
||
348 | |||
349 | $joins = $options['joins']; |
||
350 | |||
351 | $dbprefix = elgg_get_config('dbprefix'); |
||
352 | |||
353 | // joins |
||
354 | $joins = array(); |
||
355 | $joins[] = "JOIN {$dbprefix}entities oe ON rv.object_guid = oe.guid"; |
||
356 | |||
357 | // LEFT JOIN is used because all river items do not necessarily have target |
||
358 | $joins[] = "LEFT JOIN {$dbprefix}entities te ON rv.target_guid = te.guid"; |
||
359 | |||
360 | if ($options['relationship_guid']) { |
||
361 | $clauses = elgg_get_entity_relationship_where_sql( |
||
362 | 'rv.subject_guid', |
||
363 | $options['relationship'], |
||
364 | $options['relationship_guid'], |
||
365 | $options['inverse_relationship']); |
||
366 | if ($clauses) { |
||
367 | $wheres = array_merge($wheres, $clauses['wheres']); |
||
368 | $joins = array_merge($joins, $clauses['joins']); |
||
369 | } |
||
370 | } |
||
371 | |||
372 | // add optional joins |
||
373 | $joins = array_merge($joins, $options['joins']); |
||
374 | |||
375 | // see if any functions failed |
||
376 | // remove empty strings on successful functions |
||
377 | View Code Duplication | foreach ($wheres as $i => $where) { |
|
378 | if ($where === false) { |
||
379 | return false; |
||
380 | } elseif (empty($where)) { |
||
381 | unset($wheres[$i]); |
||
382 | } |
||
383 | } |
||
384 | |||
385 | // remove identical where clauses |
||
386 | $wheres = array_unique($wheres); |
||
387 | |||
388 | View Code Duplication | if (!$options['count']) { |
|
389 | $distinct = $options['distinct'] ? "DISTINCT" : ""; |
||
390 | |||
391 | $query = "SELECT $distinct rv.* FROM {$CONFIG->dbprefix}river rv "; |
||
392 | } else { |
||
393 | // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than IDs |
||
394 | $count_expr = $options['distinct'] ? "DISTINCT rv.id" : "*"; |
||
395 | |||
396 | $query = "SELECT COUNT($count_expr) as total FROM {$CONFIG->dbprefix}river rv "; |
||
397 | } |
||
398 | |||
399 | // add joins |
||
400 | foreach ($joins as $j) { |
||
401 | $query .= " $j "; |
||
402 | } |
||
403 | |||
404 | // add wheres |
||
405 | $query .= ' WHERE '; |
||
406 | |||
407 | foreach ($wheres as $w) { |
||
408 | $query .= " $w AND "; |
||
409 | } |
||
410 | |||
411 | // Make sure that user has access to all the entities referenced by each river item |
||
412 | $object_access_where = _elgg_get_access_where_sql(array('table_alias' => 'oe')); |
||
413 | $target_access_where = _elgg_get_access_where_sql(array('table_alias' => 'te')); |
||
414 | |||
415 | // We use LEFT JOIN with entities table but the WHERE clauses are used |
||
416 | // regardless if a JOIN is successfully made. The "te.guid IS NULL" is |
||
417 | // needed because of this. |
||
418 | $query .= "$object_access_where AND ($target_access_where OR te.guid IS NULL) "; |
||
419 | |||
420 | if (!$options['count']) { |
||
421 | $options['group_by'] = sanitise_string($options['group_by']); |
||
422 | if ($options['group_by']) { |
||
423 | $query .= " GROUP BY {$options['group_by']}"; |
||
424 | } |
||
425 | |||
426 | $options['order_by'] = sanitise_string($options['order_by']); |
||
427 | $query .= " ORDER BY {$options['order_by']}"; |
||
428 | |||
429 | View Code Duplication | if ($options['limit']) { |
|
430 | $limit = sanitise_int($options['limit']); |
||
431 | $offset = sanitise_int($options['offset'], false); |
||
432 | $query .= " LIMIT $offset, $limit"; |
||
433 | } |
||
434 | |||
435 | $river_items = get_data($query, '_elgg_row_to_elgg_river_item'); |
||
436 | _elgg_prefetch_river_entities($river_items); |
||
437 | |||
438 | return $river_items; |
||
439 | } else { |
||
440 | $total = get_data_row($query); |
||
441 | return (int)$total->total; |
||
442 | } |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * Prefetch entities that will be displayed in the river. |
||
447 | * |
||
448 | * @param \ElggRiverItem[] $river_items |
||
449 | * @access private |
||
450 | */ |
||
451 | function _elgg_prefetch_river_entities(array $river_items) { |
||
452 | // prefetch objects, subjects and targets |
||
453 | $guids = array(); |
||
454 | foreach ($river_items as $item) { |
||
455 | if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) { |
||
456 | $guids[$item->subject_guid] = true; |
||
457 | } |
||
458 | if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) { |
||
459 | $guids[$item->object_guid] = true; |
||
460 | } |
||
461 | if ($item->target_guid && !_elgg_retrieve_cached_entity($item->target_guid)) { |
||
462 | $guids[$item->target_guid] = true; |
||
463 | } |
||
464 | } |
||
465 | View Code Duplication | if ($guids) { |
|
0 ignored issues
–
show
The expression
$guids of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
466 | // The entity cache only holds 256. We don't want to bump out any plugins. |
||
467 | $guids = array_slice($guids, 0, 200, true); |
||
468 | // return value unneeded, just priming cache |
||
469 | elgg_get_entities(array( |
||
470 | 'guids' => array_keys($guids), |
||
471 | 'limit' => 0, |
||
472 | 'distinct' => false, |
||
473 | )); |
||
474 | } |
||
475 | |||
476 | // prefetch object containers, in case they were not in the targets |
||
477 | $guids = array(); |
||
478 | foreach ($river_items as $item) { |
||
479 | $object = $item->getObjectEntity(); |
||
480 | if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) { |
||
481 | $guids[$object->container_guid] = true; |
||
482 | } |
||
483 | } |
||
484 | View Code Duplication | if ($guids) { |
|
0 ignored issues
–
show
The expression
$guids of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
485 | $guids = array_slice($guids, 0, 200, true); |
||
486 | elgg_get_entities(array( |
||
487 | 'guids' => array_keys($guids), |
||
488 | 'limit' => 0, |
||
489 | 'distinct' => false, |
||
490 | |||
491 | // Why specify? user containers are likely already loaded via the owners, and |
||
492 | // specifying groups allows ege() to auto-join the groups_entity table |
||
493 | 'type' => 'group', |
||
494 | )); |
||
495 | } |
||
496 | |||
497 | // Note: We've tried combining the above ege() calls into one (pulling containers at the same time). |
||
498 | // Although it seems like it would reduce queries, it added some. o_O |
||
499 | } |
||
500 | |||
501 | /** |
||
502 | * List river items |
||
503 | * |
||
504 | * @param array $options Any options from elgg_get_river() plus: |
||
505 | * item_view => STR Alternative view to render list items |
||
506 | * pagination => BOOL Display pagination links (true) |
||
507 | * no_results => STR|Closure Message to display if no items |
||
508 | * |
||
509 | * @return string |
||
510 | * @since 1.8.0 |
||
511 | */ |
||
512 | function elgg_list_river(array $options = array()) { |
||
513 | global $autofeed; |
||
514 | $autofeed = true; |
||
515 | |||
516 | $defaults = array( |
||
517 | 'offset' => (int) max(get_input('offset', 0), 0), |
||
518 | 'limit' => (int) max(get_input('limit', max(20, elgg_get_config('default_limit'))), 0), |
||
519 | 'pagination' => true, |
||
520 | 'list_class' => 'elgg-list-river', |
||
521 | 'no_results' => '', |
||
522 | ); |
||
523 | |||
524 | $options = array_merge($defaults, $options); |
||
525 | |||
526 | View Code Duplication | if (!$options["limit"] && !$options["offset"]) { |
|
527 | // no need for pagination if listing is unlimited |
||
528 | $options["pagination"] = false; |
||
529 | } |
||
530 | |||
531 | $options['count'] = true; |
||
532 | $count = elgg_get_river($options); |
||
533 | |||
534 | if ($count > 0) { |
||
535 | $options['count'] = false; |
||
536 | $items = elgg_get_river($options); |
||
537 | } else { |
||
538 | $items = array(); |
||
539 | } |
||
540 | |||
541 | $options['count'] = $count; |
||
542 | $options['items'] = $items; |
||
543 | |||
544 | return elgg_view('page/components/list', $options); |
||
545 | } |
||
546 | |||
547 | /** |
||
548 | * Convert a database row to a new \ElggRiverItem |
||
549 | * |
||
550 | * @param \stdClass $row Database row from the river table |
||
551 | * |
||
552 | * @return \ElggRiverItem |
||
553 | * @since 1.8.0 |
||
554 | * @access private |
||
555 | */ |
||
556 | function _elgg_row_to_elgg_river_item($row) { |
||
557 | if (!($row instanceof \stdClass)) { |
||
558 | return null; |
||
559 | } |
||
560 | |||
561 | return new \ElggRiverItem($row); |
||
562 | } |
||
563 | |||
564 | /** |
||
565 | * Returns SQL where clause for type and subtype on river table |
||
566 | * |
||
567 | * @internal This is a simplified version of elgg_get_entity_type_subtype_where_sql() |
||
568 | * which could be used for all queries once the subtypes have been denormalized. |
||
569 | * |
||
570 | * @param string $table 'rv' |
||
571 | * @param null|array $types Array of types or null if none. |
||
572 | * @param null|array $subtypes Array of subtypes or null if none |
||
573 | * @param null|array $pairs Array of pairs of types and subtypes |
||
574 | * |
||
575 | * @return string |
||
576 | * @since 1.8.0 |
||
577 | * @access private |
||
578 | */ |
||
579 | function _elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs) { |
||
580 | // short circuit if nothing is requested |
||
581 | if (!$types && !$subtypes && !$pairs) { |
||
582 | return ''; |
||
583 | } |
||
584 | |||
585 | $wheres = array(); |
||
586 | $types_wheres = array(); |
||
587 | $subtypes_wheres = array(); |
||
588 | |||
589 | // if no pairs, use types and subtypes |
||
590 | if (!is_array($pairs)) { |
||
591 | if ($types) { |
||
592 | if (!is_array($types)) { |
||
593 | $types = array($types); |
||
594 | } |
||
595 | foreach ($types as $type) { |
||
596 | $type = sanitise_string($type); |
||
597 | $types_wheres[] = "({$table}.type = '$type')"; |
||
598 | } |
||
599 | } |
||
600 | |||
601 | if ($subtypes) { |
||
602 | if (!is_array($subtypes)) { |
||
603 | $subtypes = array($subtypes); |
||
604 | } |
||
605 | foreach ($subtypes as $subtype) { |
||
606 | $subtype = sanitise_string($subtype); |
||
607 | $subtypes_wheres[] = "({$table}.subtype = '$subtype')"; |
||
608 | } |
||
609 | } |
||
610 | |||
611 | if (is_array($types_wheres) && count($types_wheres)) { |
||
612 | $types_wheres = array(implode(' OR ', $types_wheres)); |
||
613 | } |
||
614 | |||
615 | if (is_array($subtypes_wheres) && count($subtypes_wheres)) { |
||
616 | $subtypes_wheres = array('(' . implode(' OR ', $subtypes_wheres) . ')'); |
||
617 | } |
||
618 | |||
619 | $wheres = array(implode(' AND ', array_merge($types_wheres, $subtypes_wheres))); |
||
620 | |||
621 | } else { |
||
622 | // using type/subtype pairs |
||
623 | foreach ($pairs as $paired_type => $paired_subtypes) { |
||
624 | $paired_type = sanitise_string($paired_type); |
||
625 | if (is_array($paired_subtypes)) { |
||
626 | $paired_subtypes = array_map('sanitise_string', $paired_subtypes); |
||
627 | $paired_subtype_str = implode("','", $paired_subtypes); |
||
628 | if ($paired_subtype_str) { |
||
629 | $wheres[] = "({$table}.type = '$paired_type'" |
||
630 | . " AND {$table}.subtype IN ('$paired_subtype_str'))"; |
||
631 | } |
||
632 | } else { |
||
633 | $paired_subtype = sanitise_string($paired_subtypes); |
||
634 | $wheres[] = "({$table}.type = '$paired_type'" |
||
635 | . " AND {$table}.subtype = '$paired_subtype')"; |
||
636 | } |
||
637 | } |
||
638 | } |
||
639 | |||
640 | View Code Duplication | if (is_array($wheres) && count($wheres)) { |
|
641 | $where = implode(' OR ', $wheres); |
||
642 | return "($where)"; |
||
643 | } |
||
644 | |||
645 | return ''; |
||
646 | } |
||
647 | |||
648 | /** |
||
649 | * Get the where clause based on river action type strings |
||
650 | * |
||
651 | * @param array $types Array of action type strings |
||
652 | * |
||
653 | * @return string |
||
654 | * @since 1.8.0 |
||
655 | * @access private |
||
656 | */ |
||
657 | View Code Duplication | function _elgg_river_get_action_where_sql($types) { |
|
658 | if (!$types) { |
||
0 ignored issues
–
show
The expression
$types of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
659 | return ''; |
||
660 | } |
||
661 | |||
662 | if (!is_array($types)) { |
||
663 | $types = sanitise_string($types); |
||
664 | return "(rv.action_type = '$types')"; |
||
665 | } |
||
666 | |||
667 | // sanitize types array |
||
668 | $types_sanitized = array(); |
||
669 | foreach ($types as $type) { |
||
670 | $types_sanitized[] = sanitise_string($type); |
||
671 | } |
||
672 | |||
673 | $type_str = implode("','", $types_sanitized); |
||
674 | return "(rv.action_type IN ('$type_str'))"; |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * Get the where clause based on river view strings |
||
679 | * |
||
680 | * @param array $views Array of view strings |
||
681 | * |
||
682 | * @return string |
||
683 | * @since 1.8.0 |
||
684 | * @access private |
||
685 | */ |
||
686 | View Code Duplication | function _elgg_river_get_view_where_sql($views) { |
|
687 | if (!$views) { |
||
0 ignored issues
–
show
The expression
$views of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
688 | return ''; |
||
689 | } |
||
690 | |||
691 | if (!is_array($views)) { |
||
692 | $views = sanitise_string($views); |
||
693 | return "(rv.view = '$views')"; |
||
694 | } |
||
695 | |||
696 | // sanitize views array |
||
697 | $views_sanitized = array(); |
||
698 | foreach ($views as $view) { |
||
699 | $views_sanitized[] = sanitise_string($view); |
||
700 | } |
||
701 | |||
702 | $view_str = implode("','", $views_sanitized); |
||
703 | return "(rv.view IN ('$view_str'))"; |
||
704 | } |
||
705 | |||
706 | /** |
||
707 | * Sets the access ID on river items for a particular object |
||
708 | * |
||
709 | * @param int $object_guid The GUID of the entity |
||
710 | * @param int $access_id The access ID |
||
711 | * |
||
712 | * @return bool Depending on success |
||
713 | */ |
||
714 | function update_river_access_by_object($object_guid, $access_id) { |
||
715 | // Sanitise |
||
716 | $object_guid = (int) $object_guid; |
||
717 | $access_id = (int) $access_id; |
||
718 | |||
719 | // Load config |
||
720 | global $CONFIG; |
||
721 | |||
722 | $query = "UPDATE {$CONFIG->dbprefix}river |
||
723 | SET access_id = {$access_id} |
||
724 | WHERE object_guid = {$object_guid}"; |
||
725 | return update_data($query); |
||
726 | } |
||
727 | |||
728 | /** |
||
729 | * Page handler for activity |
||
730 | * |
||
731 | * @param array $page |
||
732 | * @return bool |
||
733 | * @access private |
||
734 | */ |
||
735 | function _elgg_river_page_handler($page) { |
||
736 | global $CONFIG; |
||
737 | |||
738 | elgg_set_page_owner_guid(elgg_get_logged_in_user_guid()); |
||
739 | |||
740 | // make a URL segment available in page handler script |
||
741 | $page_type = elgg_extract(0, $page, 'all'); |
||
742 | $page_type = preg_replace('[\W]', '', $page_type); |
||
743 | View Code Duplication | if ($page_type == 'owner') { |
|
744 | elgg_gatekeeper(); |
||
745 | $page_username = elgg_extract(1, $page, ''); |
||
746 | if ($page_username == elgg_get_logged_in_user_entity()->username) { |
||
747 | $page_type = 'mine'; |
||
748 | } else { |
||
749 | set_input('subject_username', $page_username); |
||
750 | } |
||
751 | } |
||
752 | set_input('page_type', $page_type); |
||
753 | |||
754 | require_once("{$CONFIG->path}pages/river.php"); |
||
755 | return true; |
||
756 | } |
||
757 | |||
758 | /** |
||
759 | * Register river unit tests |
||
760 | * @access private |
||
761 | */ |
||
762 | function _elgg_river_test($hook, $type, $value) { |
||
763 | global $CONFIG; |
||
764 | $value[] = $CONFIG->path . 'engine/tests/ElggCoreRiverAPITest.php'; |
||
765 | return $value; |
||
766 | } |
||
767 | |||
768 | /** |
||
769 | * Disable river entries that reference a disabled entity as subject/object/target |
||
770 | * |
||
771 | * @param string $event The event 'disable' |
||
772 | * @param string $type Type of entity being disabled 'all' |
||
773 | * @param mixed $entity The entity being disabled |
||
774 | * @return boolean |
||
775 | * @access private |
||
776 | */ |
||
777 | function _elgg_river_disable($event, $type, $entity) { |
||
778 | |||
779 | if (!elgg_instanceof($entity)) { |
||
780 | return true; |
||
781 | } |
||
782 | |||
783 | $dbprefix = elgg_get_config('dbprefix'); |
||
784 | $query = <<<QUERY |
||
785 | UPDATE {$dbprefix}river AS rv |
||
786 | SET rv.enabled = 'no' |
||
787 | WHERE (rv.subject_guid = {$entity->guid} OR rv.object_guid = {$entity->guid} OR rv.target_guid = {$entity->guid}); |
||
788 | QUERY; |
||
789 | |||
790 | update_data($query); |
||
791 | return true; |
||
792 | } |
||
793 | |||
794 | /* |
||
795 | * GC_MODIFICATION |
||
796 | * Description: Split into 3 queries in order to not use ORs in (se.guid = {$entity->guid} OR oe.guid = {$entity->guid} OR te.guid = {$entity->guid}), this allows it to not use indexes and greatly speeds up execution |
||
797 | * Author: Ilia github.com/Phanoix [email protected] |
||
798 | * Date: 24/01/2017 |
||
799 | * Pull Request #734 |
||
800 | */ |
||
801 | /** |
||
802 | * Enable river entries that reference a re-enabled entity as subject/object/target |
||
803 | * |
||
804 | * @param string $event The event 'enable' |
||
805 | * @param string $type Type of entity being enabled 'all' |
||
806 | * @param mixed $entity The entity being enabled |
||
807 | * @return boolean |
||
808 | * @access private |
||
809 | */ |
||
810 | function _elgg_river_enable($event, $type, $entity) { |
||
811 | |||
812 | if (!elgg_instanceof($entity)) { |
||
813 | return true; |
||
814 | } |
||
815 | |||
816 | $dbprefix = elgg_get_config('dbprefix'); |
||
817 | $query1 = <<<QUERY |
||
818 | UPDATE {$dbprefix}river AS rv |
||
819 | LEFT JOIN {$dbprefix}entities AS se ON se.guid = rv.subject_guid |
||
820 | LEFT JOIN {$dbprefix}entities AS oe ON oe.guid = rv.object_guid |
||
821 | LEFT JOIN {$dbprefix}entities AS te ON te.guid = rv.target_guid |
||
822 | SET rv.enabled = 'yes' |
||
823 | WHERE ( |
||
824 | (se.enabled = 'yes' OR se.guid IS NULL) AND |
||
825 | (oe.enabled = 'yes' OR oe.guid IS NULL) AND |
||
826 | (te.enabled = 'yes' OR te.guid IS NULL) |
||
827 | ) |
||
828 | AND se.guid = {$entity->guid}; |
||
829 | QUERY; |
||
830 | |||
831 | $query2 = <<<QUERY |
||
832 | UPDATE {$dbprefix}river AS rv |
||
833 | LEFT JOIN {$dbprefix}entities AS se ON se.guid = rv.subject_guid |
||
834 | LEFT JOIN {$dbprefix}entities AS oe ON oe.guid = rv.object_guid |
||
835 | LEFT JOIN {$dbprefix}entities AS te ON te.guid = rv.target_guid |
||
836 | SET rv.enabled = 'yes' |
||
837 | WHERE ( |
||
838 | (se.enabled = 'yes' OR se.guid IS NULL) AND |
||
839 | (oe.enabled = 'yes' OR oe.guid IS NULL) AND |
||
840 | (te.enabled = 'yes' OR te.guid IS NULL) |
||
841 | ) |
||
842 | AND oe.guid = {$entity->guid}; |
||
843 | QUERY; |
||
844 | |||
845 | $query3 = <<<QUERY |
||
846 | UPDATE {$dbprefix}river AS rv |
||
847 | LEFT JOIN {$dbprefix}entities AS se ON se.guid = rv.subject_guid |
||
848 | LEFT JOIN {$dbprefix}entities AS oe ON oe.guid = rv.object_guid |
||
849 | LEFT JOIN {$dbprefix}entities AS te ON te.guid = rv.target_guid |
||
850 | SET rv.enabled = 'yes' |
||
851 | WHERE ( |
||
852 | (se.enabled = 'yes' OR se.guid IS NULL) AND |
||
853 | (oe.enabled = 'yes' OR oe.guid IS NULL) AND |
||
854 | (te.enabled = 'yes' OR te.guid IS NULL) |
||
855 | ) |
||
856 | AND te.guid = {$entity->guid}; |
||
857 | QUERY; |
||
858 | |||
859 | update_data($query1); |
||
860 | update_data($query2); |
||
861 | update_data($query3); |
||
862 | return true; |
||
863 | } |
||
864 | |||
865 | /** |
||
866 | * Initialize river library |
||
867 | * @access private |
||
868 | */ |
||
869 | function _elgg_river_init() { |
||
870 | elgg_register_page_handler('activity', '_elgg_river_page_handler'); |
||
871 | $item = new \ElggMenuItem('activity', elgg_echo('activity'), 'activity'); |
||
872 | elgg_register_menu_item('site', $item); |
||
873 | |||
874 | elgg_register_widget_type('river_widget', elgg_echo('river:widget:title'), elgg_echo('river:widget:description')); |
||
875 | |||
876 | elgg_register_action('river/delete', '', 'admin'); |
||
877 | |||
878 | elgg_register_plugin_hook_handler('unit_test', 'system', '_elgg_river_test'); |
||
879 | } |
||
880 | |||
881 | return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
||
882 | $events->registerHandler('init', 'system', '_elgg_river_init'); |
||
883 | $events->registerHandler('disable:after', 'all', '_elgg_river_disable'); |
||
884 | $events->registerHandler('enable:after', 'all', '_elgg_river_enable'); |
||
885 | }; |
||
886 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
integer
values, zero is a special case, in particular the following results might be unexpected: