Passed
Push — 1.0.0-dev ( 9c9ab7...066288 )
by nguereza
02:38
created

set_http_status_header()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 63
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 52
nc 9
nop 2
dl 0
loc 63
rs 8.7361
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
	defined('ROOT_PATH') || exit('Access denied');
3
	/**
4
	 * TNH Framework
5
	 *
6
	 * A simple PHP framework using HMVC architecture
7
	 *
8
	 * This content is released under the GNU GPL License (GPL)
9
	 *
10
	 * Copyright (C) 2017 Tony NGUEREZA
11
	 *
12
	 * This program is free software; you can redistribute it and/or
13
	 * modify it under the terms of the GNU General Public License
14
	 * as published by the Free Software Foundation; either version 3
15
	 * of the License, or (at your option) any later version.
16
	 *
17
	 * This program is distributed in the hope that it will be useful,
18
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
	 * GNU General Public License for more details.
21
	 *
22
	 * You should have received a copy of the GNU General Public License
23
	 * along with this program; if not, write to the Free Software
24
	 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
	*/
26
27
	/**
28
	 *  @file common.php
29
	 *  
30
	 *  Contains most of the commons functions used by the system
31
	 *  
32
	 *  @package	core
33
	 *  @author	Tony NGUEREZA
34
	 *  @copyright	Copyright (c) 2017
35
	 *  @license	https://opensource.org/licenses/gpl-3.0.html GNU GPL License (GPL)
36
	 *  @link	http://www.iacademy.cf
37
	 *  @version 1.0.0
38
	 *  @filesource
39
	 */
40
	
41
42
	/**
43
	 * This function is the class loader helper is used if the library "Loader" not yet loaded
44
	 * he load the class once
45
	 * @param  string $class  the class name to be loaded
46
	 * @param  string $dir    the directory where to find the class
47
	 * @param  mixed $params the parameter to pass as argument to the constructor of the class
48
	 * @codeCoverageIgnore
49
	 * 
50
	 * @return object         the instance of the loaded class
51
	 */
52
	function & class_loader($class, $dir = 'libraries', $params = null){
53
		//put the first letter of class to upper case 
54
		$class = ucfirst($class);
55
		static $classes = array();
56
		if (isset($classes[$class]) /*hack for duplicate log Logger name*/ && $class != 'Log'){
57
			return $classes[$class];
58
		}
59
		$found = false;
60
		foreach (array(ROOT_PATH, CORE_PATH) as $path) {
61
			$file = $path . $dir . '/' . $class . '.php';
62
			if (file_exists($file)){
63
				if (class_exists($class, false) === false){
64
					require_once $file;
65
				}
66
				//already found
67
				$found = true;
68
				break;
69
			}
70
		}
71
		if (! $found){
72
			//can't use show_error() at this time because some dependencies not yet loaded
73
			set_http_status_header(503);
74
			echo 'Cannot find the class [' . $class . ']';
75
			die();
76
		}
77
		
78
		/*
79
		   TODO use the best method to get the Log instance
80
		 */
81
		if ($class == 'Log'){
82
			//can't use the instruction like "return new Log()" 
83
			//because we need return the reference instance of the loaded class.
84
			$log = new Log();
85
			return $log;
86
		}
87
		//track of loaded classes
88
		class_loaded($class);
89
		
90
		//record the class instance
91
		$classes[$class] = isset($params) ? new $class($params) : new $class();
92
		
93
		return $classes[$class];
94
	}
95
96
	/**
97
	 * This function is the helper to record the loaded classes
98
	 * @param  string $class the loaded class name
99
	 * @codeCoverageIgnore
100
	 * 
101
	 * @return array        the list of the loaded classes
102
	 */
103
	function & class_loaded($class = null){
104
		static $list = array();
105
		if ($class !== null){
106
			$list[strtolower($class)] = $class;
107
		}
108
		return $list;
109
	}
110
111
	/**
112
	 * This function is used to load the configurations in the case the "Config" library not yet loaded
113
	 * @param  array  $overwrite_values if need overwrite the existing configuration
114
	 * @codeCoverageIgnore
115
	 * 
116
	 * @return array                   the configurations values
117
	 */
