Issues (2473)

Branch: master

Security Analysis    no vulnerabilities found

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

engine/lib/views.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
1
<?php
2
/**
3
 * Elgg's view system.
4
 *
5
 * The view system is the primary templating engine in Elgg and renders
6
 * all output.  Views are short, parameterised PHP scripts for displaying
7
 * output that can be regsitered, overridden, or extended.  The view type
8
 * determines the output format and location of the files that renders the view.
9
 *
10
 * Elgg uses a two step process to render full output: first
11
 * content-specific elements are rendered, then the resulting
12
 * content is inserted into a layout and displayed.  This makes it
13
 * easy to maintain a consistent look on all pages.
14
 *
15
 * A view corresponds to a single file on the filesystem and the views
16
 * name is its directory structure.  A file in
17
 * <code>mod/plugins/views/default/myplugin/example.php</code>
18
 * is called by saying (with the default viewtype):
19
 * <code>echo elgg_view('myplugin/example');</code>
20
 *
21
 * View names that are registered later override those that are
22
 * registered earlier.  For plugins this corresponds directly
23
 * to their load order: views in plugins lower in the list override
24
 * those higher in the list.
25
 *
26
 * Plugin views belong in the views/ directory under an appropriate
27
 * viewtype.  Views are automatically registered.
28
 *
29
 * Views can be embedded-you can call a view from within a view.
30
 * Views can also be prepended or extended by any other view.
31
 *
32
 * Any view can extend any other view if registered with
33
 * {@link elgg_extend_view()}.
34
 *
35
 * Viewtypes are set by passing $_REQUEST['view'].  The viewtype
36
 * 'default' is a standard HTML view.  Types can be defined on the fly
37
 * and you can get the current viewtype with {@link elgg_get_viewtype()}.
38
 *
39
 * @note Internal: Plugin views are autoregistered before their init functions
40
 * are called, so the init order doesn't affect views.
41
 *
42
 * @note Internal: The file that determines the output of the view is the last
43
 * registered by {@link elgg_set_view_location()}.
44
 *
45
 * @package Elgg.Core
46
 * @subpackage Views
47
 */
48
49
/**
50
 * The viewtype override.
51
 *
52
 * @global string $CURRENT_SYSTEM_VIEWTYPE
53
 * @see elgg_set_viewtype()
54
 */
55
global $CURRENT_SYSTEM_VIEWTYPE;
56
$CURRENT_SYSTEM_VIEWTYPE = "";
57
58
/**
59
 * Manually set the viewtype.
60
 *
61
 * View types are detected automatically.  This function allows
62
 * you to force subsequent views to use a different viewtype.
63
 *
64
 * @tip Call elgg_set_viewtype() with no parameter to reset.
65
 *
66
 * @param string $viewtype The view type, e.g. 'rss', or 'default'.
67
 *
68
 * @return bool
69
 */
70
function elgg_set_viewtype($viewtype = "") {
71 1
	global $CURRENT_SYSTEM_VIEWTYPE;
72
73 1
	$CURRENT_SYSTEM_VIEWTYPE = $viewtype;
74
75 1
	return true;
76
}
77
78
/**
79
 * Return the current view type.
80
 *
81
 * Viewtypes are automatically detected and can be set with $_REQUEST['view']
82
 * or {@link elgg_set_viewtype()}.
83
 *
84
 * @note Internal: Viewtype is determined in this order:
85
 *  - $CURRENT_SYSTEM_VIEWTYPE Any overrides by {@link elgg_set_viewtype()}
86
 *  - $CONFIG->view  The default view as saved in the DB.
87
 *
88
 * @return string The view.
89
 * @see elgg_set_viewtype()
90
 */
91
function elgg_get_viewtype() {
92 10
	global $CURRENT_SYSTEM_VIEWTYPE, $CONFIG;
93
94 10
	if ($CURRENT_SYSTEM_VIEWTYPE != "") {
95 1
		return $CURRENT_SYSTEM_VIEWTYPE;
96
	}
97
98 9
	$viewtype = get_input('view', '', false);
99 9
	if (_elgg_is_valid_viewtype($viewtype)) {
100 1
		return $viewtype;
101
	}
102
103 9
	if (isset($CONFIG->view) && _elgg_is_valid_viewtype($CONFIG->view)) {
104
		return $CONFIG->view;
105
	}
106
107 9
	return 'default';
108
}
109
110
/**
111
 * Register a viewtype.
112
 *
113
 * @param string $viewtype The view type to register
114
 * @return bool
115
 */
116
function elgg_register_viewtype($viewtype) {
117
	global $CONFIG;
118
119
	if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
120
		$CONFIG->view_types = array();
121
	}
122
123
	if (!in_array($viewtype, $CONFIG->view_types)) {
124
		$CONFIG->view_types[] = $viewtype;
125
	}
126
127
	return true;
128
}
129
130
/**
131
 * Checks if $viewtype is registered.
132
 *
133
 * @param string $viewtype The viewtype name
134
 *
135
 * @return bool
136
 * @since 1.9.0
137
 */
138
function elgg_is_registered_viewtype($viewtype) {
139
	global $CONFIG;
140
141
	if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
142
		return false;
143
	}
144
145
	return in_array($viewtype, $CONFIG->view_types);
146
}
147
148
149
/**
150
 * Checks if $viewtype is a string suitable for use as a viewtype name
151
 *
152
 * @param string $viewtype Potential viewtype name. Alphanumeric chars plus _ allowed.
153
 *
154
 * @return bool
155
 * @access private
156
 * @since 1.9
157
 */
158
function _elgg_is_valid_viewtype($viewtype) {
159 11
	if (!is_string($viewtype) || $viewtype === '') {
160 10
		return false;
161
	}
162
163 3
	if (preg_match('/\W/', $viewtype)) {
164 2
		return false;
165
	}
166
167 3
	return true;
168
}
169
170
/**
171
 * Register a viewtype to fall back to a default view if a view isn't
172
 * found for that viewtype.
173
 *
174
 * @tip This is useful for alternate html viewtypes (such as for mobile devices).
175
 *
176
 * @param string $viewtype The viewtype to register
177
 *
178
 * @return void
179
 * @since 1.7.2
180
 */
181
function elgg_register_viewtype_fallback($viewtype) {
182
	_elgg_services()->views->registerViewtypeFallback($viewtype);
183
}
184
185
/**
186
 * Checks if a viewtype falls back to default.
187
 *
188
 * @param string $viewtype Viewtype
189
 *
190
 * @return boolean
191
 * @since 1.7.2
192
 */
193
function elgg_does_viewtype_fallback($viewtype) {
194
	return _elgg_services()->views->doesViewtypeFallback($viewtype);
195
}
196
197
/**
198
 * Register a view to be available for ajax calls
199
 *
200
 * @warning Only views that begin with 'js/' and 'css/' have their content
201
 * type set to 'text/javascript' and 'text/css'. Other views are served as
202
 * 'text/html'.
203
 *
204
 * @param string $view The view name
205
 * @return void
206
 * @since 1.8.3
207
 */
208
function elgg_register_ajax_view($view) {
209
	elgg_register_external_view($view, false);
210
}
211
212
/**
213
 * Unregister a view for ajax calls
214
 *
215
 * @param string $view The view name
216
 * @return void
217
 * @since 1.8.3
218
 */
219
function elgg_unregister_ajax_view($view) {
220
	elgg_unregister_external_view($view);
221
}
222
223
/**
224
 * Registers a view as being available externally (i.e. via URL).
225
 *
226
 * @param string  $view      The name of the view.
227
 * @param boolean $cacheable Whether this view can be cached.
228
 * @return void
229
 * @since 1.9.0
230
 */
