Passed
Push — 1.0.0-dev ( 459011...73c7ea )
by nguereza
03:08
created

set_session_config()   C

Complexity

Conditions 12
Paths 41

Size

Total Lines 62
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 45
nc 41
nop 0
dl 0
loc 62
rs 6.9666
c 1
b 0
f 0

How to fix   Long Method    Complexity   

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
                                200 => 'OK',
184
                                201 => 'Created',
185
                                202 => 'Accepted',
186
                                203 => 'Non-Authoritative Information',
187
                                204 => 'No Content',
188
                                205 => 'Reset Content',
189
                                206 => 'Partial Content',
190
                                300 => 'Multiple Choices',
191
                                301 => 'Moved Permanently',
192
                                302 => 'Found',
193
                                303 => 'See Other',
194
                                304 => 'Not Modified',
195
                                305 => 'Use Proxy',
196
                                307 => 'Temporary Redirect',
197
                                400 => 'Bad Request',
198
                                401 => 'Unauthorized',
199
                                402 => 'Payment Required',
200
                                403 => 'Forbidden',
201
                                404 => 'Not Found',
202
                                405 => 'Method Not Allowed',
203
                                406 => 'Not Acceptable',
204
                                407 => 'Proxy Authentication Required',
205
                                408 => 'Request Timeout',
206
                                409 => 'Conflict',
207
                                410 => 'Gone',
208
                                411 => 'Length Required',
209
                                412 => 'Precondition Failed',
210
                                413 => 'Request Entity Too Large',
211
                                414 => 'Request-URI Too Long',
212
                                415 => 'Unsupported Media Type',
213
                                416 => 'Requested Range Not Satisfiable',
214
                                417 => 'Expectation Failed',
215
                                418 => 'I\'m a teapot',
216
                                500 => 'Internal Server Error',
217
                                501 => 'Not Implemented',
218
                                502 => 'Bad Gateway',
219
                                503 => 'Service Unavailable',
220
                                504 => 'Gateway Timeout',
221
                                505 => 'HTTP Version Not Supported',
222
                            );
223
            if (isset($http_status[$code])) {
224
                $text = $http_status[$code];
225
            } else {
226
                show_error('No HTTP status text found for your code please check it.');
227
            }
228
        }
229
		
230
        if (strpos(php_sapi_name(), 'cgi') === 0) {
231
            header('Status: ' . $code . ' ' . $text, TRUE);
232
        } else {
233
            $proto = 'HTTP/1.1';
234
            if (isset($_SERVER['SERVER_PROTOCOL'])) {
235
                $proto = $_SERVER['SERVER_PROTOCOL'];
236
            }
237
            header($proto . ' ' . $code . ' ' . $text, TRUE, $code);
238
        }
239
    }
240
241
    /**
242
     *  This function displays an error message to the user and ends the execution of the script.
243
     *  
244
     *  @param string $msg the message to display
245
     *  @param string $title the message title: "error", "info", "warning", etc.
246
     *  @param boolean $logging either to save error in log
247
     *  
248
     *  @codeCoverageIgnore
249
     */
250
    function show_error($msg, $title = 'error', $logging = true) {
251
        $title = strtoupper($title);
252
        $data = array();
253
        $data['error'] = $msg;
254
        $data['title'] = $title;
255
        if ($logging) {
256
            save_to_log('error', '[' . $title . '] ' . strip_tags($msg), 'GLOBAL::ERROR');
257
        }
258
        $response = & class_loader('Response', 'classes');
259
        $response->sendError($data);
260
        die();
261
    }
262
263
    /**
264
     *  Check whether the protocol used is "https" or not
265
     *  That is, the web server is configured to use a secure connection.
266
     *  @codeCoverageIgnore
267
     *  
268
     *  @return boolean true if the web server uses the https protocol, false if not.
269
     */
270
    function is_https() {
271
        /*
272
		* some servers pass the "HTTPS" parameter in the server variable,
273
		* if is the case, check if the value is "on", "true", "1".
274
		*/
275
        if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
276
            return true;
277
        }
278
        if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
279
            return true;
280
        }
281
        if (isset($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
282
            return true;
283
        }
284
        return false;
285
    }
286
	
287
    /**
288
     *  This function is used to check the URL format of the given string argument. 
289
     *  The address is valid if the protocol is http, https, ftp, etc.
290
     *
291
     *  @param string $url the URL address to check
292
     *  @test
293
     *  
294
     *  @return boolean true if is a valid URL address or false.
295
     */
296
    function is_url($url) {
297
        return preg_match('/^(http|https|ftp):\/\/(.*)/', $url) == 1;
298
    }
299
	
300
    /**
301
     *  Function defined to load controller
302
     *  
303
     *  @param string $controllerClass the controller class name to be loaded
304
     *  @codeCoverageIgnore
305
     */
306
    function autoload_controller($controllerClass) {
307
        if (file_exists($path = APPS_CONTROLLER_PATH . $controllerClass . '.php')) {
308
            require_once $path;
309
        }
310
    }
311
	
