I am setting up a EC2 cluster with a load balancer. I have seperate DB server which has mysql running on it. I have 3 webservers running, mostly for high availability, and of course its round-robin load balancing it seems, so every page you go to you get a different server which looses your session.
I am trying to setup PHP to store it in the DB. I have setup a table, and setup all the functions (open,close,etc). and I have set:
session_set_save_handler('_open',
'_close',
'_read',
'_write',
'_destroy',
'_clean');
But when I login or anything on the site I check the table and nothing has been written. I am not sure If i need to change something in the php.ini file. If so what is the value to change?
Thanks!!
EDIT: functions:
function _open(){
global $con;
connect();
}
function _close(){
global $con;
//mysql_close();
}
function _read($id){
global $con;
$id = mysql_real_escape_string($id);
$sql = "SELECT data FROM sessions WHERE id = '$id'";
if ($result = mysql_query($sql, $con)) {
if (mysql_num_rows($result)) {
$record = mysql_fetch_assoc($result);
return $record['data'];
}
}
return '';
}
function _write($id, $data)
{
global $con;
$access = time();
$id = mysql_real_escape_string($id);
$access = mysql_real_escape_string($access);
$data = mysql_real_escape_string($data);
$sql = "REPLACE
INTO sessions
VALUES ('$id', '$access', '$data')";
return mysql_query($sql, $con);
}
function _destroy($id)
{
global $con;
$id = mysql_real_escape_string($id);
$sql = "DELETE
FROM sessions
WHERE id = '$id'";
return mysql_query($sql, $con);
}
function _clean($max)
{
global $con;
$old = time() - $max;
$old = mysql_real_escape_string($old);
$sql = "DELETE
FROM sessions
WHERE access < '$old'";
return mysql_query($sql, $con);
}
session_set_save_handler('_open',
'_close',
'_read',
'_write',
'_destroy',
'_clean');
The function you're using will interrupt the normal session function and insert your code in to act, then carry on with other internal functions.
In the functions where you aren't really doing anything session-wise (things like '_open' and '_close'), you need return something to carry on the command or it will just die right there.
Example:
function _open($save_path, $session_name){
global $con;
connect();
return true; //Do nothing but carry on
}
function _close(){
global $con;
//mysql_close();
return true; //Do nothing but carry on
}
Really this is not the answer to your question, but if you need really high availability I can suggest that storing sessions in mysql is not a good method.
A better practice: Put your sessions in memcache. Memcache server it's easy to install. Memcache client is easy to install and php support storing session in memcache without programming!!! Memcache store data in memory, not in disk and it's faster.
Here you can view a good post about this: http://kevin.vanzonneveld.net/techblog/article/enhance_php_session_management/
Luck!!
How come you can't use cookies? and just have the script check if the cookies is present then read the value's from there. Unless security is an issue .. I suggest cookies over sessions for cheap scalability ..Writing session's in the database won't be good and will probably result in expensive queries being ran for no reason.
The best database for sessions is going to be something like Redis or MonogDB and not MySQL and not memcached. You could use memcached depending on how much traffic you get, but Redis or MongoDB is a much more scalable database. Also, since you're on EC2, you may want to look at Amazon SimpleDB. It's a key/value store so it should lend itself well to sessions.
I'd personally run with MongoDB because not only can you store your sessions there, but you can take what you do have from MySQL and cache it there too as well as store other data in Mongo...Or just think about converting your site's database altogether because you'll probably fall in love with MongoDB =)
You can also look into the settings of HAProxy under Application Cookies. That may help you too.
Related
I've been checking on this error with no solutions specific to my code. I have connected to mysql server using the mysqli_connect() call. then passed the connection result to a $_SESSION to have it available over the whole website - as i normally do in all my other projects, But for some reason i keep getting the error:
"mysqli_query(): Couldn't fetch mysqli"
There is the code that generates the error:
if(!isset($_GET['sortBy']))
{
$listSQL = "SELECT * FROM '".$_SESSION['WorkTable']."'";
}
else
{
$listSQL = "SELECT * FROM '".$_SESSION['WorkTable']."' where ".$_GET['sortBy']."='".$_GET['sortBy']."'";
}
//get Contacts From DB
if(!empty(mysqli_query(#$_SESSION['IMWEDBcxn'],$listSQL)))
Here is the connection class code...
if(!empty($cxn))
{
$_SESSION['WorkTable'] = $dbTable;
$_SESSION['IMWEDBcxn'] = $cxn;
}
Anything I'm missing here?
As stated by Ivan Solntsev, do not store a connection handler in a user's session for 2 obvious reasons :
1- Handlers can not be serialized.
2- Anything you store in a user's session (using $_SESSION), would only be available under that user's scope. I suggest you read more about sessions and PHP, $_SESSION is not a way to store data over sessions.
So doing something like :
$connect = mysqli_connect("...");
$_SESSION["dbconnection"] = $connect;
mysqli_query($_SESSION["dbconnection"], $query);
IS WRONG!
If you want a persistent connection, to avoid reconnecting on each DB query, read about MySQLi and Persistent connections : http://php.net/manual/en/mysqli.persistconns.php . If you are running on a PHP version under 5.3, I'd recommend using PDO (which I'd recommend regardless of the PHP version you're using).
I am trying to send two values to my server to be input into a database in the same row, the problem I have is that it isn't possible to send both values in one request. So what I want to do is send both the values in separate requests but handle them on the server at once so I can add the values into a database as one entry. My php isn't very strong, and I have no idea how to go about doing this. Is it possible? How would I do it?
Here's what I have so far:
<?php
$user = "user";
$pass = "pass";
$table = "database";
if(isset($_POST['currentUser']))
{
$userID = 'currentUser';
}
if(isset($_POST ['e.regid']))
{
$regid = 'e.regid';
}
if ($regid && $userID != null)
{
$con = mysqli_connect("localhost", $user, $pass);
mysqli_select_db($con, $table);
if (mysqli_connect_errno$con))
{
echo "Error connecting to the DB: " . mysqli_connect_errno());
}
else
{
"INSERT INTO gek_devices('regid', 'pin') VALUES ($regid, $userID)";
}
}
No, due to network latency and unreliability there's not even any guarantee that both requests will ever arrive at the server, let alone within a minute apart, let alone that you could run code once handling both requests. In practice chances are over 90% that both requests will not even be handled by the same Apache process on the server, given that a default Apache install on *nix will prefork 10 'spare' instances.
If you need to process the data 'simultaneously` you need to send them in the same request, that's the only way to guarantee atomicity.
Your intended solution is completely impossible, but also a glaring XY problem. Solve why you can't send the values simultaneously right now instead of focusing on hacky workarounds following that.
I assume this will be a rather basic question for most of you PHP guys out there. Let's assume I have this file to work with a DB:
<?php
define("DB_HOST", "localhost");
define("DB_NAME", "dbname");
define("DB_USER", "admin");
define("DB_PASSWORD", "abcdefg");
$connection;
$result;
function connectDatabase() {
global $connection;
if(isset($connection)) return;
$connection = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if(mysqli_connect_errno()) {
die("Database connection failed: " . mysqli_connect_error() . " (" . mysqli_connect_errno() . ")");
}
}
function queryDatabase($query) {
global $connection, $result;
$result = mysqli_query($connection, $query);
if(!$result) {
die("Database query failed");
}
else {
return $result;
}
}
function releaseResult() {
global $result;
mysqli_free_result($result);
}
function closeConnection() {
global $connection;
mysqli_close($connection);
}
?>
And let's say it I call it like this:
<?php
require_once("db_connection.php");
function createNavigation() {
connectDatabase();
$query = "SELECT * ";
$query .= "FROM subjects ";
$query .= "ORDER BY position ASC";
$result = queryDatabase($query);
while($subject = mysqli_fetch_assoc($result)) {
//do something
}
releaseResult();
}
?>
The question is - do I actually have to release the local $result in the createNavigation function too or that is not necessary?
What is the mysqli_free_result good for anyway? Coming from other OOP languages I understand releasing/destroying/disabling/nulling objects, GC, memory management, etc. but I am kind of confused what it is good for in PHP considering the script runs only once, returns something and it is done. Thank you!
It's about helping php manage resources effectively. If you don't call it, then the resource will get cleaned up by php, but it's better to call it yourself and get rid of it straight away when you know it's no longer required.
Take an extreme example of a script which takes a second to run, where a database connection is opened at the beginning and only needed very briefly. Once the script finishes, resources (database connections etc) will be freed, but the connection could have been open for, say 0.8secs longer than needed. Now add multiple users hitting the page in parallel and you have ended up with lots of instances of this connection being open at any given time, whereas if yo had cleaned up the connection straight away, fewer instances would be needed.
In practice, it's not particularly necessary. Most PHP scripts are written to be accessed over HTTP, which means they run briefly, then they stop, and memory is freed up at that point. The only practical reason I could see this being important is if you're running a persistent script, such as one you've built as a daemon that you kick off and it continues to run until you stop it. Releasing your results at that point would prevent the memory footprint from bloating up.
For security, future compatibility, and because you said that you've come from an OOP background, you should probably be using PDO instead of the mysqli_* functions. To establish a MySQL connection, you create a new PDO object. To free up the resources, you simply unset of the object (or the result, as the case may be).
I'm trying to add some speed performance to a project I'm working on using memcache. However I'm having a problem with the following
public function sql_query($query){
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$memkey = md5($query);
$get_result = $memcache->get($memkey);
if ($get_result){
return $get_result;
} else {
$q = $this->mysqli->query($query);
$memcache->set($memkey, $q, false, 120) or die ("Failed to save data at the server");
if ($this->mysqli->error){
App::Error($this->mysqli->error);
}
return $q;
}
}
It is certainly putting something into memcached but I get this error when pulling it back out and use it as I would if it wasn't from the cache.
"Warning: mysqli_result::fetch_assoc(): Couldn't fetch mysqli_result"
Am I missing something? I'm sure I've used memcache before in a similar way without any issues.
You can not store all data-types into memcached (and other data-stores), one which most often does not work are resources Docs, for example a database link or a result identifier.
You stored such a value and on another request you pulled it out again. But as the database already is in another state, this resource does not work any longer. You get the error then.
Instead you need to store the result data from the query, that's static data you can put into memcache.
Just want to apologise in advance for writing so much text. Here is the problem: I use a persistent connection to connect to the database with a wait_timeout of 60 seconds and I store session data in a MySQL table. The problem I have is that the sessions just don't seem to use their own rows; each page refresh keeps starting a new session instead of using the old one. What is more, the persistent connections mentioned earlier keep starting new processes insead of using their own as they should. Since these two problems seem to have the same origin, I decided to put them here together. My PHP code is the following:
(View it on Pastebin)
mysql_pconnect('localhost', 'root') or die('Could not connect: ' . mysql_error());
mysql_set_charset('utf8');
mysql_select_db('azgoth') or die('Could not choose DB: ' . mysql_error());
session_set_cookie_params(3600,'/','www.azgoth',FALSE,TRUE);
session_set_save_handler('_open','_close','_read','_write','_destroy','_clean');
function _open(){
return true;}
function _close(){
return true;}
function _read($id){
$id = mysql_real_escape_string($id);
if ($result = mysql_query("SELECT data FROM sess_en WHERE id='$id'")) {
if (mysql_num_rows($result)) {
$record = mysql_fetch_assoc($result);
return $record['data'];}}
return '';}
function _write($id, $data){
$access = $_SERVER['REQUEST_TIME'];
$id = mysql_real_escape_string($id);
$access = mysql_real_escape_string($access);
$data = mysql_real_escape_string($data);
return mysql_query("REPLACE INTO sess_en VALUES('$id', '$access', '$data')");}
function _destroy($id){
$id = mysql_real_escape_string($id);
return mysql_query("DELETE FROM sess_en WHERE id='$id'");}
function _clean($max){
$old = $_SERVER['REQUEST_TIME'] - $max;
$old = mysql_real_escape_string($old);
return mysql_query("DELETE FROM sess_en WHERE access<'$old'");}
session_start();
Any ideas on what could be causing this issue?
EDIT: I thought at first that it was just in my head, but I can now confirm this: this weird thing keeps appearing randomly: it usually does, but not sometimes (rarely, in fact) doesn't..
The new session starting every time problem is probably because of the domain parameter you have passed to session_set_cookie_params(). You have passed www.azgoth, presumably because you have more than one top-level domain (TLD) and you want the cookies to be shared across all of them. This is not allowed. With what you have set, the TLD is azgoth, which is not (currently) possible, therefore the cookie will be invalid and will never be sent back to the server, ergo a new session will be started every time.
The persistent DB problem is probably server configuration related. The PHP manual states, on the page for mysql_pconnect():
Note, that these kind of links only work if you are using a module version of PHP. See the Persistent Database Connections section for more information.
...and...
Using persistent connections can require a bit of tuning of your Apache and MySQL configurations to ensure that you do not exceed the number of connections allowed by MySQL.