231
function elgg_register_external_view($view, $cacheable = false) {
232
	global $CONFIG;
233
234
	if (!isset($CONFIG->allowed_ajax_views)) {
235
		$CONFIG->allowed_ajax_views = array();
236
	}
237
238
	$CONFIG->allowed_ajax_views[$view] = true;
239
240
	if ($cacheable) {
241
		_elgg_services()->views->registerCacheableView($view);
242
	}
243
}
244
245
/**
246
 * Check whether a view is registered as cacheable.
247
 *
248
 * @param string $view The name of the view.
249
 * @return boolean
250
 * @access private
251
 * @since 1.9.0
252
 */
253
function _elgg_is_view_cacheable($view) {
254
	return _elgg_services()->views->isCacheableView($view);
255
}
256
257
/**
258
 * Unregister a view for ajax calls
259
 *
260
 * @param string $view The view name
261
 * @return void
262
 * @since 1.9.0
263
 */
264
function elgg_unregister_external_view($view) {
265
	global $CONFIG;
266
267
	if (isset($CONFIG->allowed_ajax_views[$view])) {
268
		unset($CONFIG->allowed_ajax_views[$view]);
269
	}
270
}
271
272
273
/**
274
 * Set an alternative base location for a view.
275
 *
276
 * Views are expected to be in plugin_name/views/.  This function can
277
 * be used to change that location.
278
 *
279
 * @note Internal: Core view locations are stored in $CONFIG->viewpath.
280
 *
281
 * @tip This is useful to optionally register views in a plugin.
282
 *
283
 * @param string $view     The name of the view
284
 * @param string $location The base location path
285
 * @param string $viewtype The view type
286
 *
287
 * @return void
288
 */
289
function elgg_set_view_location($view, $location, $viewtype = '') {
290
	_elgg_services()->views->setViewLocation($view, $location, $viewtype);
291
}
292
293
/**
294
 * Returns whether the specified view exists
295
 *
296
 * @note If $recurse is true, also checks if a view exists only as an extension.
297
 *
298
 * @param string $view     The view name
299
 * @param string $viewtype If set, forces the viewtype
300
 * @param bool   $recurse  If false, do not check extensions
301
 *
302
 * @return bool
303
 */
304
function elgg_view_exists($view, $viewtype = '', $recurse = true) {
305
	return _elgg_services()->views->viewExists($view, $viewtype, $recurse);
306
}
307
308
/**
309
 * Return a parsed view.
310
 *
311
 * Views are rendered by a template handler and returned as strings.
312
 *
313
 * Views are called with a special $vars variable set,
314
 * which includes any variables passed as the second parameter.
315
 * For backward compatbility, the following variables are also set but we
316
 * recommend that you do not use them:
317
 *  - $vars['config'] The $CONFIG global. (Use {@link elgg_get_config()} instead).
318
 *  - $vars['url'] The site URL. (use {@link elgg_get_site_url()} instead).
319
 *  - $vars['user'] The logged in user. (use {@link elgg_get_logged_in_user_entity()} instead).
320
 *
321
 * Custom template handlers can be set with {@link set_template_handler()}.
322
 *
323
 * The output of views can be intercepted by registering for the
324
 * view, $view_name plugin hook.
325
 *
326
 * @warning Any variables in $_SESSION will override passed vars
327
 * upon name collision.  See https://github.com/Elgg/Elgg/issues/2124
328
 *
329
 * @param string  $view     The name and location of the view to use
330
 * @param array   $vars     Variables to pass to the view.
331
 * @param boolean $bypass   If set to true, elgg_view will bypass any specified
332
 *                          alternative template handler; by default, it will
333
 *                          hand off to this if requested (see set_template_handler)
334
 * @param boolean $ignored  This argument is ignored and will be removed eventually
335
 * @param string  $viewtype If set, forces the viewtype for the elgg_view call to be
336
 *                          this value (default: standard detection)
337
 *
338
 * @return string The parsed view
339
 */
340
function elgg_view($view, $vars = array(), $bypass = false, $ignored = false, $viewtype = '') {
341
	return _elgg_services()->views->renderView($view, $vars, $bypass, $viewtype);
342
}
343
344
/**
345
 * Display a view with a deprecation notice. No missing view NOTICE is logged
346
 *
347
 * @see elgg_view()
348
 *
349
 * @param string  $view       The name and location of the view to use
350
 * @param array   $vars       Variables to pass to the view
351
 * @param string  $suggestion Suggestion with the deprecation message
352
 * @param string  $version    Human-readable *release* version: 1.7, 1.8, ...
353
 *
354
 * @return string The parsed view
355
 * @access private
356
 */
357
function elgg_view_deprecated($view, array $vars, $suggestion, $version) {
358
	return _elgg_services()->views->renderDeprecatedView($view, $vars, $suggestion, $version);
359
}
360
361
/**
362
 * Extends a view with another view.
363
 *
364
 * The output of any view can be prepended or appended to any other view.
365
 *
366
 * The default action is to append a view.  If the priority is less than 500,
367
 * the output of the extended view will be appended to the original view.
368
 *
369
 * Views can be extended multiple times, and extensions are not checked for
370
 * uniqueness. Use {@link elgg_unextend_view()} to help manage duplicates.
371
 *
372
 * Priority can be specified and affects the order in which extensions
373
 * are appended or prepended.
374
 *
375
 * @note Internal: View extensions are stored in
376
 * $CONFIG->views->extensions[$view][$priority] = $view_extension
377
 *
378
 * @param string $view           The view to extend.
379
 * @param string $view_extension This view is added to $view
380
 * @param int    $priority       The priority, from 0 to 1000,
381
 *                               to add at (lowest numbers displayed first)
382
 * @param string $viewtype       I'm not sure why this is here @todo
383
 *
384
 * @return void
385
 * @since 1.7.0
386
 */
387
function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') {
388
	_elgg_services()->views->extendView($view, $view_extension, $priority, $viewtype);
389
}
390
391
/**
392
 * Unextends a view.
393
 *
394
 * @param string $view           The view that was extended.
395
 * @param string $view_extension This view that was added to $view
396
 *
397
 * @return bool
398
 * @since 1.7.2
399
 */
400
function elgg_unextend_view($view, $view_extension) {
401
	return _elgg_services()->views->unextendView($view, $view_extension);
402
}
403
404
/**
405
 * Assembles and outputs a full page.
406
 *
407
 * A "page" in Elgg is determined by the current view type and
408
 * can be HTML for a browser, RSS for a feed reader, or
409
 * Javascript, PHP and a number of other formats.
410
 *
411
 * For HTML pages, use the 'head', 'page' plugin hook for setting meta elements
412
 * and links.
413
 *
414
 * @param string $title      Title
415
 * @param string $body       Body
416
 * @param string $page_shell Optional page shell to use. See page/shells view directory
417
 * @param array  $vars       Optional vars array to pass to the page
418
 *                           shell. Automatically adds title, body, head, and sysmessages
419
 *
420
 * @return string The contents of the page
421
 * @since  1.8
422
 */