312
    /**
313
     *  Function defined for handling PHP exception error message, 
314
     *  it displays an error message using the function "show_error"
315
     *  
316
     *  @param object $ex instance of the "Exception" class or a derived class
317
     *  @codeCoverageIgnore
318
     *  
319
     *  @return boolean
320
     */
321
    function php_exception_handler($ex) {
322
        if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))) {
323
            show_error('An exception is occured in file ' . $ex->getFile() . ' at line ' . $ex->getLine() . ' raison : ' . $ex->getMessage(), 'PHP Exception #' . $ex->getCode());
324
        } else {
325
            save_to_log('error', 'An exception is occured in file ' . $ex->getFile() . ' at line ' . $ex->getLine() . ' raison : ' . $ex->getMessage(), 'PHP Exception');
326
        }
327
        return true;
328
    }
329
	
330
    /**
331
     *  Function defined for PHP error message handling
332
     *  			
333
     *  @param int $errno the type of error for example: E_USER_ERROR, E_USER_WARNING, etc.
334
     *  @param string $errstr the error message
335
     *  @param string $errfile the file where the error occurred
336
     *  @param int $errline the line number where the error occurred
337
     *  @codeCoverageIgnore
338
     *  
339
     *  @return boolean	
340
     */
341
    function php_error_handler($errno, $errstr, $errfile, $errline) {
342
        $isError = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $errno) === $errno);
343
        if ($isError) {
344
            set_http_status_header(500);
345
        }
346
        if (!(error_reporting() & $errno)) {
347
            save_to_log('error', 'An error is occurred in the file ' . $errfile . ' at line ' . $errline . ' raison : ' . $errstr, 'PHP ERROR');
348
            return;
349
        }
350
        if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))) {
351
            $errorType = 'error';
352
            switch ($errno) {
353
                case E_USER_WARNING:
354
                    $errorType = 'warning';
355
                    break;
356
                case E_USER_NOTICE:
357
                    $errorType = 'notice';
358
                    break;
359
            }
360
            show_error('An error is occurred in the file <b>' . $errfile . '</b> at line <b>' . $errline . '</b> raison : ' . $errstr, 'PHP ' . $errorType);
361
        }
362
        if ($isError) {
363
            die();
364
        }
365
        return true;
366
    }
367
368
    /**
369
     * This function is used to run in shutdown situation of the script
370
     * @codeCoverageIgnore
371
     */
