Subversion-Projekte lars-tiefland.ci

Revision

Revision 2254 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
2257 lars 9
 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
68 lars 10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
2257 lars 32
 * @copyright	Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
68 lars 33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
 
40
/**
41
 * Common Functions
42
 *
43
 * Loads the base classes and executes the request.
44
 *
45
 * @package		CodeIgniter
46
 * @subpackage	CodeIgniter
47
 * @category	Common Functions
48
 * @author		EllisLab Dev Team
49
 * @link		https://codeigniter.com/user_guide/
50
 */
51
 
52
// ------------------------------------------------------------------------
53
 
54
if ( ! function_exists('is_php'))
55
{
56
	/**
57
	 * Determines if the current version of PHP is equal to or greater than the supplied value
58
	 *
59
	 * @param	string
60
	 * @return	bool	TRUE if the current version is $version or higher
61
	 */
62
	function is_php($version)
63
	{
64
		static $_is_php;
65
		$version = (string) $version;
66
 
67
		if ( ! isset($_is_php[$version]))
68
		{
69
			$_is_php[$version] = version_compare(PHP_VERSION, $version, '>=');
70
		}
71
 
72
		return $_is_php[$version];
73
	}
74
}
75
 
76
// ------------------------------------------------------------------------
77
 
78
if ( ! function_exists('is_really_writable'))
79
{
80
	/**
81
	 * Tests for file writability
82
	 *
83
	 * is_writable() returns TRUE on Windows servers when you really can't write to
84
	 * the file, based on the read-only attribute. is_writable() is also unreliable
85
	 * on Unix servers if safe_mode is on.
86
	 *
87
	 * @link	https://bugs.php.net/bug.php?id=54709
88
	 * @param	string
89
	 * @return	bool
90
	 */
91
	function is_really_writable($file)
92
	{
93
		// If we're on a Unix server with safe_mode off we call is_writable
94
		if (DIRECTORY_SEPARATOR === '/' && (is_php('5.4') OR ! ini_get('safe_mode')))
95
		{
96
			return is_writable($file);
97
		}
98
 
99
		/* For Windows servers and safe_mode "on" installations we'll actually
100
		 * write a file then read it. Bah...
101
		 */
102
		if (is_dir($file))
103
		{
104
			$file = rtrim($file, '/').'/'.md5(mt_rand());
105
			if (($fp = @fopen($file, 'ab')) === FALSE)
106
			{
107
				return FALSE;
108
			}
109
 
110
			fclose($fp);
111
			@chmod($file, 0777);
112
			@unlink($file);
113
			return TRUE;
114
		}
115
		elseif ( ! is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE)
116
		{
117
			return FALSE;
118
		}
119
 
120
		fclose($fp);
121
		return TRUE;
122
	}
123
}
124
 
125
// ------------------------------------------------------------------------
126
 
127
if ( ! function_exists('load_class'))
128
{
129
	/**
130
	 * Class registry
131
	 *
132
	 * This function acts as a singleton. If the requested class does not
133
	 * exist it is instantiated and set to a static variable. If it has
134
	 * previously been instantiated the variable is returned.
135
	 *
136
	 * @param	string	the class name being requested
137
	 * @param	string	the directory where the class should be found
2107 lars 138
	 * @param	mixed	an optional argument to pass to the class constructor
68 lars 139
	 * @return	object
140
	 */
141
	function &load_class($class, $directory = 'libraries', $param = NULL)
142
	{
143
		static $_classes = array();
144
 
145
		// Does the class exist? If so, we're done...
146
		if (isset($_classes[$class]))
147
		{
148
			return $_classes[$class];
149
		}
150
 
151
		$name = FALSE;
152
 
153
		// Look for the class first in the local application/libraries folder
154
		// then in the native system/libraries folder
155
		foreach (array(APPPATH, BASEPATH) as $path)
156
		{
157
			if (file_exists($path.$directory.'/'.$class.'.php'))
158
			{
159
				$name = 'CI_'.$class;
160
 
161
				if (class_exists($name, FALSE) === FALSE)
162
				{
163
					require_once($path.$directory.'/'.$class.'.php');
164
				}
165
 
166
				break;
167
			}
168
		}
169
 
170
		// Is the request a class extension? If so we load it too
171
		if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'))
172
		{
173
			$name = config_item('subclass_prefix').$class;
174
 
175
			if (class_exists($name, FALSE) === FALSE)
176
			{
177
				require_once(APPPATH.$directory.'/'.$name.'.php');
178
			}
179
		}
180
 
181
		// Did we find the class?
182
		if ($name === FALSE)
183
		{
184
			// Note: We use exit() rather than show_error() in order to avoid a
185
			// self-referencing loop with the Exceptions class
186
			set_status_header(503);
187
			echo 'Unable to locate the specified class: '.$class.'.php';
188
			exit(5); // EXIT_UNK_CLASS
189
		}
190
 
191
		// Keep track of what we just loaded
192
		is_loaded($class);
193
 
194
		$_classes[$class] = isset($param)
195
			? new $name($param)
196
			: new $name();
197
		return $_classes[$class];
198
	}
199
}
200
 