118
	function & load_configurations(array $overwrite_values = array()){
119
		static $config;
120
		if (empty($config)){
121
			$file = CONFIG_PATH . 'config.php';
122
			$found = false;
123
			if (file_exists($file)){
124
				require_once $file;
125
				$found = true;
126
			}
127
			if (! $found){
128
				set_http_status_header(503);
129
				echo 'Unable to find the configuration file [' . $file . ']';
130
				die();
131
			}
132
		}
133
		foreach ($overwrite_values as $key => $value) {
134
			$config[$key] = $value;
135
		}
136
		return $config;
137
	}
138
139
	/**
140
	 * This function is the helper to get the config value in case the "Config" library not yet loaded
141
	 * @param  string $key     the config item to get the vale
142
	 * @param  mixed $default the default value to return if can't find the config item in the configuration
143
	 * @test
144
	 * 
145
	 * @return mixed          the config value
146
	 */
147
	function get_config($key, $default = null){
148
		static $cfg;
149
		if (empty($cfg)){
150
			$cfg[0] = & load_configurations();
151
		}
152
		return array_key_exists($key, $cfg[0]) ? $cfg[0][$key] : $default;
153
	}
154
155
	/**
156
	 * This function is a helper to logging message
157
	 * @param  string $level   the log level "ERROR", "DEBUG", "INFO", etc.
158
	 * @param  string $message the log message to be saved
159
	 * @param  string $logger  the logger to use if is set
160
	 * 
161
	 * @codeCoverageIgnore
162
	 */
163
	function save_to_log($level, $message, $logger = null){
164
		$log =& class_loader('Log', 'classes');
165
		if ($logger){
166
			$log->setLogger($logger);
167
		}
168
		$log->writeLog($message, $level);
169
	}
170
171
	/**
172
	 * Set the HTTP status header
173
	 * @param integer $code the HTTP status code
174
	 * @param string  $text the HTTP status text
175
	 * 
176
	 * @codeCoverageIgnore
177
	 */
178
	function set_http_status_header($code = 200, $text = null){
179
		if (empty($text)){
180
			$http_status = array(
181
								100 => 'Continue',
182
								101 => 'Switching Protocols',
183
184
								200 => 'OK',
185
								201 => 'Created',
186
								202 => 'Accepted',
187
								203 => 'Non-Authoritative Information',
188
								204 => 'No Content',
189
								205 => 'Reset Content',
190
								206 => 'Partial Content',
191
192
								300 => 'Multiple Choices',
193
								301 => 'Moved Permanently',
194
								302 => 'Found',
195
								303 => 'See Other',
196
								304 => 'Not Modified',
197
								305 => 'Use Proxy',
198
								307 => 'Temporary Redirect',
199
200
								400 => 'Bad Request',
201
								401 => 'Unauthorized',
202
								402 => 'Payment Required',
203
								403 => 'Forbidden',
204
								404 => 'Not Found',
205
								405 => 'Method Not Allowed',
206
								406 => 'Not Acceptable',
207
								407 => 'Proxy Authentication Required',
208
								408 => 'Request Timeout',
209
								409 => 'Conflict',
210
								410 => 'Gone',
211
								411 => 'Length Required',
212
								412 => 'Precondition Failed',
213
								413 => 'Request Entity Too Large',
214
								414 => 'Request-URI Too Long',
215
								415 => 'Unsupported Media Type',
216
								416 => 'Requested Range Not Satisfiable',
217
								417 => 'Expectation Failed',
218
								418 => 'I\'m a teapot',
219
220
								500 => 'Internal Server Error',
221
								501 => 'Not Implemented',
222
								502 => 'Bad Gateway',
223
								503 => 'Service Unavailable',
224
								504 => 'Gateway Timeout',
225
								505 => 'HTTP Version Not Supported',
226
							);
227
			if (isset($http_status[$code])){
228
				$text = $http_status[$code];
229
			}
230
			else{
231
				show_error('No HTTP status text found for your code please check it.');
232
			}
233
		}
234
		
235
		if (strpos(php_sapi_name(), 'cgi') === 0){
236
			header('Status: ' . $code . ' ' . $text, TRUE);
237
		}
238
		else{
239
			$proto = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
240
			header($proto . ' ' . $code . ' ' . $text, TRUE, $code);
241
		}
242
	}