372
    function php_shudown_handler() {
373
        $lastError = error_get_last();
374
        if (isset($lastError) &&
375
            ($lastError['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING))) {
376
            php_error_handler($lastError['type'], $lastError['message'], $lastError['file'], $lastError['line']);
377
        }
378
    }
379
380
381
    /**
382
     *  Convert array attributes to string
383
     *
384
     *  This function converts an associative array into HTML attributes.
385
     *  For example :
386
     *  $a = array('name' => 'Foo', 'type' => 'text'); => produces the following string:
387
     *  name = "Foo" type = "text"
388
     *
389
     *  @param array $attributes associative array to convert to a string attribute.
390
     *   
391
     *  @return string string of the HTML attribute.
392
     */
393
    function attributes_to_string(array $attributes) {
394
        $str = ' ';
395
        //we check that the array passed as an argument is not empty.
396
        if (!empty($attributes)) {
397
            foreach ($attributes as $key => $value) {
398
                $key = trim(htmlspecialchars($key));
399
                $value = trim(htmlspecialchars($value));
400
                /*
401
				* To predict the case where the string to convert contains the character "
402
				* we check if this is the case we add a slash to solve this problem.
403
				* For example:
404
				* 	$attr = array('placeholder' => 'I am a "puple"')
405
				* 	$str = attributes_to_string($attr); => placeholder = "I am a \"puple\""
406
				 */
407
                if ($value && strpos('"', $value) !== false) {
408
                    $value = addslashes($value);
409
                }
410
                $str .= $key . ' = "' . $value . '" ';
411
            }
412
        }
413
        //remove the space after using rtrim()
414
        return rtrim($str);
415
    }
416
417
418
    /**
419
     * Function to stringfy PHP variable, useful in debug situation
420
     *
421
     * @param mixed $var the variable to stringfy
422
     * @codeCoverageIgnore
423
     *
424
     * @return string the stringfy value
425
     */
426
    function stringfy_vars($var) {
427
        return print_r($var, true);
428
    }
429
430
    /**
431
     * Clean the user input
432
     * @param  mixed $str the value to clean
433
     * @test
434
     * 
435
     * @return mixed   the sanitize value
436
     */
437
    function clean_input($str) {
438
        if (is_array($str)) {
439
            $str = array_map('clean_input', $str);
440
        } else if (is_object($str)) {
441
            $obj = $str;
442
            foreach ($str as $var => $value) {
443
                $obj->$var = clean_input($value);
444
            }
445
            $str = $obj;
446
        } else {
447
            $str = htmlspecialchars(strip_tags($str), ENT_QUOTES, 'UTF-8');
448
        }
449
        return $str;
450
    }
451
	
452
    /**
453
     * This function is used to hidden some part of the given string. Helpful if you need hide some confidential 
454
     * Information like credit card number, password, etc.
455
     *
456
     * @param  string $str the string you want to hide some part
457
     * @param  int $startCount the length of non hidden for the beginning char
458
     * @param  int $endCount the length of non hidden for the ending char
459
     * @param  string $hiddenChar the char used to hide the given string
460
     * @test
461
     * 
462
     * @return string the string with the hidden part.
463
     */
464
    function string_hidden($str, $startCount = 0, $endCount = 0, $hiddenChar = '*') {
465
        //get the string length
466
        $len = strlen($str);
467
        //if str is empty
468
        if ($len <= 0) {
469
            return str_repeat($hiddenChar, 6);
470
        }
471
        //if the length is less than startCount and endCount
472
        //or the startCount and endCount length is 0
473
        //or startCount is negative or endCount is negative
474
        //return the full string hidden
475
		
476
        if ((($startCount + $endCount) > $len) || ($startCount == 0 && $endCount == 0) || ($startCount < 0 || $endCount < 0)) {
477
            return str_repeat($hiddenChar, $len);
478
        }
479
        //the start non hidden string
480
        $startNonHiddenStr = substr($str, 0, $startCount);
481
        //the end non hidden string
482
        $endNonHiddenStr = null;
483
        if ($endCount > 0) {
484
            $endNonHiddenStr = substr($str, - $endCount);
485
        }
486
        //the hidden string
487
        $hiddenStr = str_repeat($hiddenChar, $len - ($startCount + $endCount));
488
		
489
        return $startNonHiddenStr . $hiddenStr . $endNonHiddenStr;
490
    }
491
	
492
    /**
493
     * This function is used to set the initial session config regarding the configuration
494
     * @codeCoverageIgnore
495
     */
496
    function set_session_config() {
497
        //$_SESSION is not available on cli mode 
498
        if (!IS_CLI) {
499
            $logger = & class_loader('Log', 'classes');
500
            $logger->setLogger('PHPSession');
501
            //set session params
502
            $sessionHandler = get_config('session_handler', 'files'); //the default is to store in the files
503
            $sessionName = get_config('session_name');
504
            if ($sessionName) {
505
                session_name($sessionName);
506
            }
507
            $logger->info('Session handler: ' . $sessionHandler);
508
            $logger->info('Session name: ' . $sessionName);
509
510
            if ($sessionHandler == 'files') {
511
                $sessionSavePath = get_config('session_save_path');
512
                if ($sessionSavePath) {
513
                    if (!is_dir($sessionSavePath)) {
514
                        mkdir($sessionSavePath, 1773);
515
                    }
516
                    session_save_path($sessionSavePath);
517
                    $logger->info('Session save path: ' . $sessionSavePath);
518
                }
519
            } else if ($sessionHandler == 'database') {
520
                //load database session handle library
521
                //Database Session handler Model
522
                require_once CORE_CLASSES_MODEL_PATH . 'DBSessionHandlerModel.php';
523
524
                $DBS = & class_loader('DBSessionHandler', 'classes');
525
                session_set_save_handler($DBS, true);
526
                $logger->info('session save path: ' . get_config('session_save_path'));
527
            } else {
528
                show_error('Invalid session handler configuration');
529
            }
530
            $lifetime = get_config('session_cookie_lifetime', 0);
531
            $path = get_config('session_cookie_path', '/');
532
            $domain = get_config('session_cookie_domain', '');
533
            $secure = get_config('session_cookie_secure', false);
534
            if (is_https()) {
535
                $secure = true;
536
            }
537
            session_set_cookie_params(
538
                $lifetime,
539
                $path,
540
                $domain,
541
                $secure,
542
                $httponly = true /*for security for access to cookie via javascript or XSS attack*/
543
            );
544
            //to prevent attack of Session Fixation 
545
            //thank to https://www.phparch.com/2018/01/php-sessions-in-depth/
546
            ini_set('session.use_strict_mode ', 1);
547
            ini_set('session.use_only_cookies', 1);
548
            ini_set('session.use_trans_sid ', 0);
549
			
550
            $logger->info('Session lifetime: ' . $lifetime);
551
            $logger->info('Session cookie path: ' . $path);
552
            $logger->info('Session domain: ' . $domain);
553
            $logger->info('Session is secure: ' . ($secure ? 'TRUE' : 'FALSE'));
554
			
555
            if ((function_exists('session_status') && session_status() !== PHP_SESSION_ACTIVE) || !session_id()) {
556
                $logger->info('Session not yet start, start it now');
557
                session_start();
558
            }
559
        }
560
    }
561
	
562
    /**
563
     * This function is very useful, it allows to recover the instance of the global controller.
564
     * Note this function always returns the address of the super instance.
565
     * For example :
566
     * $obj = & get_instance();
567
     * 
568
     * @codeCoverageIgnore
569
     *  
570
     * @return object the instance of the "Controller" class
571
     */
572
    function & get_instance(){
573
        return Controller::get_instance();
574
    }
575