Subversion-Projekte lars-tiefland.ci

Revision

Revision 1257 | Zur aktuellen Revision | Details | 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
 *
9
 * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
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/)
32
 * @copyright	Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
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
138
	 * @param	string	an optional argument to pass to the class constructor
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
		{
322
			if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
323
			{
324
				$_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
325
			}
326
			elseif (file_exists(APPPATH.'config/mimes.php'))
327
			{
328
				$_mimes = include(APPPATH.'config/mimes.php');
329
			}
330
			else
331
			{
332
				$_mimes = array();
333
			}
334
		}
335
 
336
		return $_mimes;
337
	}
338
}
339
 
340
// ------------------------------------------------------------------------
341
 
342
if ( ! function_exists('is_https'))
343
{
344
	/**
345
	 * Is HTTPS?
346
	 *
347
	 * Determines if the application is accessed via an encrypted
348
	 * (HTTPS) connection.
349
	 *
350
	 * @return	bool
351
	 */
352
	function is_https()
353
	{
354
		if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
355
		{
356
			return TRUE;
357
		}
358
		elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
359
		{
360
			return TRUE;
361
		}
362
		elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
363
		{
364
			return TRUE;
365
		}
366
 
367
		return FALSE;
368
	}
369
}
370
 
371
// ------------------------------------------------------------------------
372
 
373
if ( ! function_exists('is_cli'))
374
{
375
 
376
	/**
377
	 * Is CLI?
378
	 *
379
	 * Test to see if a request was made from the command line.
380
	 *
381
	 * @return 	bool
382
	 */
383
	function is_cli()
384
	{
385
		return (PHP_SAPI === 'cli' OR defined('STDIN'));
386
	}
387
}
388
 
389
// ------------------------------------------------------------------------
390
 
391
if ( ! function_exists('show_error'))
392
{
393
	/**
394
	 * Error Handler
395
	 *
396
	 * This function lets us invoke the exception class and
397
	 * display errors using the standard error template located
398
	 * in application/views/errors/error_general.php
399
	 * This function will send the error page directly to the
400
	 * browser and exit.
401
	 *
402
	 * @param	string
403
	 * @param	int
404
	 * @param	string
405
	 * @return	void
406
	 */
407
	function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
408
	{
409
		$status_code = abs($status_code);
410
		if ($status_code < 100)
411
		{
412
			$exit_status = $status_code + 9; // 9 is EXIT__AUTO_MIN
413
			if ($exit_status > 125) // 125 is EXIT__AUTO_MAX
414
			{
415
				$exit_status = 1; // EXIT_ERROR
416
			}
417
 
418
			$status_code = 500;
419
		}
420
		else
421
		{
422
			$exit_status = 1; // EXIT_ERROR
423
		}
424
 
425
		$_error =& load_class('Exceptions', 'core');
426
		echo $_error->show_error($heading, $message, 'error_general', $status_code);
427
		exit($exit_status);
428
	}
429
}
430
 
431
// ------------------------------------------------------------------------
432
 
433
if ( ! function_exists('show_404'))
434
{
435
	/**
436
	 * 404 Page Handler
437
	 *
438
	 * This function is similar to the show_error() function above
439
	 * However, instead of the standard error template it displays
440
	 * 404 errors.
441
	 *
442
	 * @param	string
443
	 * @param	bool
444
	 * @return	void
445
	 */
446
	function show_404($page = '', $log_error = TRUE)
447
	{
448
		$_error =& load_class('Exceptions', 'core');
449
		$_error->show_404($page, $log_error);
450
		exit(4); // EXIT_UNKNOWN_FILE
451
	}
452
}
453
 
454
// ------------------------------------------------------------------------
455
 