201
// --------------------------------------------------------------------
202
 
203
if ( ! function_exists('is_loaded'))
204
{
205
	/**
206
	 * Keeps track of which libraries have been loaded. This function is
207
	 * called by the load_class() function above
208
	 *
209
	 * @param	string
210
	 * @return	array
211
	 */
212
	function &is_loaded($class = '')
213
	{
214
		static $_is_loaded = array();
215
 
216
		if ($class !== '')
217
		{
218
			$_is_loaded[strtolower($class)] = $class;
219
		}
220
 
221
		return $_is_loaded;
222
	}
223
}
224
 
225
// ------------------------------------------------------------------------
226
 
227
if ( ! function_exists('get_config'))
228
{
229
	/**
230
	 * Loads the main config.php file
231
	 *
232
	 * This function lets us grab the config file even if the Config class
233
	 * hasn't been instantiated yet
234
	 *
235
	 * @param	array
236
	 * @return	array
237
	 */
238
	function &get_config(Array $replace = array())
239
	{
240
		static $config;
241
 
242
		if (empty($config))
243
		{
244
			$file_path = APPPATH.'config/config.php';
245
			$found = FALSE;
246
			if (file_exists($file_path))
247
			{
248
				$found = TRUE;
249
				require($file_path);
250
			}
251
 
252
			// Is the config file in the environment folder?
253
			if (file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
254
			{
255
				require($file_path);
256
			}
257
			elseif ( ! $found)
258
			{
259
				set_status_header(503);
260
				echo 'The configuration file does not exist.';
261
				exit(3); // EXIT_CONFIG
262
			}
263
 
264
			// Does the $config array exist in the file?
265
			if ( ! isset($config) OR ! is_array($config))
266
			{
267
				set_status_header(503);
268
				echo 'Your config file does not appear to be formatted correctly.';
269
				exit(3); // EXIT_CONFIG
270
			}
271
		}
272
 
273
		// Are any values being dynamically added or replaced?
274
		foreach ($replace as $key => $val)
275
		{
276
			$config[$key] = $val;
277
		}
278
 
279
		return $config;
280
	}
281
}
282
 
283
// ------------------------------------------------------------------------
284
 
285
if ( ! function_exists('config_item'))
286
{
287
	/**
288
	 * Returns the specified config item
289
	 *
290
	 * @param	string
291
	 * @return	mixed
292
	 */
293
	function config_item($item)
294
	{
295
		static $_config;
296
 
297
		if (empty($_config))
298
		{
299
			// references cannot be directly assigned to static variables, so we use an array
300
			$_config[0] =& get_config();
301
		}
302
 
303
		return isset($_config[0][$item]) ? $_config[0][$item] : NULL;
304
	}
305
}
306
 
307
// ------------------------------------------------------------------------
308
 
309
if ( ! function_exists('get_mimes'))
310
{
311
	/**
312
	 * Returns the MIME types array from config/mimes.php
313
	 *
314
	 * @return	array
315
	 */
316
	function &get_mimes()
317
	{
318
		static $_mimes;
319
 
320
		if (empty($_mimes))
321
		{
2107 lars 322
			$_mimes = file_exists(APPPATH.'config/mimes.php')
323
				? include(APPPATH.'config/mimes.php')
324
				: array();
325
 
68 lars 326
			if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
327
			{
2107 lars 328
				$_mimes = array_merge($_mimes, include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'));
68 lars 329
			}
330
		}
331
 
332
		return $_mimes;
333
	}
334
}
335
 
336
// ------------------------------------------------------------------------
337
 
338
if ( ! function_exists('is_https'))
339
{
340
	/**
341
	 * Is HTTPS?
342
	 *
343
	 * Determines if the application is accessed via an encrypted
344
	 * (HTTPS) connection.
345
	 *
346
	 * @return	bool
347
	 */
348
	function is_https()
349
	{
350
		if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
351
		{
352
			return TRUE;
353
		}
354
		elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
355
		{
356
			return TRUE;
357
		}
358
		elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
359
		{
360
			return TRUE;
361
		}
362
 
363
		return FALSE;
364
	}
365
}
366
 
367
// ------------------------------------------------------------------------
368
 
369
if ( ! function_exists('is_cli'))
370
{
371
 
372
	/**
373
	 * Is CLI?
374
	 *
375
	 * Test to see if a request was made from the command line.
376
	 *
377
	 * @return 	bool
378
	 */
379
	function is_cli()
380
	{
381
		return (PHP_SAPI === 'cli' OR defined('STDIN'));
382
	}
383
}
384
 
385
// ------------------------------------------------------------------------
386
 
387
if ( ! function_exists('show_error'))
388
{
389
	/**
390
	 * Error Handler
391
	 *
392
	 * This function lets us invoke the exception class and
393
	 * display errors using the standard error template located
394
	 * in application/views/errors/error_general.php
395
	 * This function will send the error page directly to the
396
	 * browser and exit.
397
	 *
398
	 * @param	string
399
	 * @param	int
400
	 * @param	string
401
	 * @return	void
402
	 */
403
	function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
404
	{
405
		$status_code = abs($status_code);
406
		if ($status_code < 100)
407
		{
408
			$exit_status = $status_code + 9; // 9 is EXIT__AUTO_MIN
409
			$status_code = 500;
410
		}
411
		else
412
		{
413
			$exit_status = 1; // EXIT_ERROR
414
		}
415
 
416
		$_error =& load_class('Exceptions', 'core');
417
		echo $_error->show_error($heading, $message, 'error_general', $status_code);
418
		exit($exit_status);
419
	}
420
}
421
 
422
// ------------------------------------------------------------------------
423
 
424
if ( ! function_exists('show_404'))
425
{
426
	/**
427
	 * 404 Page Handler
428
	 *
429
	 * This function is similar to the show_error() function above
430
	 * However, instead of the standard error template it displays
431
	 * 404 errors.
432
	 *
433
	 * @param	string
434
	 * @param	bool
435
	 * @return	void
436
	 */
437
	function show_404($page = '', $log_error = TRUE)
438
	{
439
		$_error =& load_class('Exceptions', 'core');
440
		$_error->show_404($page, $log_error);
441
		exit(4); // EXIT_UNKNOWN_FILE
442
	}
443
}
444
 
445
// ------------------------------------------------------------------------
446
 
447
if ( ! function_exists('log_message'))
448
{
449
	/**
450
	 * Error Logging Interface
451
	 *
452
	 * We use this as a simple mechanism to access the logging
453
	 * class and send messages to be logged.
454
	 *
455
	 * @param	string	the error level: 'error', 'debug' or 'info'
456
	 * @param	string	the error message
457
	 * @return	void
458
	 */
459
	function log_message($level, $message)
460
	{
461
		static $_log;
462
 
463
		if ($_log === NULL)
464
		{
465
			// references cannot be directly assigned to static variables, so we use an array
466
			$_log[0] =& load_class('Log', 'core');
467
		}
468
 
469
		$_log[0]->write_log($level, $message);
470
	}
471
}
472
 
473
// ------------------------------------------------------------------------
474
 
475
if ( ! function_exists('set_status_header'))
476
{
477
	/**
478
	 * Set HTTP Status Header
479
	 *
480
	 * @param	int	the status code
481
	 * @param	string
482
	 * @return	void
483
	 */
484
	function set_status_header($code = 200, $text = '')
485
	{
486
		if (is_cli())
487
		{
488
			return;
489
		}
490
 
491
		if (empty($code) OR ! is_numeric($code))
492
		{
493
			show_error('Status codes must be numeric', 500);
494
		}
495
 
496
		if (empty($text))
497
		{
498
			is_int($code) OR $code = (int) $code;
499
			$stati = array(
500
				100	=> 'Continue',
501
				101	=> 'Switching Protocols',
502
 
503
				200	=> 'OK',
504
				201	=> 'Created',
505
				202	=> 'Accepted',
506
				203	=> 'Non-Authoritative Information',
507
				204	=> 'No Content',
508
				205	=> 'Reset Content',
509
				206	=> 'Partial Content',
510
 
511
				300	=> 'Multiple Choices',
512
				301	=> 'Moved Permanently',
513
				302	=> 'Found',
514
				303	=> 'See Other',
515
				304	=> 'Not Modified',
516
				305	=> 'Use Proxy',
517
				307	=> 'Temporary Redirect',
518
 
519
				400	=> 'Bad Request',
520
				401	=> 'Unauthorized',
521
				402	=> 'Payment Required',
522
				403	=> 'Forbidden',
523
				404	=> 'Not Found',
524
				405	=> 'Method Not Allowed',
525
				406	=> 'Not Acceptable',
526
				407	=> 'Proxy Authentication Required',
527
				408	=> 'Request Timeout',
528
				409	=> 'Conflict',
529
				410	=> 'Gone',
530
				411	=> 'Length Required',
531
				412	=> 'Precondition Failed',
532
				413	=> 'Request Entity Too Large',
533
				414	=> 'Request-URI Too Long',
534
				415	=> 'Unsupported Media Type',
535
				416	=> 'Requested Range Not Satisfiable',
536
				417	=> 'Expectation Failed',
537
				422	=> 'Unprocessable Entity',
1257 lars 538
				426	=> 'Upgrade Required',
539
				428	=> 'Precondition Required',
540
				429	=> 'Too Many Requests',
541
				431	=> 'Request Header Fields Too Large',
68 lars 542
 
543
				500	=> 'Internal Server Error',
544
				501	=> 'Not Implemented',
545
				502	=> 'Bad Gateway',
546
				503	=> 'Service Unavailable',
547
				504	=> 'Gateway Timeout',
1257 lars 548
				505	=> 'HTTP Version Not Supported',
549
				511	=> 'Network Authentication Required',
68 lars 550
			);
551
 
552
			if (isset($stati[$code]))
553
			{
554
				$text = $stati[$code];
555
			}
556
			else
557
			{
558
				show_error('No status text available. Please check your status code number or supply your own message text.', 500);
559
			}
560
		}
561
 
562
		if (strpos(PHP_SAPI, 'cgi') === 0)
563
		{
564
			header('Status: '.$code.' '.$text, TRUE);
2107 lars 565
			return;
68 lars 566
		}
2107 lars 567
 
568
		$server_protocol = (isset($_SERVER['SERVER_PROTOCOL']) && in_array($_SERVER['SERVER_PROTOCOL'], array('HTTP/1.0', 'HTTP/1.1', 'HTTP/2'), TRUE))
569
			? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
570
		header($server_protocol.' '.$code.' '.$text, TRUE, $code);
68 lars 571
	}
572
}
573
 
574
// --------------------------------------------------------------------
575
 
576
if ( ! function_exists('_error_handler'))
577
{
578
	/**
579
	 * Error Handler
580
	 *
581
	 * This is the custom error handler that is declared at the (relative)
582
	 * top of CodeIgniter.php. The main reason we use this is to permit
583
	 * PHP errors to be logged in our own log files since the user may
584
	 * not have access to server logs. Since this function effectively
585
	 * intercepts PHP errors, however, we also need to display errors
586
	 * based on the current error_reporting level.
587
	 * We do that with the use of a PHP error template.
588
	 *
589
	 * @param	int	$severity
590
	 * @param	string	$message
591
	 * @param	string	$filepath
592
	 * @param	int	$line
593
	 * @return	void
594
	 */
595
	function _error_handler($severity, $message, $filepath, $line)
596
	{
1257 lars 597
		$is_error = (((E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
68 lars 598
 
599
		// When an error occurred, set the status header to '500 Internal Server Error'
600
		// to indicate to the client something went wrong.
601
		// This can't be done within the $_error->show_php_error method because
602
		// it is only called when the display_errors flag is set (which isn't usually
603
		// the case in a production environment) or when errors are ignored because
604
		// they are above the error_reporting threshold.
605
		if ($is_error)
606
		{
607
			set_status_header(500);
608
		}
609
 
610
		// Should we ignore the error? We'll get the current error_reporting
611
		// level and add its bits with the severity bits to find out.
612
		if (($severity & error_reporting()) !== $severity)
613
		{
614
			return;
615
		}
616
 
617
		$_error =& load_class('Exceptions', 'core');
618
		$_error->log_exception($severity, $message, $filepath, $line);
619
 
620
		// Should we display the error?
621
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
622
		{
623
			$_error->show_php_error($severity, $message, $filepath, $line);
624
		}
625
 
626
		// If the error is fatal, the execution of the script should be stopped because
627
		// errors can't be recovered from. Halting the script conforms with PHP's
628
		// default error handling. See http://www.php.net/manual/en/errorfunc.constants.php
629
		if ($is_error)
630
		{
631
			exit(1); // EXIT_ERROR
632
		}
633
	}
634
}
635
 
636
// ------------------------------------------------------------------------
637
 
638
if ( ! function_exists('_exception_handler'))
639
{
640
	/**
641
	 * Exception Handler
642
	 *
643
	 * Sends uncaught exceptions to the logger and displays them
644
	 * only if display_errors is On so that they don't show up in
645
	 * production environments.
646
	 *
647
	 * @param	Exception	$exception
648
	 * @return	void
649
	 */
650
	function _exception_handler($exception)
651
	{
652
		$_error =& load_class('Exceptions', 'core');
653
		$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
654
 
1257 lars 655
		is_cli() OR set_status_header(500);
68 lars 656
		// Should we display the error?
657
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
658
		{
659
			$_error->show_exception($exception);
660
		}
661
 
662
		exit(1); // EXIT_ERROR
663
	}
664
}
665
 
666
// ------------------------------------------------------------------------
667
 
668
if ( ! function_exists('_shutdown_handler'))
669
{
670
	/**
671
	 * Shutdown Handler
672
	 *
673
	 * This is the shutdown handler that is declared at the top
674
	 * of CodeIgniter.php. The main reason we use this is to simulate
675
	 * a complete custom exception handler.
676
	 *
677
	 * E_STRICT is purposively neglected because such events may have
678
	 * been caught. Duplication or none? None is preferred for now.
679
	 *
680
	 * @link	http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
681
	 * @return	void
682
	 */
683
	function _shutdown_handler()
684
	{
685
		$last_error = error_get_last();
686
		if (isset($last_error) &&
687
			($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
688
		{
689
			_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
690
		}
691
	}
692
}
693
 
694
// --------------------------------------------------------------------
695
 
696
if ( ! function_exists('remove_invisible_characters'))
697
{
698
	/**
699
	 * Remove Invisible Characters
700
	 *
701
	 * This prevents sandwiching null characters
702
	 * between ascii characters, like Java\0script.
703
	 *
704
	 * @param	string
705
	 * @param	bool
706
	 * @return	string
707
	 */
708
	function remove_invisible_characters($str, $url_encoded = TRUE)
709
	{
710
		$non_displayables = array();
711
 
712
		// every control character except newline (dec 10),
713
		// carriage return (dec 13) and horizontal tab (dec 09)
714
		if ($url_encoded)
715
		{
716
			$non_displayables[] = '/%0[0-8bcef]/i';	// url encoded 00-08, 11, 12, 14, 15
717
			$non_displayables[] = '/%1[0-9a-f]/i';	// url encoded 16-31
2107 lars 718
			$non_displayables[] = '/%7f/i';	// url encoded 127
68 lars 719
		}
720
 
721
		$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';	// 00-08, 11, 12, 14-31, 127
722
 
723
		do
724
		{
725
			$str = preg_replace($non_displayables, '', $str, -1, $count);
726
		}
727
		while ($count);
728
 
729
		return $str;
730
	}
731
}
732
 
733
// ------------------------------------------------------------------------
734
 
735
if ( ! function_exists('html_escape'))
736
{
737
	/**
738
	 * Returns HTML escaped variable.
739
	 *
740
	 * @param	mixed	$var		The input string or array of strings to be escaped.
741
	 * @param	bool	$double_encode	$double_encode set to FALSE prevents escaping twice.
742
	 * @return	mixed			The escaped string or array of strings as a result.
743
	 */
744
	function html_escape($var, $double_encode = TRUE)
745
	{
746
		if (empty($var))
747
		{
748
			return $var;
749
		}
750
 
751
		if (is_array($var))
752
		{
753
			foreach (array_keys($var) as $key)
754
			{
755
				$var[$key] = html_escape($var[$key], $double_encode);
756
			}
757
 
758
			return $var;
759
		}
760
 
761
		return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode);
762
	}
763
}
764
 
765
// ------------------------------------------------------------------------
766
 
767
if ( ! function_exists('_stringify_attributes'))
768
{
769
	/**
770
	 * Stringify attributes for use in HTML tags.
771
	 *
772
	 * Helper function used to convert a string, array, or object
773
	 * of attributes to a string.
774
	 *
775
	 * @param	mixed	string, array, object
776
	 * @param	bool
777
	 * @return	string
778
	 */
779
	function _stringify_attributes($attributes, $js = FALSE)
780
	{
781
		$atts = NULL;
782
 
783
		if (empty($attributes))
784
		{
785
			return $atts;
786
		}
787
 
788
		if (is_string($attributes))
789
		{
790
			return ' '.$attributes;
791
		}
792
 
793
		$attributes = (array) $attributes;
794
 
795
		foreach ($attributes as $key => $val)
796
		{
797
			$atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
798
		}
799
 
800
		return rtrim($atts, ',');
801
	}
802
}
803
 
804
// ------------------------------------------------------------------------
805
 
806
if ( ! function_exists('function_usable'))
807
{
808
	/**
809
	 * Function usable
810
	 *
811
	 * Executes a function_exists() check, and if the Suhosin PHP
812
	 * extension is loaded - checks whether the function that is
813
	 * checked might be disabled in there as well.
814
	 *
815
	 * This is useful as function_exists() will return FALSE for
816
	 * functions disabled via the *disable_functions* php.ini
817
	 * setting, but not for *suhosin.executor.func.blacklist* and
818
	 * *suhosin.executor.disable_eval*. These settings will just
819
	 * terminate script execution if a disabled function is executed.
820
	 *
821
	 * The above described behavior turned out to be a bug in Suhosin,
2107 lars 822
	 * but even though a fix was committed for 0.9.34 on 2012-02-12,
68 lars 823
	 * that version is yet to be released. This function will therefore
824
	 * be just temporary, but would probably be kept for a few years.
825
	 *
826
	 * @link	http://www.hardened-php.net/suhosin/
827
	 * @param	string	$function_name	Function to check for
828
	 * @return	bool	TRUE if the function exists and is safe to call,
829
	 *			FALSE otherwise.
830
	 */
831
	function function_usable($function_name)
832
	{
833
		static $_suhosin_func_blacklist;
834
 
835
		if (function_exists($function_name))
836
		{
837
			if ( ! isset($_suhosin_func_blacklist))
838
			{
839
				$_suhosin_func_blacklist = extension_loaded('suhosin')
840
					? explode(',', trim(ini_get('suhosin.executor.func.blacklist')))
841
					: array();
842
			}
843
 
844
			return ! in_array($function_name, $_suhosin_func_blacklist, TRUE);
845
		}
846
 
847
		return FALSE;
848
	}
849
}