PHP custom session handler - database connection becoming NULL - php

I debugged and searched for quite a while and I can't figure out what is happening. This is my first time doing a custom session handler, so I'm afraid I'm overlooking something painfully obvious. I want to implement a custom session handler so I can store additional information with the sessions and be able to temporarily disable access to protected areas of the site for certain groups of users.
My login page (which was working fine with basic file-based php sessions), includes a php file with a lot of functions including the session handler functions and my error handler. That included file includes a third file that does the database connection. The connection is made using mysqli_connect() and the resulting link is stored in a variable, $dbc. That same connection is used throughout the site for logging errors, loading/editing site content, etc. I decided to use the same database connection, since it is used already on every page and my session handler will need to be used on almost every page as well. Nowhere in my code do I manually close the database connection, but I think perhaps it is automatically closing somehow.
My functions access the database connection ($dbc) with a global statement. Ex:
function sess_write($id, $data)
{
global $dbc;
...
My open, read, and write functions are supposed to use the variable in this manner. I checked the database connection variable in the open and read functions and it is non-null as expected, but in my write function it suddenly shows up as null. Is PHP doing something between read and write that could potentially be closing that connection? I created a test variable in the same included file that creates the database connection, and used the same global $test; statement in the write function, and that variable appears just fine, so I'm guessing it has something to do with the database being closed. I tried using a second variable to store the database connection (to only be used by the session handler) and that didn't work either. Any ideas? Am I just being dumb as usual?

Per your note, that is correct -- objects will be disposed of before write and close. The traditional workaround for this is to use the register_shutdown_function. PHP 5.4 now has an interface you can use to write a session handler class that simplifies this process. If you implement the interface in a session class, when you pass it to session_set_save_handler() it defaults to setting things up to register the shutdown call for you.

Related

Session variable not being set if not in global scope

I am trying to make a login system using a series of methods and sessions. This is how it works:
User makes POST request via XHR to domain.com/api/login
Nginx does a rewrite to domain.com/api.php?request=url
File runs some validations, and if everything is good, it instantiates the target class and then uses call_user_func_array to call the target method with the newly instantiated object.
Method called is UsersController->logIn, this method runs some validations, and then calls UsersModel::Condition which in simplest terms selects the user and returns an object with the user's properties and a few methods.
Then, we run $instanceOfUserRow->LogIn(), which updates the last_logged column of that user and also instantiates the session doing $_SESSION['user_id'] = $this->user_id.
However, no matter what I try, it just will not set the session variable. I tried the following:
Naming the variable different, from user_id to identifier, to id_test, etc.
Instead of setting it in the UserRow->LogIn method, set it instead in the UsersController->logIn directly, which also didn't work
Created a session variable in my framework's main file (Called Init.php) called test.
This session variable was set successfully and behaved correctly, and the behavior was the same if I renamed it to user_id, which I thought was weird.
Created a simple function that was declared right after the session_start in the Init.php file called set_session that simply took the name and value and set a session like this: $_SESSION[$name] = $value;. This also didn't work.
At this point I have no idea what to do, I did verify that the session was active using session_status before setting any new variable. Classes are loaded using a custom autoload. I am not sure if the culprit is either how many files we are layering through (From the original request being API/login, then rewriting to api.php, then UsersController.php, then UsersModel.php and then UserRow.php) or if it could be just the fact that it is being called via call_user_func_array.
Any help or leads would really help out. Thank you.
Turns out even though nearly everything was the same, I was querying the API using HTTPS, but the request was being made from a page that was not over TLS.
So requests were being made from http://website.lan to https://website.lan/api and that caused the session to change across requests.

My website started to load slow after I added mysqli

I am sorry if there is lack of information I'm not that really good of explaining and English is not my native language.
After I designed the website with html/css etc...I started to add mysqli, to display the user information, tables.
I just glimmsed at your code: In every function, you are calling db_login(), which opens every time a new database connection. Try to reuse the same database connection, would speed up a lot.
For example you can make a global variable, where you open the connection once and then import the variable via the global keyword, or you could pass the functions this variable as parameter. This best option though, would be designing the whole thing into a class, where the (open) connection is a shared variable of the instance of this class.

PHP Class - Store MySQL connection for each instance

I'm facing a problem which I don't know how to solve. Let's start explaining:
I've got the following class:
class MyClass{
function MyClass($mysql_dbcon){
$this->mysql_dbcon = $mysql_dbcon;
}
function execute(){
include("myscript.php");
}
}
myscript.php is an HTML template which uses Ajax to comunicate with other PHP scripts. Since these other PHP scripts aren't included directly in the class I'm not able to get the variable mysql_dbcon and use a different connection for each instance. Let's guess I've got the following instances:
$i1 = new Myclass($dbcon1);
$i1->execute();
$i2 = new Myclass($dbcon2);
$i2->execute();
Both instances will execute an Ajax function which call other processing scripts but these scripts can't access the instance's mysql_dbcon variable due to they're independent script executions.
How can I solve this? Is it correct to store the MySQL connection in $_SESSION so all the scripts can access it? Maybe this:
$_SESSION['instance_identifier'] = $this->mysql_dbcon;
What I want to achieve
I want to create a class in which the developer can set a MySQL connection and each instance can access to different databases so each instance will show data from different databases. The problem is the dynamic loading of that data.
Thanks in advance
You cannot solve it.
but this script can't access the instance's mysql_dbcon variable due to it's an independent script execution
Exactly. Period. You're starting an entirely different PHP script which shares absolutely nothing with the previous script. In fact, by the time the AJAX request is initiated by the browser, the "existing" MySQL connection will already be torn down and closed since the entire PHP script has already stopped.
"myscript.php" will simply have to open a new connection. You cannot serialise a connection into a session; it's not data which can be represented in a serialised form. This is exactly the same mechanism as any other two independent PHP files, the fact that include and AJAX are involved changes nothing.
Also see https://stackoverflow.com/a/13840431/476
Is it correct to store the MySQL connection in $_SESSION so all the scripts can access it?
No.
I'm facing a problem
You probably aren't, or at least it's not the problem you think it is. It's likely there is no reason for you to need to try to "share" the same database connection across the scripts, even if you could. If you provide more context about why you want to access the same connection, then further advice can be given. There is probably a better way to achieve what you want.
Perhaps you are trying to access one query's result set in different places, in which case the answer would not be trying to share a connection but probably to pass the result set itself.
Additional note about your syntax
class MyClass {
function MyClass($mysql_dbcon) {
Looks like you're using outdated PHP 4 syntax for your constructors. See the manual entry on constructors in PHP 5 for the modern standard.
It's also good practice to define the visibility of your class members using the public/protected/private keywords. See the manual entry on visibility.

MySQL Variables PHP COnnections

I'm using a PHP web application to connect to MySQL, what I would like to do is set the userID of the client who has logged in and then use that MySQL variables within views and functions to limit data returned.
Currently, I'm simply using:-
SET #UserID = 3;
And then referencing this within views/functions.
Is this a suitable and reliable method to do this across multiple concurrent user sessions? Will this be present for the lifetime of that users MySQL connection (or page load) from PHP and I obviously want to ensure no other connections leverage this. It's set on every page load (or MySQL reconnection from my app).
Thanks all!
As it clearly states in the first paragraph of the mysql variables man page: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html
User-defined variables are session-specific. That is, a user variable defined by one client cannot be seen or used by other clients. All variables for a given client session are automatically freed when that client exits.
e.g. they exist while the php<->mysql connection is kept alive, PER connection, and automatically removed when the connection is closed/terminated. Unless you're using persistent connections in PHP (which you shouldn't be anyways), the mysql variables would basically exist for the life of that particular script invocation, and will NOT be available when the same user comes back with another http request later.
So, strictly speaking, what you're doing shouldn't be a problem (each PHP connection exists more-or-less independantly). But, that said, it isn't the best approach.
I think you've got a "if all you have is a hammer, everything looks like a nail" problem. MySQL is not designed with the request lifecycle in mind, and it shouldn't need to be aware of it. PHP, on the other hand, is designed with exactly that idea.
Instead of:
mysqli_query('Set #UserID=' . $id);
$output = mysqli_query('SELECT * FROM FOO WHERE ID=#UserID');
Why not just use bound variables?

session data not being written to database

The site I'm renovating writes session data to their database using the session_set_save_handler function as follows:
session_set_save_handler (array(&$ses_class, '_open'),
array(&$ses_class, '_close'),
array(&$ses_class, '_read'),
array(&$ses_class, '_write'),
array(&$ses_class, '_destroy'),
array(&$ses_class, '_gc'));
I have the _open, _close, etc. functions log any calls they receive to the error_log
file but upon opening I only see calls to _write and _close. Why would these be the
only functions being called?
Also, depending on the page I'm on the _write function can or cannot write to the
database, returning an 'Access denied...(using password: NO)' mysql_error.
I'm at a loss. Any good resources I should look at?
You're definitely calling session_start() after session_set_save_handler?
'Access denied...(using password: NO)'
mysql_error.
That usually indicates that the the database hasn't been connected to, so PHP is attempting to connect with the default username and no password, which 99.999% of the time doesn't work. E.g. mysql_query() is being called before mysql_connect()
Sounds like problems with the ordering of the code.
PHP 5.1 had a bug where objects were destroyed before the session was closed. My solution was to create a destructor function for my DB object that explicitly closed the session.
The other problem is that you might have code starting up the session before the database connection is initialized. That requires carefully tracing through your includes looking for global code unexpectedly calling $_SESSION. This will also play hop with your session_set_save_handler() call. I had that problem in a previous job. The only solution was to re-order how things initialized so they didn't happen in the wrong order.
My question was two-part and this answer corresponds to the second part, the issue of not being able to write to the database.
The session object the site I'm working on uses did not store the database resource and so database connections made downstream in the code were clobbering the session's connection. I created an object variable to store the database resource and explicitly referred to it in all session queries, i.e.
$result = mysql_query($query)
became
$result = mysql_query($query, $this -> db);
and I'm now able to write to the database just fine.

Categories