All of the answers here seem to be saying to use the session methods in ways that they were clearly not intended to be used...namely calling session_start() more than once.
The PHP website offers an example SessionHandlerInterface implementation that will work just like existing sessions but without locking the file. Just implementing their example interface fixed my locking issue to allow for concurrent connections on the same session without limiting my ability to add vars to the session. To prevent some race conditions, since the app's session isn't fully stateless, I did have to make a way to save the session mid-request without closing it so that important changes could save immediately after change and less important session vars could just save at the end of the request. See the below example for usage: Session::start(); echo("Vars Stored in Session Were:\n");print_r($_SESSION);echo(""); $_SESSION['one'] = 'one'; $_SESSION['two'] = 'two'; //save won't close session and subsequent request will show 'three' Session::save(); $_SESSION['three'] = 'three';
If you replace that Session::start() with session_start() and Session::save() with session_write_close(), you'll notice that subsequent requests will never print out the third variable...it will be lost. However, using the SessionHandler (below), no data is lost.
The OOP implementation requires PHP 5.4+. However, you can provide individual callback methods in older versions of PHP. See docs. namespace { class Session implements SessionHandlerInterface { /** @var Session */ private static $_instance; private $savePath; public static function start() { if( empty(self::$_instance) ) { self::$_instance = new self(); session_set_save_handler(self::$_instance,true); session_start(); } } public static function save() { if( empty(self::$_instance) ) { throw new \Exception("You cannot save a session before starting the session"); } self::$_instance->write(session_id(),session_encode()); } public function open($savePath, $sessionName) { $this->savePath = $savePath; if (!is_dir($this->savePath)) { mkdir($this->savePath, 0777); } return true; } public function close() { return true; } public function read($id) { return (string)@file_get_contents("$this->savePath/sess_$id"); } public function write($id, $data) { return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; } public function destroy($id) { $file = "$this->savePath/sess_$id"; if (file_exists($file)) { unlink($file); } return true; } public function gc($maxlifetime) { foreach (glob("$this->savePath/sess_*") as $file) { if (filemtime($file) + $maxlifetime