243
244
	/**
245
	 *  This function displays an error message to the user and ends the execution of the script.
246
	 *  
247
	 *  @param string $msg the message to display
248
	 *  @param string $title the message title: "error", "info", "warning", etc.
249
	 *  @param boolean $logging either to save error in log
250
	 *  
251
	 *  @codeCoverageIgnore
252
	 */
253
	function show_error($msg, $title = 'error', $logging = true){
254
		$title = strtoupper($title);
255
		$data = array();
256
		$data['error'] = $msg;
257
		$data['title'] = $title;
258
		if ($logging){
259
			save_to_log('error', '['.$title.'] '.strip_tags($msg), 'GLOBAL::ERROR');
260
		}
261
		$response = & class_loader('Response', 'classes');
262
		$response->sendError($data);
263
		die();
264
	}
265
266
	/**
267
	 *  Check whether the protocol used is "https" or not
268
	 *  That is, the web server is configured to use a secure connection.
269
	 *  @codeCoverageIgnore
270
	 *  
271
	 *  @return boolean true if the web server uses the https protocol, false if not.
272
	 */
273
	function is_https(){
274
		/*
275
		* some servers pass the "HTTPS" parameter in the server variable,
276
		* if is the case, check if the value is "on", "true", "1".
277
		*/
278
		if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off'){
279
			return true;
280
		}
281
		else if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'){
282
			return true;
283
		}
284
		else if (isset($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off'){
285
			return true;
286
		}
287
		return false;
288
	}
289
	
290
	/**
291
	 *  This function is used to check the URL format of the given string argument. 
292
	 *  The address is valid if the protocol is http, https, ftp, etc.
293
	 *
294
	 *  @param string $url the URL address to check
295
	 *  @test
296
	 *  
297
	 *  @return boolean true if is a valid URL address or false.
298
	 */
299
	function is_url($url){
300
		return preg_match('/^(http|https|ftp):\/\/(.*)/', $url) == 1;
301
	}
302
	
303
	/**
304
	 *  Function defined to load controller
305
	 *  
306
	 *  @param string $controllerClass the controller class name to be loaded
307
	 *  @codeCoverageIgnore
308
	 */
309
	function autoload_controller($controllerClass){
310
		if (file_exists($path = APPS_CONTROLLER_PATH . $controllerClass . '.php')){
311
			require_once $path;
312
		}
313
	}
314
	
315
	/**
316
	 *  Function defined for handling PHP exception error message, 
317
	 *  it displays an error message using the function "show_error"
318
	 *  
319
	 *  @param object $ex instance of the "Exception" class or a derived class
320
	 *  @codeCoverageIgnore
321
	 *  
322
	 *  @return boolean
323
	 */
324
	function php_exception_handler($ex){
325
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))){
326
			show_error('An exception is occured in file '. $ex->getFile() .' at line ' . $ex->getLine() . ' raison : ' . $ex->getMessage(), 'PHP Exception #' . $ex->getCode());
327
		}
328
		else{
329
			save_to_log('error', 'An exception is occured in file ' . $ex->getFile() . ' at line ' . $ex->getLine() . ' raison : ' . $ex->getMessage(), 'PHP Exception');
330
		}
331
		return true;
332
	}
333
	
334
	/**
335
	 *  Function defined for PHP error message handling
336
	 *  			
337
	 *  @param int $errno the type of error for example: E_USER_ERROR, E_USER_WARNING, etc.
338
	 *  @param string $errstr the error message
339
	 *  @param string $errfile the file where the error occurred
340
	 *  @param int $errline the line number where the error occurred
341
	 *  @codeCoverageIgnore
342
	 *  
343
	 *  @return boolean	
344
	 */
345
	function php_error_handler($errno , $errstr, $errfile , $errline){
346
		$isError = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $errno) === $errno);
347
		if ($isError){
348
			set_http_status_header(500);
349
		}
350
		if (! (error_reporting() & $errno)) {
351
			save_to_log('error', 'An error is occurred in the file ' . $errfile . ' at line ' . $errline . ' raison : ' . $errstr, 'PHP ERROR');
352
			return;
353
		}
