A super easy PHP Framework for web development!
				https://github.com/exacti/phacil-framework
			
			
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					202 lines
				
				4.1 KiB
			
		
		
			
		
	
	
					202 lines
				
				4.1 KiB
			| 
								 
											2 years ago
										 
									 | 
							
								<?php
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copyright © 2024 ExacTI Technology Solutions. All rights reserved.
							 | 
						||
| 
								 | 
							
								 * GPLv3 General License.
							 | 
						||
| 
								 | 
							
								 * https://exacti.com.br
							 | 
						||
| 
								 | 
							
								 * Phacil PHP Framework - https://github.com/exacti/phacil-framework
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Phacil\Framework\Session\Handlers;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * File session handler
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @since 2.0.0
							 | 
						||
| 
								 | 
							
								 * @package Phacil\Framework\Session;
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class File implements \Phacil\Framework\Session\Api\HandlerInterface
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									const KEY_EXPIRES = 'session_expires';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const SHORT_NAME = 'file';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * 
							 | 
						||
| 
								 | 
							
									 * @var \Phacil\Framework\Config
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									private $config;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * 
							 | 
						||
| 
								 | 
							
									 * @var \Phacil\Framework\Encryption
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									private $encryptor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * 
							 | 
						||
| 
								 | 
							
									 * @var \Phacil\Framework\Json
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									private $json;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * 
							 | 
						||
| 
								 | 
							
									 * @var bool
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									protected $isFirstSession = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Constructor
							 | 
						||
| 
								 | 
							
									 *
							 | 
						||
| 
								 | 
							
									 * @param \Phacil\Framework\Config $config
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									public function __construct(
							 | 
						||
| 
								 | 
							
										\Phacil\Framework\Config $config, 
							 | 
						||
| 
								 | 
							
										\Phacil\Framework\Encryption $encryption, 
							 | 
						||
| 
								 | 
							
										\Phacil\Framework\Json $json
							 | 
						||
| 
								 | 
							
									){
							 | 
						||
| 
								 | 
							
										$this->config = $config;
							 | 
						||
| 
								 | 
							
										$this->encryptor = $encryption;
							 | 
						||
| 
								 | 
							
										$this->json = $json;
							 | 
						||
| 
								 | 
							
										if(!\Phacil\Framework\Config::DIR_SESSION())
							 | 
						||
| 
								 | 
							
											\Phacil\Framework\Config::DIR_SESSION(\Phacil\Framework\Config::DIR_CACHE()."sessions/");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										$this->checkDir();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * @return void 
							 | 
						||
| 
								 | 
							
									 * @throws \Phacil\Framework\Exception 
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									protected function checkDir()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (!is_dir(\Phacil\Framework\Config::DIR_SESSION())) {
							 | 
						||
| 
								 | 
							
											mkdir(\Phacil\Framework\Config::DIR_SESSION(), 0764, true);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (!is_writable(\Phacil\Framework\Config::DIR_SESSION())) {
							 | 
						||
| 
								 | 
							
											throw new \Phacil\Framework\Exception(
							 | 
						||
| 
								 | 
							
												"The session dir storage doesn't exist or isn't writable. Verify the permissions and try again."
							 | 
						||
| 
								 | 
							
											);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** {@inheritdoc} */
							 | 
						||
| 
								 | 
							
									public function getFailedLockAttempts() { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** {@inheritdoc} */
							 | 
						||
| 
								 | 
							
									public function setName($name) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** @return int  */
							 | 
						||
| 
								 | 
							
									protected function getLifetime()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return (int)$this->config->get('session_expire') ?: self::DEFAULT_SESSION_LIFETIME;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** @return int  */
							 | 
						||
| 
								 | 
							
									protected function getFirstLifetime()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return (int)$this->config->get('session_first_lifetime') ?: self::DEFAULT_SESSION_FIRST_LIFETIME;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * @param string $hash 
							 | 
						||
| 
								 | 
							
									 * @return string|false 
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									private function hashed($hash)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										//$this->encryptor->setHashAlgo('sha256');
							 | 
						||
| 
								 | 
							
										return $this->encryptor->hash($hash) ?: $hash;
							 | 
						||
| 
								 | 
							
										//return $hash;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function close()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function open($savePath, $sessionName)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function read($session_id)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										$file = \Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (is_file($file)) {
							 | 
						||
| 
								 | 
							
											$data = $this->json->decode(file_get_contents($file));
							 | 
						||
| 
								 | 
							
											if($data && $data[self::KEY_EXPIRES] >= time()){
							 | 
						||
| 
								 | 
							
												$this->isFirstSession = false;
							 | 
						||
| 
								 | 
							
												return $data['data'];
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												$this->destroy($session_id);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function write($session_id, $data)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										$data = [
							 | 
						||
| 
								 | 
							
											'data' => $data,
							 | 
						||
| 
								 | 
							
											self::KEY_EXPIRES => time() + ($this->isFirstSession ? $this->getFirstLifetime() : $this->getLifetime())
							 | 
						||
| 
								 | 
							
										];
							 | 
						||
| 
								 | 
							
										file_put_contents(\Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id)), $this->json->encode($data));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function destroy($session_id)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										$file = \Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (is_file($file) && is_writable($file)) {
							 | 
						||
| 
								 | 
							
											return unlink($file);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * {@inheritdoc}
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									#[\ReturnTypeWillChange]
							 | 
						||
| 
								 | 
							
									public function gc($maxLifeTime)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (round(mt_rand(1, $this->config->get('session_divisor') / $this->config->get('session_probability'))) == 1) {
							 | 
						||
| 
								 | 
							
											$expire = time() - $this->config->get('session_expire');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											$files = scandir(\Phacil\Framework\Config::DIR_SESSION());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											foreach ($files as $file) {
							 | 
						||
| 
								 | 
							
												if (is_file($file) && filemtime($file) < $expire && is_writable($file)) {
							 | 
						||
| 
								 | 
							
													unlink($file);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |