Symfony: Custom Session Save Handler Maximum Execution Time - php

I am using Symfony's Custom Session handler. It works fine when I set the session for the first time but when I refresh the page. The page will keep on loading and after 30 seconds which is max_execution_time defined in php.ini, the errors are shown. To setup custom save handler, I created a table sessions in ratchet database. The structure and the data in the table:
Now the script, on the top of page looks like this to initialize custom save handler:
<?php
ini_set('session.auto_start', false);
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
require dirname(__DIR__) . '/vendor/autoload.php';
$pdo = new \PDO('mysql:host=localhost;dbname=ratchet', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$storage = new NativeSessionStorage(array(), new PdoSessionHandler($pdo)); // Here when PdoSessionHandler class is initialized again on refreshing it locks the page there
$session = new Session($storage);
$session->start();
$username = $session->get('username');
The errors thrown by PHP script for Line 153:
Line 153 is a statement in the following method which executes and reads a session value from database.
private function doRead($sessionId)
{
$this->sessionExpired = false;
if (self::LOCK_ADVISORY === $this->lockMode) {
$this->unlockStatements[] = $this->doAdvisoryLock($sessionId);
}
$selectSql = $this->getSelectSql();
$selectStmt = $this->pdo->prepare($selectSql);
$selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$selectStmt->execute(); // Line 153
Is something broken in the framework's component or am I missing something? I have followed the documentation. I can't find anything that is new or has been added by myself.
Addition
In addition to initializing session in the web app, I initialize symfony session in my server script as well because it is required in order to attach the same session object to each connection. The points to be noted:
The application works fine for the first attempt.
Chat server works as intended. It never throws an error.
When the page in which I connect to the websocket server is refreshed, it remains in the loading state for 30 seconds. Then the errors occur.
Same happens in other browsers. Like it will let the connection establish but when I will refresh ........ See above :D

You mentioned that:
I initialize symfony session in my server script as well
Does this also call new NativeSessionStorage?
What I think is happening is that you are creating essentially two session handlers but PHP only knows about one and thus only closes the database connection / lifts the database lock for one of them. Let me see if I can explain clearly. Every time you instantiate NativeSessionStorage the class registers the sessionHandler (the pdo session handler in your case) with php via session_set_save_handler which you can see in the NativeSessionStorage code here.
When PHP stops execution it calls the PdoSessionHandler->close() method. However since you have two instances and php only has one registered as the session handler, its closing one but not the other. Which keeps the database locked. Based on your description I think this may be your problem. You should be able to easily test this by explicitly calling Session->save() try doing this explicitly in your app and server code to see if you don't get the locked error anymore.
Hope this helps!

Is the session closing when the websocket disconnects? If not, it is keeping the lock on the session record and not allowing the incoming request to continue past starting the session. The initial page load works because the websocket picks up the session when the page load is complete.

Related

Trigger function just before exit

I'm using DHTMLX Scheduler on the front end and DHTMLX Connector on the backend as part of my radio automation app. Every time a user edits the calendar, an AJAX call is made to a file that looks like this:
require_once("dhtmlxScheduler_v4/connector/scheduler_connector.php");
require_once('QDRAconf.php');
$res = mysql_connect($QDRAconf['mysqlHost'], $QDRAconf['mysqlUser'], $QDRAconf['mysqlPass']);
mysql_select_db($QDRAconf['mysqlDb']);
// init the schedulerconnector
$conn = new SchedulerConnector($res);
// render the table
$conn->render_table("events","id","start_date,end_date,text");
This file is my "shim" that hooks up the fronted to the back end. I want to run another PHP script that writes the changes to my crontab, but it needs to happen after the DHTMLX library has updated the database. Trouble is, the DHTMLX library will automatically exit whenever it thinks it's done: sometimes it might not get past the first require_once('...') line so I can't just put require_once('cronwriter.php'); at the last line of the script.
My solution to this was to create a class with a destructor that updates the crontab with the latest changes. Since the php manual states that destructors will still be run if the exit() or die() function is called, I added a dummy class with a destructor that runs cronwriter.php script: (I added this to the beginning of the file.)
class ExitCatcher
{
function __destruct()
{
require_once('cronwriter.php');
}
}
//init the class
$ExitCatcher = new ExitCatcher;
For some reason, it doesn't work.
register_shutdown_function may offer a quick solution; but, you might save yourself some future trouble by inspecting the cause of that library's sporadic process haltings.
A good place to start might be...
your browser's JS console for JS errors
your JS console's network tab for AJAX errors
your server's error logs for PHP errors

Using server-sent events and php sessions

I'm using in my project server-sent events where the JS is calling a PHP page, say eventserver.php which consists basically of an infinite loop which checks the existence of an event in a $_SESSION variable.
On my first implementation this lead my website to hung up because the eventserver took the lock on the session and did not release it until the timeout expired; however, I managed to resolve this issue by locking/unlocking the session by using session_write_lock() and
session_start() continuously in the loop.
This is actually causing a lot of PHP warnings (on Apache error.log) saying that "cannot send session cache limiter - headers already sent", "cannot send session cookies" and so on.
Posting some code here
session_start();
header('Cache-Control: no-cache');
header('Content-Type: text/event-stream');
class EventServer
{
public function WaitForEvents( $eventType )
{
// ... do stuff
while( true )
{
// lock the session to this instance
session_start();
// ...check/output the event
ob_flush();
flush();
// unlock the session
session_write_close();
sleep( 1 );
}
}
}
Why is this happening?
I am doing the same thing as the OP and ran into the same issue. Some of these answers don't understand how eventSource should work. My code is identical to yours and uses a session variable to know what view the user is on which drives what data to return in the event of a server trigger. It's part of a realtime collaboration app.
I simply prepended an # to the session_start() to suppress the warnings in the log. Not really a fix, but it keeps the log from filling up.
Alternatively, not sure how well it would work for your application, but you could use ajax to write the session variable you are monitoring to the database, then your eventSource script can monitor for a change in the DB instead of having to start sessions.
This is not a good idea. HTTP is a request-response protocol so if you want server-client communication to be bi-directional you will need to look into websockets or something similar. There are also things like "long polling" and "heart beating"
If you want an event loop try something like servlets in apache tomcat.
You will grapple for hours with issues because of your design.
Also check out ajax if you just want to shoot messages from javascript to PHP.
Make sure you know an overview of the tech stack you are working with :)
You don't need an infinite loop with SSE. The EventSource keeps an open connection to the server and any update on the server side data will be read by the client.
Check out basic usage of SSE here
It's probably because you start the session twice in your code. Don't restart the session at the beginning of the loop, but after the sleep().

how to serialize phpseclib?

I have been trying to serialize phpseclib connection since I am loading some php pages from ajax and I dont want to reconnect again and again.
Page 1 - define SSH2 First
require("Net/SSH2.php");
session_start();
$ssh = new Net_SSH2 ("localhost");
if ($ssh->login($username, $pass)) {
$_SESSION['obj'] = serialize($ssh);
}else{
echo "Invalid Login !!!";
}
Page 2 - Get Stored session with unserialize
session_start();
require("Net/SSH2.php");
$ssh = unserialize($_SESSION['obj']);
echo $ssh->exec('ls');
I want to put Login information in $_SESSION['obj'] too so Whenever I am on that php page i just $ssh = unserialize($_SESSION['obj']); and then $ssh->exec('pwd') ..
Is there work around or will I have to always connect/login to Net/SSH2.php whenever I am on that PHP page ???
Depending on which PHP version you have, you could try to declare a static variable for the ssh connection.
If phpseclib uses pfsockopen it might be able to reuse existing connections - but that is a longshot, and might require modification of the library.
But generally speaking you cannot do what you want in PHP. When the script is finished all open sockets are closed, as the executing process terminates.
You certainly can't store it in a session variable - as soon as the Net_SSH2 object goes out of scope it is destroyed.
The only way to have a persistent connection is to actually have a script constantly running which is keeping the connection open. Which means you have one script with a never ending while (true) { ... } loop which opens a connection once and keeps it. You then need to find a way to communicate with this script to make it execute commands. AMQP, ØMQ, Gearman, sockets and similar techniques can be employed for that.

Using same MySQL Connection in different PHP pages

I am creating a simple Web Application in PHP for my college project. I am using the MySQL database.
I connect to the database in login.php. After connection I assign the connection to $_SESSION["conn"] and then redirect to main.php.
In main.php I write $conn = $_SESSION["conn"]. But the connection in $conn does not work.
I thought that as the login.php script ends, the connection gets closed. So I tried using mysql_pconnect instead of mysql_connect but that too does not work.
I know I can reconnect to the database in every PHP file. But I don't want to do this. I want to use the same connection in all PHP files.
Instead of saving the DB connection in a session you should make the connection calls in a separate file such as db.php and then require it from each of your scripts. For example, place your connection in db.php:
mysql_connect('...', '...', '...');
mysql_select_db('...');
and then bring it in in login.php:
require('db.php');
$res = mysql_query('...');
You can then do the same for each PHP file that needs access to the DB and you'll only ever have to change your DB access credentials in one file.
After connection I assign the connection to $_SESSION["conn"] and then redirect to main.php.
You'll probably want to read up on PHP sessions. You can't store resources (database connections, file handles, etc) in a session, because they can not be serialized and stored.
Keep in mind that each and every visit to a PHP script invokes a new instance of the PHP interpreter (via CGI, via FastCGI, or via a built-in module), and invokes a new instance of the script. Nothing is shared between script calls, because the entire environment goes away when the script exits.
The other answers are correct -- you'll need to connect to the database on every script call. Place the connection in a common include file for convenience.
The second request may not be served by the same web server process as the first, which means that you will have a completely separate set of database resources. You'll need to connect again in this new process in order to run queries.
What I normally have is a Connection class that pages will require in order to establish a connection. Something along the lines of:
class Connection {
public $dbConnection = null;
public $isConnectionActive = false;
private $dbServer = null;
private $dbCatalog = null;
private $dbUser = null;
private $dbPassword = null;
}
This class handles opening and closing of the connection on any pages.
It sounds that you want to make your php connections persistants , in that way and if it is so , then you have to create a PDO Object with the required parameters to create a new PHP PDO Object that will attempt to connect to mysql , and in the object instanciation , try to pass persistancy option value to true , you may have available in every php scripts the same PDO Connection Objetc but you will end up to face issues with that way ... but it is not reconmmanded as PHP Programming Best Pratices ... the best way to do so is to include a connection file for every script in your project. Read PHP Documentation for Persistant Connections in order to learn more about Issues found for these Connection Objets especially for recent php versions. PHP Announced that Persistant Connections are on the way to be dropped from futur version as it may increase server workload with persistant ressources ... Sorry if it is too late

Understanding PHP's database connection variable

How can you have only one declaration of the database connection variable, $dbconn?
My login script is based on the following procedure
If the user is not authenticated, he is thrown back to the login page
If the user is authenticated, he gets an $_SESSION["logged_in"] = true;
Then when the user is browsing the main page or other pages that need auth, they just check if the $_SESSION["auth"] is set.
I have the database variable only at the beginning of my index.php:
$dbconn = pg_connect("host=localhost port=5432 dbname=masi user=masi password=123");
I do not the connection by db_close() anywhere in my codes.
I source my login script to index.php which uses my database.
However, I get the standard warnings of not getting access to db when I do not have the variable declaration also in my scripts. If I add the declaration to each of my scripts, I get an access to db.
We need to first understand how PHP is running the show here before we can delve into the wide, wide world of database connections.
Each PHP page request fires off a new PHP script. While you may have sessions turned on, that's an internal PHP construct only. The database sees this as a new connection/process connecting to the server. Therefore, it creates a new process on the database for it, so long as you call your pg_connect code. Otherwise, Postgres has no idea who you are or what session you want to use. Moreover, once the parent process dies, it generally kills the Postgres session (in this case, the PHP script runs and then dies once it's finished). Sometimes these can leave zombies roaming the streets of Postgres, but by and large, it'll just kill them.
If you want to use SQL code in your PHP script, you must connect to the database in that script before making a call to Postgres.
If i remember your other question you're redirecting to login.php? Which means that no the dbconn variable will not exist because it was initialised on another page.
if you required login.php from index.php it would work
$dbconn = pg_connect("host=localhost port=5432 dbname=masi user=masi password=123");
require_once('login.php');

Categories