456
if ( ! function_exists('log_message'))
457
{
458
	/**
459
	 * Error Logging Interface
460
	 *
461
	 * We use this as a simple mechanism to access the logging
462
	 * class and send messages to be logged.
463
	 *
464
	 * @param	string	the error level: 'error', 'debug' or 'info'
465
	 * @param	string	the error message
466
	 * @return	void
467
	 */
468
	function log_message($level, $message)
469
	{
470
		static $_log;
471
 
472
		if ($_log === NULL)
473
		{
474
			// references cannot be directly assigned to static variables, so we use an array
475
			$_log[0] =& load_class('Log', 'core');
476
		}
477
 
478
		$_log[0]->write_log($level, $message);
479
	}
480
}
481
 
482
// ------------------------------------------------------------------------
483
 
484
if ( ! function_exists('set_status_header'))
485
{
486
	/**
487
	 * Set HTTP Status Header
488
	 *
489
	 * @param	int	the status code
490
	 * @param	string
491
	 * @return	void
492
	 */
493
	function set_status_header($code = 200, $text = '')
494
	{
495
		if (is_cli())
496
		{
497
			return;
498
		}
499
 
500
		if (empty($code) OR ! is_numeric($code))
501
		{
502
			show_error('Status codes must be numeric', 500);
503
		}
504
 
505
		if (empty($text))
506
		{
507
			is_int($code) OR $code = (int) $code;
508
			$stati = array(
509
				100	=> 'Continue',
510
				101	=> 'Switching Protocols',
511
 
512
				200	=> 'OK',
513
				201	=> 'Created',
514
				202	=> 'Accepted',
515
				203	=> 'Non-Authoritative Information',
516
				204	=> 'No Content',
517
				205	=> 'Reset Content',
518
				206	=> 'Partial Content',
519
 
520
				300	=> 'Multiple Choices',
521
				301	=> 'Moved Permanently',
522
				302	=> 'Found',
523
				303	=> 'See Other',
524
				304	=> 'Not Modified',
525
				305	=> 'Use Proxy',
526
				307	=> 'Temporary Redirect',
527
 
528
				400	=> 'Bad Request',
529
				401	=> 'Unauthorized',
530
				402	=> 'Payment Required',
531
				403	=> 'Forbidden',
532
				404	=> 'Not Found',
533
				405	=> 'Method Not Allowed',
534
				406	=> 'Not Acceptable',
535
				407	=> 'Proxy Authentication Required',
536
				408	=> 'Request Timeout',
537
				409	=> 'Conflict',
538
				410	=> 'Gone',
539
				411	=> 'Length Required',
540
				412	=> 'Precondition Failed',
541
				413	=> 'Request Entity Too Large',
542
				414	=> 'Request-URI Too Long',
543
				415	=> 'Unsupported Media Type',
544
				416	=> 'Requested Range Not Satisfiable',
545
				417	=> 'Expectation Failed',
546
				422	=> 'Unprocessable Entity',
547
 
548
				500	=> 'Internal Server Error',
549
				501	=> 'Not Implemented',
550
				502	=> 'Bad Gateway',
551
				503	=> 'Service Unavailable',
552
				504	=> 'Gateway Timeout',
553
				505	=> 'HTTP Version Not Supported'
554
			);
555
 
556
			if (isset($stati[$code]))
557
			{
558
				$text = $stati[$code];
559
			}
560
			else
561
			{
562
				show_error('No status text available. Please check your status code number or supply your own message text.', 500);
563
			}
564
		}
565
 
566
		if (strpos(PHP_SAPI, 'cgi') === 0)
567
		{
568
			header('Status: '.$code.' '.$text, TRUE);
569
		}
570
		else
571
		{
572
			$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
573
			header($server_protocol.' '.$code.' '.$text, TRUE, $code);
574
		}
575
	}
576
}
577
 
578
// --------------------------------------------------------------------
579
 