423
function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) {
424
425
	$params = array();
426
	$params['identifier'] = _elgg_services()->request->getFirstUrlSegment();
427
	$params['segments'] = _elgg_services()->request->getUrlSegments();
428
	array_shift($params['segments']);
429
	$page_shell = elgg_trigger_plugin_hook('shell', 'page', $params, $page_shell);
430
431
	$system_messages = _elgg_services()->systemMessages;
432
433
	$messages = null;
434
	if ($system_messages->count()) {
435
		$messages = $system_messages->dumpRegister();
436
		
437
		if (isset($messages['error'])) {
438
			// always make sure error is the first type
439
			$errors = array(
440
				'error' => $messages['error']
441
			);
442
			
443
			unset($messages['error']);
444
			$messages = array_merge($errors, $messages);
445
		}
446
	}
447
448
	$vars['title'] = $title;
449
	$vars['body'] = $body;
450
	$vars['sysmessages'] = $messages;
451
452
	// head has keys 'title', 'metas', 'links'
453
	$head_params = _elgg_views_prepare_head($title);
454
455
	$vars['head'] = elgg_trigger_plugin_hook('head', 'page', $vars, $head_params);
456
457
	$vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars);
458
	
459
	// check for deprecated view
460 View Code Duplication
	if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) {
461
		elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8);
462
		$output = elgg_view('pageshells/pageshell', $vars);
463
	} else {
464
		$output = elgg_view("page/$page_shell", $vars);
465
	}
466
467
	$vars['page_shell'] = $page_shell;
468
469
	// Allow plugins to modify the output
470
	return elgg_trigger_plugin_hook('output', 'page', $vars, $output);
471
}
472
473
/**
474
 * Prepare the variables for the html head
475
 *
476
 * @param string $title Page title for <head>
477
 * @return array
478
 * @access private
479
 */
480
function _elgg_views_prepare_head($title) {
481
	$params = array(
482
		'links' => array(),
483
		'metas' => array(),
484
	);
485
486
	if (empty($title)) {
487
		$params['title'] = elgg_get_config('sitename');
488
	} else if ( elgg_is_active_plugin('wet4') ) {
489
		//add translation
490
		$params['title'] = gc_explode_translation($title,get_current_language()) . ' : ' . elgg_get_config('sitename');
491
	}else {
492
		//add translation
493
		$params['title'] = $title . ' : ' . elgg_get_config('sitename');
494
	}
495
496
	$params['metas']['content-type'] = array(
497
		'http-equiv' => 'Content-Type',
498
		'content' => 'text/html; charset=utf-8',
499
	);
500
501
	$params['metas']['description'] = array(
502
		'name' => 'description',
503
		'content' => elgg_get_config('sitedescription')
504
	);
505
	
506
	// https://developer.chrome.com/multidevice/android/installtohomescreen
507
	$params['metas']['viewport'] = array(
508
		'name' => 'viewport',
509
		'content' => 'width=device-width',
510
	);    
511
	$params['metas']['mobile-web-app-capable'] = array(
512
		'name' => 'mobile-web-app-capable',
513
		'content' => 'yes',
514
	);
515
	$params['metas']['apple-mobile-web-app-capable'] = array(
516
		'name' => 'apple-mobile-web-app-capable',
517
		'content' => 'yes',
518
	);
519
	$params['links']['apple-touch-icon'] = array(
520
		'rel' => 'apple-touch-icon',
521
		'href' => elgg_normalize_url('_graphics/favicon-128.png'),
522
	);
523
524
	// favicons
525
	$params['links']['icon-ico'] = array(
526
		'rel' => 'icon',
527
		'href' => elgg_normalize_url('_graphics/favicon.ico'),
528
	);
529
	$params['links']['icon-vector'] = array(
530
		'rel' => 'icon',
531
		'sizes' => '16x16 32x32 48x48 64x64 128x128',
532
		'type' => 'image/svg+xml',
533
		'href' => elgg_normalize_url('_graphics/favicon.svg'),
534
	);
535
	$params['links']['icon-16'] = array(
536
		'rel' => 'icon',
537
		'sizes' => '16x16',
538
		'type' => 'image/png',
539
		'href' => elgg_normalize_url('_graphics/favicon-16.png'),
540
	);
541
	$params['links']['icon-32'] = array(
542
		'rel' => 'icon',
543
		'sizes' => '32x32',
544
		'type' => 'image/png',
545
		'href' => elgg_normalize_url('_graphics/favicon-32.png'),
546
	);
547
	$params['links']['icon-64'] = array(
548
		'rel' => 'icon',
549
		'sizes' => '64x64',
550
		'type' => 'image/png',
551
		'href' => elgg_normalize_url('_graphics/favicon-64.png'),
552
	);
553
	$params['links']['icon-128'] = array(
554
		'rel' => 'icon',
555
		'sizes' => '128x128',
556
		'type' => 'image/png',
557
		'href' => elgg_normalize_url('_graphics/favicon-128.png'),
558
	);
559
560
	// RSS feed link
561
	global $autofeed;
562
	if (isset($autofeed) && $autofeed == true) {
563
		$url = current_page_url();
564
		if (substr_count($url,'?')) {
565
			$url .= "&view=rss";
566
		} else {
567
			$url .= "?view=rss";
568
		}
569
		$params['links']['rss'] = array(
570
			'rel' => 'alternative',
571
			'type' => 'application/rss+xml',
572
			'title' => 'RSS',
573
			'href' => elgg_format_url($url),
574
		);
575
	}
576
577
	return $params;
578
}
579
580
/**
581
 * Displays a layout with optional parameters.
582
 *
583
 * Layouts provide consistent organization of pages and other blocks of content.
584
 * There are a few default layouts in core:
585
 *  - admin                   A special layout for the admin area.
586
 *  - one_column              A single content column.
587
 *  - one_sidebar             A content column with sidebar.
588
 *  - two_sidebar             A content column with two sidebars.
589
 *  - widgets                 A widget canvas.
590
 *
591
 * The layout views take the form page/layouts/$layout_name
592
 * See the individual layouts for what options are supported. The three most
593
 * common layouts have these parameters:
594
 * one_column
595
 *     content => string
596
 * one_sidebar
597
 *     content => string
598
 *     sidebar => string (optional)
599
 * content
600
 *     content => string
601
 *     sidebar => string (optional)
602
 *     buttons => string (override the default add button)
603
 *     title   => string (override the default title)
604
 *     filter_context => string (selected content filter)
605
 *     See the content layout view for more parameters
606
 *
607
 * @param string $layout_name The name of the view in page/layouts/.
608
 * @param array  $vars        Associative array of parameters for the layout view
609
 *
610
 * @return string The layout
611
 */
612
function elgg_view_layout($layout_name, $vars = array()) {
613
614
	$params = array();
615
	$params['identifier'] = _elgg_services()->request->getFirstUrlSegment();
616
	$params['segments'] = _elgg_services()->request->getUrlSegments();
617
	array_shift($params['segments']);
618
	$layout_name = elgg_trigger_plugin_hook('layout', 'page', $params, $layout_name);
619
620
	if (is_string($vars) || $vars === null) {
621
		elgg_deprecated_notice("The use of unlimited optional string arguments in elgg_view_layout() was deprecated in favor of an options array", 1.8);
622
		$arg = 1;
623
		$param_array = array();
624
		while ($arg < func_num_args()) {
625
			$param_array['area' . $arg] = func_get_arg($arg);
626
			$arg++;
627
		}
628
	} else {
629
		$param_array = $vars;
630
	}
631
	$param_array['layout'] = $layout_name;
632
633
	$params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array);
634
635
	// check deprecated location
636 View Code Duplication
	if (elgg_view_exists("canvas/layouts/$layout_name")) {
637
		elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8);
638
		$output = elgg_view("canvas/layouts/$layout_name", $params);
639
	} elseif (elgg_view_exists("page/layouts/$layout_name")) {
640
		$output = elgg_view("page/layouts/$layout_name", $params);
641
	} else {
642
		$output = elgg_view("page/layouts/default", $params);
643
	}
644
645
	return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output);
