Sessions and Non-Sessions
PHP Usergroup Munich
2016-05-25
Why?
● Sessions tend to get in the way of modern
applications and infrastructure
● People seem to ignore the fine print when
rolling their own session handler
● Also: It's an old topic that everyone got in touch
with, but hasn't fully understood in all depth
● Are there alternatives to sessions?
PHP Sessions
What do you expect from using them?
How do they behave?
PHP Sessions
Anything I write to $_SESSION comes back on
the next page after calling session_start()
if (isset($_GET['subrequest'])) {
$requestStart = time();
$subrequest = intval($_GET['subrequest']);
$delay = isset($_GET['delay']) ? intval($_GET['delay']) : 1000000;
session_start();
echo "<html><body><pre>";
echo "Request started on ".date('Y-m-d H:i:s',
$requestStart)."n";
echo "Executing subrequest ". $subrequest."n";
echo "Session startedn";
echo date('Y-m-d H:i:s') . "n";
if ($_SESSION['content'] != "foobar in the session") {
echo "Expected value NOT FOUNDn";
}
$_SESSION['requests'][] = $subrequest;
echo "waiting $delay usecn";
usleep($delay);
echo "back againn";
echo date('Y-m-d H:i:s') . "n";
echo "Received subrequests: ". implode(', ',
$_SESSION['requests'])."n";
echo "</pre></body></html>";
exit();
}
if (isset($_GET['subrequest'])) {
// ...
}
session_start();
$_SESSION['content'] = "foobar in the session";
$_SESSION['requests'] = array();
$delay = isset($_GET['delay']) ? intval($_GET['delay']) : 1000000;
?>
<html>
<body>
<iframe src="?subrequest=1&delay=<?=$delay?>" width="90%"
height="200"></iframe>
<hr>
<iframe src="?subrequest=2&delay=<?=$delay?>" width="90%"
height="200"></iframe>
<hr>
<iframe src="?subrequest=3&delay=<?=$delay?>" width="90%"
height="200"></iframe>
</body>
</html>
SessionHandler: files
Delay: 1000ms
SessionHandler: files
Delay: 500ms
Firebug network tab
http://stackoverflow.com/questions/21044608/php-session-locking-and-using-memcache-to-store-sessions
Memcache 3.0.4 introduces locking
Changelog http://pecl.php.net/package/memcache/3.0.4
http://stackoverflow.com/questions/21044608/php-session-locking-and-using-memcache-to-store-sessions
Memcache 3.0.4 introduces locking
Changelog http://pecl.php.net/package/memcache/3.0.4
A lock on the data is essential for
consistent access to the data.
It prevents overwriting or losing data.
PHP Sessions
PHP Sessions
Locks on the network
are not that easy.
Memcache config docs
http://php.net/manual/en/memcache.ini.php
Undocumented memcache.lock_timeout = 15
Released 2009-02-22
Last version 3.0.8 from 2013-04-07
Conclusion: Don't use Memcache extension
Memcache config docs
http://php.net/manual/en/memcache.ini.php
Undocumented memcache.lock_timeout = 15
Released 2009-02-22
Last version 3.0.8 from 2013-04-07
Conclusion: Don't use Memcache extension
Memcache config docs
http://php.net/manual/en/memcached.configuration.php
All config values at least documented
Locking since 1.0.0 from 2009-07-07
Memcached config docs
There are plenty of possible values for
session.save_handler
Always available: files
Coming with extensions:
memcache
memcached
sqlite
redis
cluster (Zend Session Cluster)
...
However...
Locks on the network
are not that easy.
Network locking may add additional delays
The problem with lock timeouts
(illustrated with Zend Session Cluster)
2sec1sec 4sec?
500msec 1500msec? 2500msec?
Redis session handler :(https://github.com/phpredis/phpredis/issues/37
Redis session handler :(https://github.com/phpredis/phpredis/issues/37
PHP Sessions
Lets do it in userland code!
SessionHandlerInterfacehttp://php.net/manual/en/class.sessionhandlerinterface.php
Warning...
Locks on the network
are not that easy.
Symfony
https://github.com/symfony/symfony/issues/4976
What do you want to do, anyway?
Solved in 3 days!
Encrypting the locally stored session data
https://github.com/ezimuel/PHP-Secure-Session
… extends SessionHandler
https://github.com/ezimuel/PHP-Secure-Session/blob/master/src/SecureHandler.php
Avoiding the problem?
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Session/Middleware/StartSession.php#L54-L55
Laravel code comment:
“Note that the Laravel sessions
do not make use of PHP "native" sessions
in any way since they are crappy.”
https://github.com/laravel/framework/issues/7549
Known limitation → closed
<rant>
https://github.com/laravel/framework/issues/6777
“Can anyone provide a fix?”
No? → closed
Reopen?
“Hmmm, maybe.
We've got no idea what is going on here.”
<rant>
https://github.com/laravel/framework/issues/8172
<rant>
https://github.com/laravel/framework/issues/8172#issuecomment-114260875
“I solved my problem putting session_start() in the
top of my routes file.”
“Oh wow. NEVER do that!”
“why? That solved my problem”
“Because that's totally incorrect.” → closed
<rant>
</rant>
PHP Sessions
They are crappy?
What's the problem?
PHP Sessions
● session_start automatically writes a cookie
● calling it multiple times will create conflicts
● wrapping it into OOP seems complicated
● What about this?
http://paul-m-jones.com/archives/6310
Non-session solutions*
* no PHP-provided session functions
Data in cookies
https://github.com/Ocramius/PSR7Session
Data in cookies
Data in cookies
Data in cookies
Split the problem
Restful web APIs should manage
resources independent from others
POST /api/basket
→ creates /api/basket/randomid
POST /api/customer
→ creates /api/customer/randomid
No blocking, can be done concurrently.
Split the problem
However...
PUT /api/basket/randomid → with dataset A
PUT /api/basket/randomid → with dataset B
Who will win?
Move the problem elsewhere
CouchDB has a strategy for concurrent changes:
1) Reject writes with outdated datasets
2) Accept both changes and let the application
or the user sort it out.
https://wiki.apache.org/couchdb/Replication_and_conflicts
Summary
PHP Sessions
Session data is individual global state
PHP Sessions
Fixing Addressing long lock times in the code
PHP 5, 7:
session_write_close(); // ASAP
PHP 7:
session_start(['read_and_close' => true]);
PHP SessionHandlers
Don't forget that you HAVE TO LOCK the data
Using Cookies
Solves some problems,
but has drawbacks
Using alternative storage strategies
Splitting data units will reduce the problem
Merging data on conflicts...
...is left as an exercise to the developer
Thank you!
Any questions?
Find me on twitter: @SvenRtbg
Find me on StackOverflow: SvenRtbg
Find me on GitHub: SvenRtbg
Find me on Slideshare: SvenRtbg
This presentation on Slideshare
http://de.slideshare.net/svenrtbg/php-sessions-and-nonsessions

PHP Sessions and Non-Sessions