580
if ( ! function_exists('_error_handler'))
581
{
582
	/**
583
	 * Error Handler
584
	 *
585
	 * This is the custom error handler that is declared at the (relative)
586
	 * top of CodeIgniter.php. The main reason we use this is to permit
587
	 * PHP errors to be logged in our own log files since the user may
588
	 * not have access to server logs. Since this function effectively
589
	 * intercepts PHP errors, however, we also need to display errors
590
	 * based on the current error_reporting level.
591
	 * We do that with the use of a PHP error template.
592
	 *
593
	 * @param	int	$severity
594
	 * @param	string	$message
595
	 * @param	string	$filepath
596
	 * @param	int	$line
597
	 * @return	void
598
	 */
599
	function _error_handler($severity, $message, $filepath, $line)
600
	{
601
		$is_error = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
602
 
603
		// When an error occurred, set the status header to '500 Internal Server Error'
604
		// to indicate to the client something went wrong.
605
		// This can't be done within the $_error->show_php_error method because
606
		// it is only called when the display_errors flag is set (which isn't usually
607
		// the case in a production environment) or when errors are ignored because
608
		// they are above the error_reporting threshold.
609
		if ($is_error)
610
		{
611
			set_status_header(500);
612
		}
613
 
614
		// Should we ignore the error? We'll get the current error_reporting
615
		// level and add its bits with the severity bits to find out.
616
		if (($severity & error_reporting()) !== $severity)
617
		{
618
			return;
619
		}
620
 
621
		$_error =& load_class('Exceptions', 'core');
622
		$_error->log_exception($severity, $message, $filepath, $line);
623
 
624
		// Should we display the error?
625
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
626
		{
627
			$_error->show_php_error($severity, $message, $filepath, $line);
628
		}
629
 
630
		// If the error is fatal, the execution of the script should be stopped because
631
		// errors can't be recovered from. Halting the script conforms with PHP's
632
		// default error handling. See http://www.php.net/manual/en/errorfunc.constants.php
633
		if ($is_error)
634
		{
635
			exit(1); // EXIT_ERROR
636
		}
637
	}
638
}
639
 
640
// ------------------------------------------------------------------------
641
 
642
if ( ! function_exists('_exception_handler'))
643
{
644
	/**
645
	 * Exception Handler
646
	 *
647
	 * Sends uncaught exceptions to the logger and displays them
648
	 * only if display_errors is On so that they don't show up in
649
	 * production environments.
650
	 *
651
	 * @param	Exception	$exception
652
	 * @return	void
653
	 */
654
	function _exception_handler($exception)
655
	{
656
		$_error =& load_class('Exceptions', 'core');
657
		$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
658
 
659
		// Should we display the error?
660
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
661
		{
662
			$_error->show_exception($exception);
663
		}
664
 
665
		exit(1); // EXIT_ERROR
666
	}
667
}
668
 
669
// ------------------------------------------------------------------------
670
 
