/src/Phoriz/Session/FileSession/FileSessionHandler.php
PHP | 285 lines | 169 code | 21 blank | 95 comment | 22 complexity | 24bfa7d055ea8ada49e517d54a3c88d6 MD5 | raw file
Possible License(s): EPL-1.0
- <?php
- /******************************************************************************
- * Copyright (c) 29/01/13 Kaspar Bach Pedersen.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Kaspar Bach Pedersen - initial API and implementation and/or initial
- * documentation
- ******************************************************************************/
- namespace Phoriz\Session\FileSession;
- use DI\Annotation\Inject;
- use Phoriz\Exceptions\SessionHandlerException;
- use Phoriz\Session\SessionHandler;
- class FileSessionHandler extends SessionHandler
- {
- /**
- * @Inject("session.params")
- */
- private $configuration;
- /**
- * @var \string
- */
- private $sessionId;
- /**
- * @var \resource[]
- */
- private $files = array();
- /**
- * Open the session
- */
- public function open($sessionId)
- {
- $this->sessionId = $sessionId;
- // Check session age and delete if older than max age
- $maxAge = $this->configuration['lifetime_s'];
- $sessionAge = $this->findSessionAge($sessionId);
- if ($sessionAge !== false && $sessionAge >= $maxAge) {
- $this->destroy();
- }
- }
- /**
- * Close the session
- */
- public function close()
- {
- foreach ($this->files as $handle) {
- @flock($handle, LOCK_UN);
- @fclose($handle);
- }
- $this->files = array();
- }
- /**
- * Destroy the session
- */
- public function destroy()
- {
- $this->close();
- $path = $this->configuration['store_path'];
- $globvar = $path . DIRECTORY_SEPARATOR . $this->sessionId . '-*.session';
- $files = glob($globvar);
- foreach ($files as $file) {
- @unlink($file);
- }
- $this->files = array();
- }
- /**
- * Garbage collect expired sessions.
- */
- public function gc()
- {
- $path = $this->configuration['store_path'];
- $maxAge = $this->configuration['lifetime_s'];
- $sessionIds = $this->listActiveSessions($path);
- foreach ($sessionIds as $currentSessionId) {
- $globName = $path . DIRECTORY_SEPARATOR . $currentSessionId . '-*.' . 'session';
- $currFiles = glob($globName);
- $currAge = $this->findAgeOfNewestFile($currFiles);
- if ($currAge !== false && $currAge >= $maxAge) {
- foreach ($currFiles as $file) {
- @unlink($file);
- }
- }
- }
- }
- /**
- * Find the last accessed file and return age
- * @param \string[] $files
- * @return int age in seconds
- */
- private function findAgeOfNewestFile($files)
- {
- $now = time();
- $newestAge = false;
- foreach ($files as $file) {
- $filetime = fileatime($file);
- if ($filetime !== false) {
- $currentAge = $now - $filetime;
- if ($newestAge === false || $currentAge < $newestAge) {
- $newestAge = $currentAge;
- }
- }
- }
- return $newestAge;
- }
- /**
- * Find age of given session
- * @param string $sessionId
- * @return int age in seconds
- */
- private function findSessionAge($sessionId)
- {
- $path = $this->configuration['store_path'];
- $globName = $path . DIRECTORY_SEPARATOR . $sessionId . '-*.' . 'session';
- $files = glob($globName);
- return $this->findAgeOfNewestFile($files);
- }
- /**
- * List all sessions in path
- * @param $path
- * @return array with session id's
- */
- private function listActiveSessions($path)
- {
- $sessionIds = array();
- $globvar = $path . DIRECTORY_SEPARATOR . '*.session';
- $files = glob($globvar);
- foreach ($files as $file) {
- if (is_file($file)) {
- $exploded = explode('-', basename($file));
- if (count($exploded) == 2) {
- $sessionId = $exploded[0];
- if (!in_array($sessionId, $sessionIds)) {
- $sessionIds[] = $sessionId;
- }
- }
- }
- }
- return $sessionIds;
- }
- /**
- * Read a session variable.
- * If the value should be modified use readAndLock instead.
- * @param string $sessionVar name of session variable
- * @param bool $lock lock this session variable (use full if multiple requests write to the samme session var)
- * @param null $resolver
- * @return mixed|null content of the read session var
- */
- public function read($sessionVar, $lock = false, $resolver = null)
- {
- $filename = $this->varFilename($sessionVar);
- if (!isset($this->files[$sessionVar])|| !is_file($filename)) {
- $this->files[$sessionVar] = fopen($filename, 'c+');
- if ($lock) {
- flock($this->files[$sessionVar], LOCK_EX);
- }
- }
- return $this->seekAndRead($sessionVar, $filename);
- }
- /**
- * Write a session variable.
- * @param string $sessionVar name of session variable
- * @param mixed $sessionValue content of session var
- * @param bool $unlock unlock the session variable when the variable has been written
- * @param null|SessionContainerResolver $resolver
- * @return void
- */
- public function write($sessionVar, $sessionValue, $unlock = false, $resolver = null)
- {
- if (isset($this->files[$sessionVar])) {
- $value = serialize($sessionValue);
- $handle = $this->files[$sessionVar];
- $this->perfromWrite($this->varFilename($sessionVar), $handle, $value);
- if ($unlock) {
- flock($this->files[$sessionVar], LOCK_UN);
- }
- }
- }
- /**
- * Removes a session variable from current session
- * @param string $sessionVar
- * @return null
- */
- public function removeVar($sessionVar)
- {
- if (isset($this->files[$sessionVar])) {
- flock($this->files[$sessionVar], LOCK_UN);
- fclose($this->files[$sessionVar]);
- unset($this->files[$sessionVar]);
- }
- $filename = $this->varFilename($sessionVar);
- if (is_file($filename)) {
- @unlink($filename);
- }
- }
- /**
- * Check if an session var exists
- * @param string $sessionVar
- * @return boolean
- */
- public function varExists($sessionVar)
- {
- return is_file($this->varFilename($sessionVar));
- }
- /**
- * Calculates filename of a session var
- * @param \string $sessionVar session var name
- * @return string
- */
- private function varFilename($sessionVar)
- {
- $path = $this->configuration['store_path'];
- $filename = $path . DIRECTORY_SEPARATOR . $this->sessionId . '-' . $sessionVar . '.' . 'session';
- return $filename;
- }
- /**
- * @param $sessionVar
- * @param \string $filename
- * @return mixed|null
- * @throws SessionHandlerException
- */
- public function seekAndRead($sessionVar, $filename)
- {
- fseek($this->files[$sessionVar], SEEK_SET, 0);
- if (filesize($filename) > 0) {
- $fread = fread($this->files[$sessionVar], filesize($filename));
- if ($fread === false) {
- throw new SessionHandlerException("Failed to read session var from ".$filename);
- }
- return unserialize($fread);
- } else {
- return null;
- }
- }
- /**
- * @param $filename
- * @param \resource $handle
- * @param string $value
- * @throws SessionHandlerException
- * @return void
- */
- private function perfromWrite($filename, $handle, $value)
- {
- $length = strlen($value);
- fseek($handle, SEEK_SET, 0);
- while ($length > 0) {
- $res = fwrite($handle, $value);
- if ($res === false) {
- throw new SessionHandlerException("Failed to write session var to ".$filename);
- }
- $length -= $res;
- }
- ftruncate($handle, strlen($value));
- }
- /** Does this session handler support locking
- * @return bool
- */
- public function supportsLocking()
- {
- return true;
- }
- }