646
}
647
648
/**
649
 * Render a menu
650
 *
651
 * @see elgg_register_menu_item() for documentation on adding menu items and
652
 * navigation.php for information on the different menus available.
653
 *
654
 * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables
655
 * plugins to add menu items just before a menu is rendered. This is used by
656
 * dynamic menus (menus that change based on some input such as the user hover
657
 * menu). Using elgg_register_menu_item() in response to the hook can cause
658
 * incorrect links to show up. See the blog plugin's blog_owner_block_menu()
659
 * for an example of using this plugin hook.
660
 *
661
 * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins
662
 * to modify the structure of the menu (sort it, remove items, set variables on
663
 * the menu items).
664
 *
665
 * elgg_view_menu() uses views in navigation/menu
666
 *
667
 * @param string $menu_name The name of the menu
668
 * @param array  $vars      An associative array of display options for the menu.
669
 *                          Options include:
670
 *                              sort_by => string or php callback
671
 *                                  string options: 'name', 'priority', 'title' (default),
672
 *                                  'register' (registration order) or a
673
 *                                  php callback (a compare function for usort)
674
 *                              handler: string the page handler to build action URLs
675
 *                              entity: \ElggEntity to use to build action URLs
676
 *                              class: string the class for the entire menu.
677
 *                              show_section_headers: bool show headers before menu sections.
678
 *
679
 * @return string
680
 * @since 1.8.0
681
 */
682
function elgg_view_menu($menu_name, array $vars = array()) {
683
	global $CONFIG;
684
685
	$vars['name'] = $menu_name;
686
	
687
	$vars = elgg_trigger_plugin_hook('parameters', "menu:$menu_name", $vars, $vars);
688
	
689
	$sort_by = elgg_extract('sort_by', $vars, 'text');
690
691
	if (isset($CONFIG->menus[$menu_name])) {
692
		$menu = $CONFIG->menus[$menu_name];
693
	} else {
694
		$menu = array();
695
	}
696
697
	// Give plugins a chance to add menu items just before creation.
698
	// This supports dynamic menus (example: user_hover).
699
	$menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu);
700
701
	$builder = new \ElggMenuBuilder($menu);
702
	$vars['menu'] = $builder->getMenu($sort_by);
703
	$vars['selected_item'] = $builder->getSelected();
704
705
	// Let plugins modify the menu
706
	$vars['menu'] = elgg_trigger_plugin_hook('prepare', "menu:$menu_name", $vars, $vars['menu']);
707
708
	if (elgg_view_exists("navigation/menu/$menu_name")) {
709
		return elgg_view("navigation/menu/$menu_name", $vars);
710
	} else {
711
		return elgg_view("navigation/menu/default", $vars);
712
	}
713
}
714
715
/**
716
 * Render a menu item (usually as a link)
717
 *
718
 * @param \ElggMenuItem $item The menu item
719
 * @param array         $vars Options to pass to output/url if a link
720
 * @return string
721
 * @since 1.9.0
722
 */
723
function elgg_view_menu_item(\ElggMenuItem $item, array $vars = array()) {
724
	if (!isset($vars['class'])) {
725
		$vars['class'] = 'elgg-menu-content';
726
	}
727
728
	$vars = array_merge($item->getValues(), $vars);
729
730
	if ($item->getLinkClass()) {
731
		$vars['class'] .= ' ' . $item->getLinkClass();
732
	}
733
734
	if ($item->getHref() === false || $item->getHref() === null) {
735
		$text = $item->getText();
736
737
		// if contains elements, don't wrap
738
		if (preg_match('~<[a-z]~', $text)) {
739
			return $text;
740
		} else {
741
			return elgg_format_element('span', array('class' => 'elgg-non-link'), $text);
742
		}
743
	}
744
745
	if (!isset($vars['rel']) && !isset($vars['is_trusted'])) {
746
		$vars['is_trusted'] = true;
747
	}
748
749
	if ($item->getConfirmText()) {
750
		$vars['confirm'] = $item->getConfirmText();
751
	}
752
753
	return elgg_view('output/url', $vars);
754
}
755
756
/**
757
 * Returns a string of a rendered entity.
758
 *
759
 * Entity views are either determined by setting the view property on the entity
760
 * or by having a view named after the entity $type/$subtype.  Entities that have
761
 * neither a view property nor a defined $type/$subtype view will fall back to
762
 * using the $type/default view.
763
 *
764
 * The entity view is called with the following in $vars:
765
 *  - \ElggEntity 'entity' The entity being viewed
766
 *
767
 * @tip This function can automatically appends annotations to entities if in full
768
 * view and a handler is registered for the entity:annotate.  See https://github.com/Elgg/Elgg/issues/964 and
769
 * {@link elgg_view_entity_annotations()}.
770
 *
771
 * @param \ElggEntity $entity The entity to display
772
 * @param array       $vars   Array of variables to pass to the entity view.
773
 *                            In Elgg 1.7 and earlier it was the boolean $full_view
774
 *      'full_view'        Whether to show a full or condensed view. (Default: true)
775
 *      'item_view'        Alternative view used to render this entity
776
 * @param boolean     $bypass If true, will not pass to a custom template handler.
777
 *                            {@link set_template_handler()}
778
 * @param boolean     $debug  Complain if views are missing
779
 *
780
 * @return string HTML to display or false
781
 * @todo The annotation hook might be better as a generic plugin hook to append content.
782
 */
783
function elgg_view_entity(\ElggEntity $entity, $vars = array(), $bypass = false, $debug = false) {
784
785
	// No point continuing if entity is null
786
	if (!$entity || !($entity instanceof \ElggEntity)) {
787
		return false;
788
	}
789
790
	global $autofeed;
791
	$autofeed = true;
792
793
	$defaults = array(
794
		'full_view' => true,
795
	);
796
797
	if (is_array($vars)) {
798
		$vars = array_merge($defaults, $vars);
799
	} else {
800
		elgg_deprecated_notice("Update your use of elgg_view_entity()", 1.8);
801
		$vars = array(
802
			'full_view' => $vars,
803
		);
804
	}
805
806
	$vars['entity'] = $entity;
807
808
	$entity_type = $entity->getType();
809
	$entity_subtype = $entity->getSubtype();
810
	if (empty($entity_subtype)) {
811
		$entity_subtype = 'default';
812
	}
813
814
	$entity_views = array(
815
		elgg_extract('item_view', $vars, ''),
816
		$entity->view,
817
		"$entity_type/$entity_subtype",
818
		"$entity_type/default",
819
	);
820
821
	$contents = '';
822 View Code Duplication
	foreach ($entity_views as $view) {
823
		if (elgg_view_exists($view)) {
824
			$contents = elgg_view($view, $vars, $bypass, $debug);
825
			break;
826
		}
827
	}
828
829
	// Marcus Povey 20090616 : Speculative and low impact approach for fixing #964
830
	if ($vars['full_view']) {
831
		$annotations = elgg_view_entity_annotations($entity, $vars['full_view']);
832
833
		if ($annotations) {
834
			$contents .= $annotations;
835
		}
836
	}
837
	return $contents;
838
}
839
840
/**
841
 * View the icon of an entity
842
 *
843
 * Entity views are determined by having a view named after the entity $type/$subtype.
844
 * Entities that do not have a defined icon/$type/$subtype view will fall back to using
845
 * the icon/$type/default view.
846
 *
847
 * @param \ElggEntity $entity The entity to display
848
 * @param string      $size   The size: tiny, small, medium, large
849
 * @param array       $vars   An array of variables to pass to the view. Some possible
850
 *                            variables are img_class and link_class. See the
851
 *                            specific icon view for more parameters.
852
 *
853
 * @return string HTML to display or false
854
 */