671
if ( ! function_exists('_shutdown_handler'))
672
{
673
	/**
674
	 * Shutdown Handler
675
	 *
676
	 * This is the shutdown handler that is declared at the top
677
	 * of CodeIgniter.php. The main reason we use this is to simulate
678
	 * a complete custom exception handler.
679
	 *
680
	 * E_STRICT is purposively neglected because such events may have
681
	 * been caught. Duplication or none? None is preferred for now.
682
	 *
683
	 * @link	http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
684
	 * @return	void
685
	 */
686
	function _shutdown_handler()
687
	{
688
		$last_error = error_get_last();
689
		if (isset($last_error) &&
690
			($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
691
		{
692
			_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
693
		}
694
	}
695
}
696
 
697
// --------------------------------------------------------------------
698
 
699
if ( ! function_exists('remove_invisible_characters'))
700
{
701
	/**
702
	 * Remove Invisible Characters
703
	 *
704
	 * This prevents sandwiching null characters
705
	 * between ascii characters, like Java\0script.
706
	 *
707
	 * @param	string
708
	 * @param	bool
709
	 * @return	string
710
	 */
711
	function remove_invisible_characters($str, $url_encoded = TRUE)
712
	{
713
		$non_displayables = array();
714
 
715
		// every control character except newline (dec 10),
716
		// carriage return (dec 13) and horizontal tab (dec 09)
717
		if ($url_encoded)
718
		{
719
			$non_displayables[] = '/%0[0-8bcef]/i';	// url encoded 00-08, 11, 12, 14, 15
720
			$non_displayables[] = '/%1[0-9a-f]/i';	// url encoded 16-31
721
		}
722
 
723
		$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';	// 00-08, 11, 12, 14-31, 127
724
 
725
		do
726
		{
727
			$str = preg_replace($non_displayables, '', $str, -1, $count);
728
		}
729
		while ($count);
730
 
731
		return $str;
732
	}
733
}
734
 
735
// ------------------------------------------------------------------------
736
 
737
if ( ! function_exists('html_escape'))
738
{
739
	/**
740
	 * Returns HTML escaped variable.
741
	 *
742
	 * @param	mixed	$var		The input string or array of strings to be escaped.
743
	 * @param	bool	$double_encode	$double_encode set to FALSE prevents escaping twice.
744
	 * @return	mixed			The escaped string or array of strings as a result.
745
	 */
746
	function html_escape($var, $double_encode = TRUE)
747
	{
748
		if (empty($var))
749
		{
750
			return $var;
751
		}
752
 
753
		if (is_array($var))
754
		{
755
			foreach (array_keys($var) as $key)
756
			{
757
				$var[$key] = html_escape($var[$key], $double_encode);
758
			}
759
 
760
			return $var;
761
		}
762
 
763
		return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode);
764
	}
765
}
766
 
767
// ------------------------------------------------------------------------
768
 
769
if ( ! function_exists('_stringify_attributes'))
770
{
771
	/**
772
	 * Stringify attributes for use in HTML tags.
773
	 *
774
	 * Helper function used to convert a string, array, or object
775
	 * of attributes to a string.
776
	 *
777
	 * @param	mixed	string, array, object
778
	 * @param	bool
779
	 * @return	string
780
	 */
781
	function _stringify_attributes($attributes, $js = FALSE)
782
	{
783
		$atts = NULL;
784
 
785
		if (empty($attributes))
786
		{
787
			return $atts;
788
		}
789
 
790
		if (is_string($attributes))
791
		{
792
			return ' '.$attributes;
793
		}
794
 
795
		$attributes = (array) $attributes;
796
 
797
		foreach ($attributes as $key => $val)
798
		{
799
			$atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
800
		}
801
 
802
		return rtrim($atts, ',');
803
	}
804
}
805
 
806
// ------------------------------------------------------------------------
807
 
808
if ( ! function_exists('function_usable'))
809
{
810
	/**
811
	 * Function usable
812
	 *
813
	 * Executes a function_exists() check, and if the Suhosin PHP
814
	 * extension is loaded - checks whether the function that is
815
	 * checked might be disabled in there as well.
816
	 *
817
	 * This is useful as function_exists() will return FALSE for
818
	 * functions disabled via the *disable_functions* php.ini
819
	 * setting, but not for *suhosin.executor.func.blacklist* and
820
	 * *suhosin.executor.disable_eval*. These settings will just
821
	 * terminate script execution if a disabled function is executed.
822
	 *
823
	 * The above described behavior turned out to be a bug in Suhosin,
824
	 * but even though a fix was commited for 0.9.34 on 2012-02-12,
825
	 * that version is yet to be released. This function will therefore
826
	 * be just temporary, but would probably be kept for a few years.
827
	 *
828
	 * @link	http://www.hardened-php.net/suhosin/
829
	 * @param	string	$function_name	Function to check for
830
	 * @return	bool	TRUE if the function exists and is safe to call,
831
	 *			FALSE otherwise.
832
	 */
833
	function function_usable($function_name)
834
	{
835
		static $_suhosin_func_blacklist;
836
 
837
		if (function_exists($function_name))
838
		{
839
			if ( ! isset($_suhosin_func_blacklist))
840
			{
841
				$_suhosin_func_blacklist = extension_loaded('suhosin')
842
					? explode(',', trim(ini_get('suhosin.executor.func.blacklist')))
843
					: array();
844
			}
845
 
846
			return ! in_array($function_name, $_suhosin_func_blacklist, TRUE);
847
		}
848
 
849
		return FALSE;
850
	}
851
}