BLOG

Incoherent ramblings, devlogs, edgy philosophy and other topics of interest

ENTRY #101

---



POCKET_PHP has been updated with extra session management features. For starters, the database table for accounts and the provided HTTPRequest object now include the following session information:


session_timestamp: UNIX style timestamp of the session start
session_id: The UID PHP assigns to the user at session start
logged_in: Flag value that reflects the state of the session using this account
logout_type: How the session was last terminated


With this data the framework can provide a more thorough status of the account assigned to each session. This is necessary because PHP manages sessions by storing them in either a database or as a file in the local file system (default), then sends the client this same UID as a cookie. When the client connects to the POCKET_PHP™©® server the browser (by default) sends whatever cookies match the target domain along with the actual HTTP request, the server then matches the cookie's UID with it's internal sessions and, if it finds a match, proceeds to assign the account data to the $_SESSION superglobal. Linking the client's session with an account in particular.
As long as the client keeps the session cookie and the server keeps the session alive (be it as a local file or an entry in a database) the user will be recognized by the server and automatically assigned the sessions data on each request.


As simple and efficient as it may seem, the codependency on the user's cookie and the server's session registry does further complicate the problem. Neither side has any control or notion about it's opposite SID container. If the server decides to delete a user's session (i.e. delete the correspondent file from the sessions directory) then the user's cookie can't be verified and thus, becomes useless. Likewise if the user decides to manually delete or tamper with the cookie (or it simply expires) then no ID is sent with the user's requests, the server-side session file then becomes useless. In the case of the former, the client's now invalid cookie is discarded and a new one is generated, in the case of the latter, however, it's the server's session file that is now invalid. It will simply generate a new UID, store it as another session file and send it back as a cookie to the user, leaving the user's previous session file pointlessly waiting for activity.


The way PHP deals with these potentially obsolete files is by having a chance of triggering a garbage collection routine every time session_start() is called. The probability of it happening is calculated by divding the php.ini settings session.gc_probability and session.gc_divisor. By default, PHP assigns these values to 1 and 100 respectively, giving the garbage collection a 1% chance of being triggered by calls to session_start(). This routine checks the existing session files and deletes them based on the expiry time set by session.gc_maxlifetime. Needless to say, each file has to be individually checked for expiration making this a linear search problem with a (O)N performance rating, meaning that the more session files there are, the more computationally expensive the routine grows. Hence why PHP defaults to a 1% chance of calling it, and only during session creation (perhaps the least intrusive step to add more overhead to).


In a scenario where the client's cookie is prematurely disabled and the server side SID file remains, the account associated to the session won't be properly logged out, even the internal session life counter won't be recognized as expired because the client can't match the session file to trigger this check anymore. This means that if the client (or anybody else, for that matter) tries to log in to this account, POCKET_PHP will recognize it as already logged in and must either reject the latest login attempt or reassign the account data to the newly created session. Either way the previous session file should be manually destroyed to avoid having to wait for the garbage collector, hence why the SID assigned to an account on login is stored in the accounts table. Should a login clash occur, POCKET_PHP will attempt to manually destroy the session file saved in the account entry and replace it with the new SID. The account's logged in status then correctly reflects it's pairing with the new session and it's previous session identifier no longer hogs memory by uselessly sitting in the sessions directory. It also updates the "logout_type" cell with "SESSION_HIJACKED".


Do note that a "SESSION_HIJACKED" simply means that the account shifted sessions without logging out, this is also the case when the server side SUI file is deleted or expires.


Of course, the other ways of ending a session are also reflected in the account's entry.


CLEAN_LOGOUT The user manually logged out
SESSION_INACTIVITY: The user (with a valid SUI cookie) refreshed the page after the inactivity tolerance (specified in SESSION_INACTIVITY_TOLERANCE) was over
SESSION_MAX_DURATION: The user (with a valid SUI cookie) refreshed the page after the session max duration (specified in SESSION_MAX_DURATION) was over
SESSION_HIJACKED: The account's assigned session was reassigned without logging out


This extra control enables the administrators to make better informed decisions in regards to suspicious accunt activity, an account that continuously has it's sessions hijacked is a clear sign that something's wrong, in contrast with the occasional hijack which may simply be a user that forgot to logout of his account in his desktop computer and relogs to the same account from his phone before the garbage collector can clear the previous session. A smooth transition between sessions that offers a much better user experience than outright rejecting the login attempt.


The app/configuration.php file has been updated to include settings for the session management changes, including a new session directory (app/tools/sessions) to store the SID files in a virtual host basis, this prevents PHP from piling up all the hosted sites SIDs into the same folder and the php.ini global settings from messing with individual configurations. Sessions themselves can also be toggled on and off from the config file, if enabled alongside the included request tracker (TRACK_REQUESTS), they are also added to the tracked data.


Finally, the included example site has been repurposed as a landing site and as a feature tester, keeping the project information updated in three different domains (xenobyte, the project's README file and the example site) was getting tedious, not to mention redundant. It will instead serve as the default landing page for POCKET_PHP installations.


New home and settings pages

There are still a couple of relatively minor tweaks and additions I'd like to make before releasing a few more example projects as previously planned. But with my current workload I'm just glad I got this update through.