855
function elgg_view_entity_icon(\ElggEntity $entity, $size = 'medium', $vars = array()) {
856
857
	// No point continuing if entity is null
858
	if (!$entity || !($entity instanceof \ElggEntity)) {
859
		return false;
860
	}
861
862
	$vars['entity'] = $entity;
863
	$vars['size'] = $size;
864
865
	$entity_type = $entity->getType();
866
867
	$subtype = $entity->getSubtype();
868
	if (empty($subtype)) {
869
		$subtype = 'default';
870
	}
871
872
	$contents = '';
873
	if (elgg_view_exists("icon/$entity_type/$subtype")) {
874
		$contents = elgg_view("icon/$entity_type/$subtype", $vars);
875
	}
876
	if (empty($contents)) {
877
		$contents = elgg_view("icon/$entity_type/default", $vars);
878
	}
879
	if (empty($contents)) {
880
		$contents = elgg_view("icon/default", $vars);
881
	}
882
883
	return $contents;
884
}
885
886
/**
887
 * Returns a string of a rendered annotation.
888
 *
889
 * Annotation views are expected to be in annotation/$annotation_name.
890
 * If a view is not found for $annotation_name, the default annotation/default
891
 * will be used.
892
 *
893
 * @warning annotation/default is not currently defined in core.
894
 *
895
 * The annotation view is called with the following in $vars:
896
 *  - \ElggEntity 'annotation' The annotation being viewed.
897
 *
898
 * @param \ElggAnnotation $annotation The annotation to display
899
 * @param array           $vars       Variable array for view.
900
 *      'item_view'  Alternative view used to render an annotation
901
 * @param bool            $bypass     If true, will not pass to a custom
902
 *                                    template handler. {@link set_template_handler()}
903
 * @param bool            $debug      Complain if views are missing
904
 *
905
 * @return string/false Rendered annotation
0 ignored issues
show
The doc-type string/false could not be parsed: Unknown type name "string/false" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
906
 */
907
function elgg_view_annotation(\ElggAnnotation $annotation, array $vars = array(), $bypass = false, $debug = false) {
908
	global $autofeed;
909
	$autofeed = true;
910
911
	$defaults = array(
912
		'full_view' => true,
913
	);
914
915
	$vars = array_merge($defaults, $vars);
916
	$vars['annotation'] = $annotation;
917
918
	// @todo setting the view on an annotation is not advertised anywhere
919
	// do we want to keep this?
920
	$view = $annotation->view;
921
	if (is_string($view)) {
922
		return elgg_view($view, $vars, $bypass, $debug);
923
	}
924
925
	$name = $annotation->name;
926
	if (empty($name)) {
927
		return false;
928
	}
929
930
	$annotation_views = array(
931
		elgg_extract('item_view', $vars, ''),
932
		"annotation/$name",
933
		"annotation/default",
934
	);
935
936
	$contents = '';
937 View Code Duplication
	foreach ($annotation_views as $view) {
938
		if (elgg_view_exists($view)) {
939
			$contents = elgg_view($view, $vars, $bypass, $debug);
940
			break;
941
		}
942
	}
943
944
	return $contents;
945
}
946
947
/**
948
 * Returns a rendered list of entities with pagination. This function should be
949
 * called by wrapper functions.
950
 *
951
 * @see elgg_list_entities()
952
 * @see list_user_friends_objects()
953
 * @see elgg_list_entities_from_metadata()
954
 * @see elgg_list_entities_from_relationships()
955
 * @see elgg_list_entities_from_annotations()
956
 *
957
 * @param array $entities Array of entities
958
 * @param array $vars     Display variables
959
 *      'count'            The total number of entities across all pages
960
 *      'offset'           The current indexing offset
961
 *      'limit'            The number of entities to display per page (default from settings)
962
 *      'full_view'        Display the full view of the entities?
963
 *      'list_class'       CSS class applied to the list
964
 *      'item_class'       CSS class applied to the list items
965
 *      'item_view'        Alternative view to render list items
966
 *      'pagination'       Display pagination?
967
 *      'list_type'        List type: 'list' (default), 'gallery'
968
 *      'list_type_toggle' Display the list type toggle?
969
 *      'no_results'       Message to display if no results (string|Closure)
970
 *
971
 * @return string The rendered list of entities
972
 * @access private
973
 */
974
function elgg_view_entity_list($entities, $vars = array(), $offset = 0, $limit = null, $full_view = true,
975
$list_type_toggle = true, $pagination = true) {
976
977
	if (!is_int($offset)) {
978
		$offset = (int)get_input('offset', 0);
979
	}
980
981
	// list type can be passed as request parameter
982
	$list_type = get_input('list_type', 'list');
983
	if (get_input('listtype')) {
984
		elgg_deprecated_notice("'listtype' has been deprecated by 'list_type' for lists", 1.8);
985
		$list_type = get_input('listtype');
986
	}
987
988
	if (is_array($vars)) {
989
		// new function
990
		$defaults = array(
991
			'items' => $entities,
992
			'list_class' => 'elgg-list-entity',
993
			'full_view' => true,
994
			'pagination' => true,
995
			'list_type' => $list_type,
996
			'list_type_toggle' => false,
997
			'offset' => $offset,
998
			'limit' => null,
999
		);
1000
1001
		$vars = array_merge($defaults, $vars);
1002
1003
	} else {
1004
		// old function parameters
1005
		elgg_deprecated_notice("Please update your use of elgg_view_entity_list()", 1.8);
1006
1007
		if ($limit === null) {
1008
			$limit = elgg_get_config('default_limit');
1009
		}
1010
1011
		$vars = array(
1012
			'items' => $entities,
1013
			'count' => (int) $vars, // the old count parameter
1014
			'offset' => $offset,
1015
			'limit' => (int) $limit,
1016
			'full_view' => $full_view,
1017
			'pagination' => $pagination,
1018
			'list_type' => $list_type,
1019
			'list_type_toggle' => $list_type_toggle,
1020
			'list_class' => 'elgg-list-entity',
1021
		);
1022
	}
1023
1024 View Code Duplication
	if (!$vars["limit"] && !$vars["offset"]) {
1025
		// no need for pagination if listing is unlimited
1026
		$vars["pagination"] = false;
1027
	}
1028
1029
	if ($vars['list_type'] != 'list') {
1030
		return elgg_view('page/components/gallery', $vars);
1031
	} else {
1032
		return elgg_view('page/components/list', $vars);
1033
	}
1034
}
1035
1036
/**
1037
 * Returns a rendered list of annotations, plus pagination. This function
1038
 * should be called by wrapper functions.
1039
 *
1040
 * @param array $annotations Array of annotations
1041
 * @param array $vars        Display variables
1042
 *      'count'      The total number of annotations across all pages
1043
 *      'offset'     The current indexing offset
1044
 *      'limit'      The number of annotations to display per page
1045
 *      'full_view'  Display the full view of the annotation?
1046
 *      'list_class' CSS Class applied to the list
1047
 *      'item_view'  Alternative view to render list items
1048
 *      'offset_key' The url parameter key used for offset
1049
 *      'no_results' Message to display if no results (string|Closure)
1050
 *
1051
 * @return string The list of annotations
1052
 * @access private
1053
 */