354
		if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))){
355
			$errorType = 'error';
356
			switch ($errno) {
357
				case E_USER_ERROR:
358
					$errorType = 'error';
359
					break;
360
				case E_USER_WARNING:
361
					$errorType = 'warning';
362
					break;
363
				case E_USER_NOTICE:
364
					$errorType = 'notice';
365
					break;
366
				default:
367
					$errorType = 'error';
368
					break;
369
			}
370
			show_error('An error is occurred in the file <b>' . $errfile . '</b> at line <b>' . $errline .'</b> raison : ' . $errstr, 'PHP ' . $errorType);
371
		}
372
		if ($isError){
373
			die();
374
		}
375
		return true;
376
	}
377
378
	/**
379
	 * This function is used to run in shutdown situation of the script
380
	 * @codeCoverageIgnore
381
	 */
382
	function php_shudown_handler(){
383
		$lastError = error_get_last();
384
		if (isset($lastError) &&
385
			($lastError['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING))){
386
			php_error_handler($lastError['type'], $lastError['message'], $lastError['file'], $lastError['line']);
387
		}
388
	}
389
390
391
	/**
392
	 *  Convert array attributes to string
393
	 *
394
	 *  This function converts an associative array into HTML attributes.
395
	 *  For example :
396
	 *  $a = array('name' => 'Foo', 'type' => 'text'); => produces the following string:
397
	 *  name = "Foo" type = "text"
398
	 *
399
	 *  @param array $attributes associative array to convert to a string attribute.
400
	 *   
401
	 *  @return string string of the HTML attribute.
402
	 */
403
	function attributes_to_string(array $attributes){
404
		$str = ' ';
405
		//we check that the array passed as an argument is not empty.
406
		if (! empty($attributes)){
407
			foreach($attributes as $key => $value){
408
				$key = trim(htmlspecialchars($key));
409
				$value = trim(htmlspecialchars($value));
410
				/*
411
				* To predict the case where the string to convert contains the character "
412
				* we check if this is the case we add a slash to solve this problem.
413
				* For example:
414
				* 	$attr = array('placeholder' => 'I am a "puple"')
415
				* 	$str = attributes_to_string($attr); => placeholder = "I am a \"puple\""
416
				 */
417
				if ($value && strpos('"', $value) !== false){
418
					$value = addslashes($value);
419
				}
420
				$str .= $key.' = "'.$value.'" ';
421
			}
422
		}
423
		//remove the space after using rtrim()
424
		return rtrim($str);
425
	}
426
427
428
	/**
429
	* Function to stringfy PHP variable, useful in debug situation
430
	*
431
	* @param mixed $var the variable to stringfy
432
	* @codeCoverageIgnore
433
	*
434
	* @return string the stringfy value
435
	*/
436
	function stringfy_vars($var){
437
		return print_r($var, true);
438
	}
439
440
	/**
441
	 * Clean the user input
442
	 * @param  mixed $str the value to clean
443
	 * @test
444
	 * 
445
	 * @return mixed   the sanitize value
446
	 */
447
	function clean_input($str){
448
		if (is_array($str)){
449
			$str = array_map('clean_input', $str);
450
		}
451
		else if (is_object($str)){
452
			$obj = $str;
453
			foreach ($str as $var => $value) {
454
				$obj->$var = clean_input($value);
455
			}
456
			$str = $obj;
457
		}
458
		else{
459
			$str = htmlspecialchars(strip_tags($str), ENT_QUOTES, 'UTF-8');
460
		}
461
		return $str;
462
	}
463
	
464
	/**
465
	 * This function is used to hidden some part of the given string. Helpful if you need hide some confidential 
466
	 * Information like credit card number, password, etc.
467
	 *
468
	 * @param  string $str the string you want to hide some part
469
	 * @param  int $startCount the length of non hidden for the beginning char
470
	 * @param  int $endCount the length of non hidden for the ending char
471
	 * @param  string $hiddenChar the char used to hide the given string
472
	 * @test
473
	 * 
474
	 * @return string the string with the hidden part.
475
	 */
476
	function string_hidden($str, $startCount = 0, $endCount = 0, $hiddenChar = '*'){
477
		//get the string length
478
		$len = strlen($str);
479
		//if str is empty
480
		if ($len <= 0){
481
			return str_repeat($hiddenChar, 6);
482
		}
483
		//if the length is less than startCount and endCount
484
		//or the startCount and endCount length is 0
485
		//or startCount is negative or endCount is negative
486
		//return the full string hidden
487
		
488
		if ((($startCount + $endCount) > $len) || ($startCount == 0 && $endCount == 0) || ($startCount < 0 || $endCount < 0)){
489
			return str_repeat($hiddenChar, $len);
490
		}
491
		//the start non hidden string
492
		$startNonHiddenStr = substr($str, 0, $startCount);
493
		//the end non hidden string
494
		$endNonHiddenStr = null;
495
		if ($endCount > 0){
496
			$endNonHiddenStr = substr($str, - $endCount);
497
		}
498
		//the hidden string
499
		$hiddenStr = str_repeat($hiddenChar, $len - ($startCount + $endCount));
500
		
501
		return $startNonHiddenStr . $hiddenStr . $endNonHiddenStr;
502
	}
503
	
504
	/**
505
	 * This function is used to set the initial session config regarding the configuration
506
	 * @codeCoverageIgnore
507
	 */
508
	function set_session_config(){
509
		//$_SESSION is not available on cli mode 
510
		if (! IS_CLI){
511
			$logger =& class_loader('Log', 'classes');
512
			$logger->setLogger('PHPSession');
513
			//set session params
514
			$sessionHandler = get_config('session_handler', 'files'); //the default is to store in the files
515
			$sessionName = get_config('session_name');
516
			if ($sessionName){
517
				session_name($sessionName);
518
			}
519
			$logger->info('Session handler: ' . $sessionHandler);
520
			$logger->info('Session name: ' . $sessionName);
521
522
			if ($sessionHandler == 'files'){
523
				$sessionSavePath = get_config('session_save_path');
524
				if ($sessionSavePath){
525
					if (! is_dir($sessionSavePath)){
526
						mkdir($sessionSavePath, 1773);
527
					}
528
					session_save_path($sessionSavePath);
529
					$logger->info('Session save path: ' . $sessionSavePath);
530
				}
531
			}
532
			else if ($sessionHandler == 'database'){
533
				//load database session handle library
534
				//Database Session handler Model
535
				require_once CORE_CLASSES_MODEL_PATH . 'DBSessionHandlerModel.php';
536
537
				$DBS =& class_loader('DBSessionHandler', 'classes');
538
				session_set_save_handler($DBS, true);
539
				$logger->info('session save path: ' . get_config('session_save_path'));
540
			}
541
			else{
542
				show_error('Invalid session handler configuration');
543
			}
544
			$lifetime = get_config('session_cookie_lifetime', 0);
545
			$path = get_config('session_cookie_path', '/');
546
			$domain = get_config('session_cookie_domain', '');
547
			$secure = get_config('session_cookie_secure', false);
548
			session_set_cookie_params(
549
				$lifetime,
550
				$path,
551
				$domain,
552
				$secure,
553
				$httponly = true /*for security for access to cookie via javascript or XSS attack*/
554
			);
555
			//to prevent attack of Session Fixation 
556
			//thank to https://www.phparch.com/2018/01/php-sessions-in-depth/
557
			ini_set('session.use_strict_mode ', 1);
558
			ini_set('session.use_only_cookies', 1);
559
			ini_set('session.use_trans_sid ', 0);
560
			
561
			$logger->info('Session lifetime: ' . $lifetime);
562
			$logger->info('Session cookie path: ' . $path);
563
			$logger->info('Session domain: ' . $domain);
564
			$logger->info('Session is secure: ' . ($secure ? 'TRUE':'FALSE'));
565
			
566
			if ((function_exists('session_status') && session_status() !== PHP_SESSION_ACTIVE) || !session_id()){
567
				$logger->info('Session not yet start, start it now');
568
				session_start();
569
			}
570
		}
571
	}
572
	
573
	/**
574
	* This function is very useful, it allows to recover the instance of the global controller.
575
	* Note this function always returns the address of the super instance.
576
	* For example :
577
	* $obj = & get_instance();
578
	* 
579
	* @codeCoverageIgnore
580
	*  
581
	* @return object the instance of the "Controller" class
582
	*/
583
	function & get_instance(){
584
		return Controller::get_instance();
585
	}
586