1054
function elgg_view_annotation_list($annotations, array $vars = array()) {
1055
	$defaults = array(
1056
		'items' => $annotations,
1057
		'offset' => null,
1058
		'limit' => null,
1059
		'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9
1060
		'full_view' => true,
1061
		'offset_key' => 'annoff',
1062
	);
1063
	
1064
	$vars = array_merge($defaults, $vars);
1065
	
1066 View Code Duplication
	if (!$vars["limit"] && !$vars["offset"]) {
1067
		// no need for pagination if listing is unlimited
1068
		$vars["pagination"] = false;
1069
	}
1070
1071
	return elgg_view('page/components/list', $vars);
1072
}
1073
1074
/**
1075
 * Display a plugin-specified rendered list of annotations for an entity.
1076
 *
1077
 * This displays the output of functions registered to the entity:annotation,
1078
 * $entity_type plugin hook.
1079
 *
1080
 * This is called automatically by the framework from {@link elgg_view_entity()}
1081
 *
1082
 * @param \ElggEntity $entity    Entity
1083
 * @param bool        $full_view Display full view?
1084
 *
1085
 * @return mixed string or false on failure
1086
 * @todo Change the hook name.
1087
 */
1088
function elgg_view_entity_annotations(\ElggEntity $entity, $full_view = true) {
1089
	if (!($entity instanceof \ElggEntity)) {
1090
		return false;
1091
	}
1092
1093
	$entity_type = $entity->getType();
1094
1095
	$annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type,
1096
		array(
1097
			'entity' => $entity,
1098
			'full_view' => $full_view,
1099
		)
1100
	);
1101
1102
	return $annotations;
1103
}
1104
1105
/**
1106
 * Renders a title.
1107
 *
1108
 * This is a shortcut for {@elgg_view page/elements/title}.
1109
 *
1110
 * @param string $title The page title
1111
 * @param array  $vars  View variables (was submenu be displayed? (deprecated))
1112
 *
1113
 * @return string The HTML (etc)
1114
 */
1115
function elgg_view_title($title, $vars = array()) {
1116
	if (!is_array($vars)) {
1117
		elgg_deprecated_notice('setting $submenu in elgg_view_title() is deprecated', 1.8);
1118
		$vars = array('submenu' => $vars);
1119
	}
1120
1121
	$vars['title'] = $title;
1122
1123
	return elgg_view('page/elements/title', $vars);
1124
}
1125
1126
/**
1127
 * Displays a UNIX timestamp in a friendly way
1128
 *
1129
 * @see elgg_get_friendly_time()
1130
 *
1131
 * @param int $time A UNIX epoch timestamp
1132
 *
1133
 * @return string The friendly time HTML
1134
 * @since 1.7.2
1135
 */
1136
function elgg_view_friendly_time($time) {
1137
	return elgg_view('output/friendlytime', array('time' => $time));
1138
}
1139
1140
1141
/**
1142
 * Returns rendered comments and a comment form for an entity.
1143
 *
1144
 * @tip Plugins can override the output by registering a handler
1145
 * for the comments, $entity_type hook.  The handler is responsible
1146
 * for formatting the comments and the add comment form.
1147
 *
1148
 * @param \ElggEntity $entity      The entity to view comments of
1149
 * @param bool        $add_comment Include a form to add comments?
1150
 * @param array       $vars        Variables to pass to comment view
1151
 *
1152
 * @return string|false Rendered comments or false on failure
1153
 */
1154
function elgg_view_comments($entity, $add_comment = true, array $vars = array()) {
1155
	if (!($entity instanceof \ElggEntity)) {
1156
		return false;
1157
	}
1158
1159
	$vars['entity'] = $entity;
1160
	$vars['show_add_form'] = $add_comment;
1161
	$vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments");
1162
1163
	$output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false);
1164
	if ($output) {
1165
		return $output;
1166
	} else {
1167
		return elgg_view('page/elements/comments', $vars);
1168
	}
1169
}
1170
1171
/**
1172
 * Wrapper function for the image block display pattern.
1173
 *
1174
 * Fixed width media on the side (image, icon, flash, etc.).
1175
 * Descriptive content filling the rest of the column.
1176
 *
1177
 * This is a shortcut for {@elgg_view page/components/image_block}.
1178
 *
1179
 * @param string $image The icon and other information
1180
 * @param string $body  Description content
1181
 * @param array  $vars  Additional parameters for the view
1182
 *
1183
 * @return string
1184
 * @since 1.8.0
1185
 */
1186
function elgg_view_image_block($image, $body, $vars = array()) {
1187
	$vars['image'] = $image;
1188
	$vars['body'] = $body;
1189
	return elgg_view('page/components/image_block', $vars);
1190
}
1191
1192
/**
1193
 * Wrapper function for the module display pattern.
1194
 *
1195
 * Box with header, body, footer
1196
 *
1197
 * This is a shortcut for {@elgg_view page/components/module}.
1198
 *
1199
 * @param string $type  The type of module (main, info, popup, aside, etc.)
1200
 * @param string $title A title to put in the header
1201
 * @param string $body  Content of the module
1202
 * @param array  $vars  Additional parameters for the module
1203
 *
1204
 * @return string
1205
 * @since 1.8.0
1206
 */
1207
function elgg_view_module($type, $title, $body, array $vars = array()) {
1208
	$vars['type'] = $type;
1209
	$vars['title'] = $title;
1210
	$vars['body'] = $body;
1211
	return elgg_view('page/components/module', $vars);
1212
}
1213
1214
/**
1215
 * Renders a human-readable representation of a river item
1216
 *
1217
 * @param \ElggRiverItem $item A river item object
1218
 * @param array          $vars An array of variables for the view
1219
 *      'item_view'  Alternative view to render the item
1220
 * @return string returns empty string if could not be rendered
1221
 */
1222
function elgg_view_river_item($item, array $vars = array()) {
1223
	if (!($item instanceof \ElggRiverItem)) {
1224
		return '';
1225
	}
1226
	// checking default viewtype since some viewtypes do not have unique views per item (rss)
1227
	$view = $item->getView();
1228
	if (!$view || !elgg_view_exists($view, 'default')) {
1229
		return '';
1230
	}
1231
1232
	$subject = $item->getSubjectEntity();
1233
	$object = $item->getObjectEntity();
1234
	if (!$subject || !$object) {
1235
		// subject is disabled or subject/object deleted
1236
		return '';
1237
	}
1238
1239
	// @todo this needs to be cleaned up
1240
	// Don't hide objects in closed groups that a user can see.
1241
	// see https://github.com/elgg/elgg/issues/4789
1242
	//	else {
1243
	//		// hide based on object's container
1244
	//		$visibility = \Elgg\GroupItemVisibility::factory($object->container_guid);
1245
	//		if ($visibility->shouldHideItems) {
1246
	//			return '';
1247
	//		}
1248
	//	}
1249
1250
	$vars['item'] = $item;
1251
1252
	$river_views = array(
1253
		elgg_extract('item_view', $vars, ''),
1254
		"river/item",
1255
	);
1256
1257
	$contents = '';
1258
	foreach ($river_views as $view) {
1259
		if (elgg_view_exists($view)) {
1260
			$contents = elgg_view($view, $vars);
1261
			break;
1262
		}
1263
	}
1264
1265
	return $contents;
1266
}
1267
1268
/**
1269
 * Convenience function for generating a form from a view in a standard location.
1270
 *
1271
 * This function assumes that the body of the form is located at "forms/$action" and
1272
 * sets the action by default to "action/$action".  Automatically wraps the forms/$action
1273
 * view with a <form> tag and inserts the anti-csrf security tokens.
1274
 *
1275
 * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any
1276
 * slashes with dashes (blog/save becomes elgg-form-blog-save)
1277
 *
1278
 * @example
1279
 * <code>echo elgg_view_form('login');</code>
1280
 *
1281
 * This would assume a "login" form body to be at "forms/login" and would set the action
1282
 * of the form to "http://yoursite.com/action/login".
1283
 *
1284
 * If elgg_view('forms/login') is:
1285
 * <input type="text" name="username" />
1286
 * <input type="password" name="password" />
1287
 *
1288
 * Then elgg_view_form('login') generates:
1289
 * <form action="http://yoursite.com/action/login" method="post">
1290
 *     ...security tokens...
1291
 *     <input type="text" name="username" />
1292
 *     <input type="password" name="password" />
1293
 * </form>
1294
 *
1295
 * @param string $action    The name of the action. An action name does not include
1296
 *                          the leading "action/". For example, "login" is an action name.
1297
 * @param array  $form_vars $vars environment passed to the "input/form" view
1298
 * @param array  $body_vars $vars environment passed to the "forms/$action" view
1299
 *
1300
 * @return string The complete form
1301
 */
1302
function elgg_view_form($action, $form_vars = array(), $body_vars = array()) {
1303
	global $CONFIG;
1304
1305
	$defaults = array(
1306
		'action' => $CONFIG->wwwroot . "action/$action",
1307
		'body' => elgg_view("forms/$action", $body_vars)
1308
	);
1309
1310
	$form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action);
1311
1312
	// append elgg-form class to any class options set
1313
	if (isset($form_vars['class'])) {
1314
		$form_vars['class'] = $form_vars['class'] . " $form_class";
1315
	} else {
1316
		$form_vars['class'] = $form_class;
1317
	}
1318
1319
	$form_vars = array_merge($defaults, $form_vars);
1320
	$form_vars['action_name'] = $action;
1321
1322
	return elgg_view('input/form', $form_vars);
1323
}
1324
1325
/**
1326
 * Create a tagcloud for viewing
1327
 *
1328
 * @see elgg_get_tags
1329
 *
1330
 * @param array $options Any elgg_get_tags() options except:
1331
 *
1332
 * 	type => must be single entity type
1333
 *
1334
 * 	subtype => must be single entity subtype
1335
 *
1336
 * @return string
1337
 * @since 1.7.1
1338
 */
1339
function elgg_view_tagcloud(array $options = array()) {
1340
1341
	$type = $subtype = '';
1342
	if (isset($options['type'])) {
1343
		$type = $options['type'];
1344
	}
1345
	if (isset($options['subtype'])) {
1346
		$subtype = $options['subtype'];
1347
	}
1348
1349
	$tag_data = elgg_get_tags($options);
1350
	return elgg_view("output/tagcloud", array(
1351
		'value' => $tag_data,
1352
		'type' => $type,
1353
		'subtype' => $subtype,
1354
	));
1355
}
1356
1357
/**
1358
 * View an item in a list
1359
 *
1360
 * @param \ElggEntity|\ElggAnnotation $item
1361
 * @param array  $vars Additional parameters for the rendering
1362
 *      'item_view' Alternative view used to render list items
1363
 * @return string
1364
 * @since 1.8.0
1365
 * @access private
1366
 */
1367
function elgg_view_list_item($item, array $vars = array()) {
1368
	
1369
	if ($item instanceof \ElggEntity) {
1370
		return elgg_view_entity($item, $vars);
1371
	} else if ($item instanceof \ElggAnnotation) {
1372
		return elgg_view_annotation($item, $vars);
1373
	} else if ($item instanceof \ElggRiverItem) {
1374
		return elgg_view_river_item($item, $vars);
1375
	}
1376
1377
	return '';
1378
}
1379
1380
/**
1381
 * View one of the elgg sprite icons
1382
 *
1383
 * Shorthand for <span class="elgg-icon elgg-icon-$name"></span>
1384
 *
1385
 * @param string $name The specific icon to display
1386
 * @param mixed  $vars The additional classname as a string ('float', 'float-alt' or a custom class) 
1387
 *                     or an array of variables (array('class' => 'float')) to pass to the icon view.
1388
 *
1389
 * @return string The html for displaying an icon
1390
 * @throws InvalidArgumentException
1391
 */
1392
function elgg_view_icon($name, $vars = array()) {
1393
	if (empty($vars)) {
1394
		$vars = array();
1395
	}
1396
	
1397
	if ($vars === true) {
1398
		elgg_deprecated_notice("Using a boolean to float the icon is deprecated. Use the class float.", 1.9);
1399
		$vars = array('class' => 'float');
1400
	}
1401
	
1402
	if (is_string($vars)) {
1403
		$vars = array('class' => $vars);
1404
	}
1405
	
1406
	if (!is_array($vars)) {
1407
		throw new \InvalidArgumentException('$vars needs to be a string or an array');
1408
	}
1409
	
1410
	if (!array_key_exists('class', $vars)) {
1411
		$vars['class'] = array();
1412
	}
1413
	
1414
	if (!is_array($vars['class'])) {
1415
		$vars['class'] = array($vars['class']);
1416
	}
1417
	
1418
	$vars['class'][] = "elgg-icon-$name";
1419
	
1420
	return elgg_view("output/icon", $vars);
1421
}
1422
1423
/**
1424
 * Displays a user's access collections, using the core/friends/collections view
1425
 *
1426
 * @param int $owner_guid The GUID of the owning user
1427
 *
1428
 * @return string A formatted rendition of the collections
1429
 * @todo Move to the friends/collection.php page.
1430
 * @access private
1431
 */
1432
function elgg_view_access_collections($owner_guid) {
1433
	if ($collections = get_user_access_collections($owner_guid)) {
1434
		$user = get_user($owner_guid);
1435
		if ($user) {
1436
			$entities = $user->getFriends(array('limit' => 0));
1437
		} else {
1438
			$entities = array();
1439
		}
1440
1441
		foreach ($collections as $key => $collection) {
1442
			$collections[$key]->members = get_members_of_access_collection($collection->id, true);
1443
			$collections[$key]->entities = $entities;
1444
		}
1445
	}
1446
1447
	return elgg_view('core/friends/collections', array('collections' => $collections));
1448
}
1449
1450
/**
1451
 * Auto-registers views from a location.
1452
 *
1453
 * @note Views in plugin/views/ are automatically registered for active plugins.
1454
 * Plugin authors would only need to call this if optionally including
1455
 * an entire views structure.
1456
 *
1457
 * @param string $view_base          Optional The base of the view name without the view type.
1458
 * @param string $folder             Required The folder to begin looking in
1459
 * @param string $base_location_path The base views directory to use with elgg_set_view_location()
1460
 * @param string $viewtype           The type of view we're looking at (default, rss, etc)
1461
 *
1462
 * @return bool returns false if folder can't be read
1463
 * @since 1.7.0
1464
 * @see elgg_set_view_location()
1465
 * @access private
1466
 */
1467
function autoregister_views($view_base, $folder, $base_location_path, $viewtype) {
1468
	return _elgg_services()->views->autoregisterViews($view_base, $folder, $base_location_path, $viewtype);
1469
}
1470
1471
/**
1472
 * Minifies simplecache CSS and JS views by handling the "simplecache:generate" hook
1473
 *
1474
 * @param string $hook    The name of the hook
1475
 * @param string $type    View type (css, js, or unknown)
1476
 * @param string $content Content of the view
1477
 * @param array  $params  Array of parameters
1478
 *
1479
 * @return string|null View content minified (if css/js type)
1480
 * @access private
1481
 */
1482
function _elgg_views_minify($hook, $type, $content, $params) {
1483
	if (preg_match('~[\.-]min\.~', $params['view'])) {
1484
		// bypass minification
1485
		return;
1486
	}
1487
1488
	if ($type == 'js') {
1489
		if (elgg_get_config('simplecache_minify_js')) {
1490
			return JSMin::minify($content);
1491
		}
1492
	} elseif ($type == 'css') {
1493
		if (elgg_get_config('simplecache_minify_css')) {
1494
			$cssmin = new CSSmin();
1495
			return $cssmin->run($content);
1496
		}
1497
	}
1498
}
1499
1500
1501
/**
1502
 * Inserts module names into anonymous modules by handling the "simplecache:generate" hook.
1503
 *
1504
 * @param string $hook    The name of the hook
1505
 * @param string $type    View type (css, js, or unknown)
1506
 * @param string $content Content of the view
1507
 * @param array  $params  Array of parameters
1508
 *
1509
 * @return string|null View content minified (if css/js type)
1510
 * @access private
1511
 */
1512
function _elgg_views_amd($hook, $type, $content, $params) {
1513
	$filter = new \Elgg\Amd\ViewFilter();
1514
	return $filter->filter($params['view'], $content);
1515
}
1516
1517
/**
1518
 * Add the rss link to the extras when if needed
1519
 *
1520
 * @return void
1521
 * @access private
1522
 */
1523
function elgg_views_add_rss_link() {
1524
	global $autofeed;
1525
	if (isset($autofeed) && $autofeed == true) {
1526
		$url = current_page_url();
1527
		if (substr_count($url, '?')) {
1528
			$url .= "&view=rss";
1529
		} else {
1530
			$url .= "?view=rss";
1531
		}
1532
1533
		$url = elgg_format_url($url);
1534
		elgg_register_menu_item('extras', array(
1535
			'name' => 'rss',
1536
			'text' => elgg_view_icon('rss'),
1537
			'href' => $url,
1538
			'title' => elgg_echo('feed:rss'),
1539
		));
1540
	}
1541
}
1542
1543
/**
1544
 * Sends X-Frame-Options header on page requests
1545
 *
1546
 * @access private
1547
 */
1548
function _elgg_views_send_header_x_frame_options() {
1549
	header('X-Frame-Options: SAMEORIGIN');
1550
}
1551
1552
/**
1553
 * Checks for usage of core views that have been removed
1554
 *
1555
 * @access private
1556
 */
1557
function _elgg_views_deprecate_removed_views() {
1558
	$removed_views = array(
1559
		"1.10" => array(
1560
			'core/settings/tools',
1561
		),
1562
	);
1563
1564
	$views_svc = _elgg_services()->views;
1565
	foreach ($removed_views as $version => $names) {
1566
		foreach ($names as $name) {
1567
			if ($views_svc->viewExists($name)) {
1568
				elgg_deprecated_notice("The view $name is no longer used and should not be provided or extended.", $version);
1569
			}
1570
		}
1571
	}
1572
}
1573
1574
/**
1575
 * Registers deprecated views to avoid making some pages from older plugins
1576
 * completely empty.
1577
 *
1578
 * @access private
1579
 */
1580
function elgg_views_handle_deprecated_views() {
1581
	$location = _elgg_services()->views->getViewLocation('page_elements/contentwrapper');
1582
	if ($location === "/var/www/views/") {
1583
		elgg_extend_view('page_elements/contentwrapper', 'page/elements/wrapper');
1584
	}
1585
}
1586
1587
/**
1588
 * Initialize viewtypes on system boot event
1589
 * This ensures simplecache is cleared during upgrades. See #2252
1590
 *
1591
 * @return void
1592
 * @access private
1593
 * @elgg_event_handler boot system
1594
 */
1595
function elgg_views_boot() {
1596
	global $CONFIG;
1597
1598
	elgg_register_simplecache_view('css/ie');
1599
	elgg_register_simplecache_view('js/text.js');
1600
1601
	elgg_register_js('elgg.require_config', elgg_get_simplecache_url('js', 'elgg/require_config'), 'head');
1602
	elgg_register_js('require', '/vendors/requirejs/require-2.1.10.min.js', 'head');
1603
	elgg_register_js('jquery', '/vendors/jquery/jquery-1.11.1.min.js', 'head');
1604
	elgg_register_js('jquery-migrate', '/vendors/jquery/jquery-migrate-1.2.1.min.js', 'head');
1605
	elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.10.4.min.js', 'head');
1606
1607
	// this is the only lib that isn't required to be loaded sync in head
1608
	elgg_define_js('jquery.form', array(
1609
		'src' => '/vendors/jquery/jquery.form.min.js',
1610
		'deps' => array('jquery'),
1611
		'exports' => 'jQuery.fn.ajaxForm',
1612
	));
1613
	elgg_define_js('jquery.ui', array(
1614
		'src' => '/vendors/jquery/jquery-ui-1.10.4.min.js',
1615
		'deps' => array('jquery'),
1616
	));
1617
1618
	$elgg_js_url = elgg_get_simplecache_url('js', 'elgg');
1619
	elgg_register_js('elgg', $elgg_js_url, 'head');
1620
1621
	elgg_load_js('elgg.require_config');
1622
	elgg_load_js('require');
1623
	elgg_load_js('jquery');
1624
	elgg_load_js('jquery-migrate');
1625
	elgg_load_js('jquery-ui');
1626
	elgg_load_js('elgg');
1627
1628
	$lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox');
1629
	elgg_register_js('lightbox', $lightbox_js_url);
1630
1631
	elgg_register_css('lightbox', 'vendors/jquery/colorbox/theme/colorbox.css');
1632
1633
	$elgg_css_url = elgg_get_simplecache_url('css', 'elgg');
1634
	elgg_register_css('elgg', $elgg_css_url);
1635
1636
	elgg_load_css('elgg');
1637
1638
	elgg_register_ajax_view('js/languages');
1639
1640
	elgg_register_plugin_hook_handler('simplecache:generate', 'js', '_elgg_views_amd');
1641
	elgg_register_plugin_hook_handler('simplecache:generate', 'css', '_elgg_views_minify');
1642
	elgg_register_plugin_hook_handler('simplecache:generate', 'js', '_elgg_views_minify');
1643
1644
	elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link');
1645
	elgg_register_plugin_hook_handler('output:before', 'page', '_elgg_views_send_header_x_frame_options');
1646
1647
	// discover the core viewtypes
1648
	// @todo the cache is loaded in load_plugins() but we need to know viewtypes earlier
1649
	$view_path = $CONFIG->viewpath;
1650
	$viewtype_dirs = scandir($view_path);
1651
	foreach ($viewtype_dirs as $viewtype) {
1652
		if (_elgg_is_valid_viewtype($viewtype) && is_dir($view_path . $viewtype)) {
1653
			elgg_register_viewtype($viewtype);
1654
		}
1655
	}
1656
1657
	// set default icon sizes - can be overridden in settings.php or with plugin
1658
	if (!isset($CONFIG->icon_sizes)) {
1659
		$icon_sizes = array(
1660
			'topbar' => array('w' => 16, 'h' => 16, 'square' => true, 'upscale' => true),
1661
			'tiny' => array('w' => 25, 'h' => 25, 'square' => true, 'upscale' => true),
1662
			'small' => array('w' => 40, 'h' => 40, 'square' => true, 'upscale' => true),
1663
			'medium' => array('w' => 100, 'h' => 100, 'square' => true, 'upscale' => true),
1664
			'large' => array('w' => 200, 'h' => 200, 'square' => false, 'upscale' => false),
1665
			'master' => array('w' => 550, 'h' => 550, 'square' => false, 'upscale' => false),
1666
		);
1667
		elgg_set_config('icon_sizes', $icon_sizes);
1668
	}
1669
}
1670
1671
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
1672
	$events->registerHandler('boot', 'system', 'elgg_views_boot');
1673
	$events->registerHandler('init', 'system', 'elgg_views_handle_deprecated_views');
1674
	$events->registerHandler('ready', 'system', '_elgg_views_deprecate_removed_views');
1675
};
1676