Monday, December 12, 2016

xdebug with phpstorm and puphpet vagrant box

Xdebug is useful in many ways. debugging,  profiling, error reporting.

I have linked to many of these articles throughout this post.

Assuming you have already used that article to setup puphpet with phpstorm, this is how you can add profiling... (could add these configs to your puphpet box also!)

Configure your php.ini for xdebug with remote handling and profiling.

 /etc/php.d/99-xdebug.ini

 [XDEBUG]
 xdebug.default_enable=1
 xdebug.remote_connect_back=1
 xdebug.remote_enable=1
 xdebug.remote_handler=dbgp
 xdebug.remote_port=9000
 xdebug.remote_autostart=1
 ;xdebug.profiler_enable=1 ; uncomment for always enabled
 xdebug.profiler_output_dir=/var/www/vhosts/xdebug ; where to store output
 xdebug.profiler_enable_trigger=1 ; allow cookie/get/post to enable.
 ;XDEBUG_PROFILE cookie or GET/POST == 1

Add XDEBUG_PROFILE to your cookies or GET/POST

http://mytest.net/?XDEBUG_PROFILE=1
OR
https://www.jetbrains.com/phpstorm/marklets/ -- add bookmarks to your browser to make it easier!

Find your output

in xdebug.profiler_output_dir (directory)
file names are like "cachegrind.out.%d" where %d is unique per logged profile

Open with Phpstorm


Then select your file...


and you will end up with a profile that allows deep analysis of your script execution



Older article which may provide some more insight.

For LARGE cachegrind files... use qcachegrind

Monday, December 5, 2016

session_regenerate_id causing fatal error in Php 7

While upgrading to Php 7, our code had an issue with session_regenerate_id().

Catchable fatal error: session_regenerate_id(): Failed to create(read) session ID: user (path: /var/lib/php/session)

Thanks to bellosthomas, I was able to determine that our DB_Sessions class was causing the issue. It was a simple fix of FORCING the return values to be strings.  I have marked the code and comments with BOLD and UNDERLINED text so you can see the strings.  Just make sure that your "sess_read" method is returning a string!


https://bugs.php.net/bug.php?id=70871

  [2015-11-13 05:23 UTC] bellosthomas at gmail dot com
I was also getting a fatal error (check comment above), with a custom session handler. After yohgaki's comment about the return value of the read() method, which needs to return a string, I checked my session handler and I saw I was returning boolean false in some cases. Casting the return value to string, solved it.


https://gist.github.com/Artistan/0838c95d46ffad965570afa0ec354091
<?php
/**
* Initial Setup of file
* Garbage collection sucks, we should have a time check during read and auto destroy/not recover old sessions
*/
class DB_Sessions
{
var $session_life = 300;
var $sessiontable = 'sessions';
var $recordtable = 'sessions_loginrecord';
/**
* @var DB_Wrapper
*/
var $dbhost;
var $sessionhash;
var $write_callback;
var $memcache;
function __construct(&$dbhost)
{
$this->dbhost =& $dbhost;
ini_set('session.save_handler', 'user');
session_set_save_handler(
array($this, 'sess_open'),
array($this, 'sess_close'),
array($this, 'sess_read'),
array($this, 'sess_write'),
array($this, 'sess_destroy'),
array($this, 'sess_gc')
);
if(function_exists('memcache_pconnect')) {
$this->memcache = @memcache_pconnect($_SERVER['MEMCACHE_SERVER'], $_SERVER['MEMCACHE_PORT']);
}
}
/**************************************
* sess_open
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $save_path STRING
* @param $session_name STRING
*
* @return BOOL
*/
function sess_open($save_path, $session_name)
{
return true;
}
/**************************************
* sess_close
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
* @return BOOL
*/
function sess_close()
{
return true;
}
/**************************************
* sess_read
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $key STRING
*
* @return BOOL
*/
function sess_read($key)
{
if (!is_object($this->memcache) OR (!$value = $this->memcache->get('sess_key_' . $key)))
{
$qry = "SELECT `value` FROM " . $this->sessiontable . " WHERE `sesskey` = '$key'";
$qid = $this->dbhost->query($qry);
if (list($value) = $qid->fetch_row())
{
$this->sessionhash = md5($value);
if (is_object($this->memcache) AND $value)
{
$this->memcache->set('sess_key_' . $key, $value, COMPRESS_CACHE);
}
return (String) $value;
}
}
else
{
$this->sessionhash = md5($value);
return (String) $value;
}
return '';
}
/**************************************
* sess_write
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $key STRING
* @param $val STRING
*
* @return BOOL
*/
function sess_write($key, $val)
{
$expiry = time() + $this->session_life;
$value = addslashes($val);
if (md5($val) == $this->sessionhash)
{
$qry = "UPDATE " . $this->sessiontable . " SET expiry = $expiry, userkey = '" . @$_SESSION['login'] . "' WHERE sesskey = '$key'";
}
else
{
if (is_object($this->memcache))
{
$this->memcache->delete('sess_key_' . $key);
}
$qry = "UPDATE " . $this->sessiontable . " SET expiry = $expiry, value = '$value', userkey = '" . @$_SESSION['login'] . "' WHERE sesskey = '$key'";
if ($this->write_callback)
{
call_user_func($this->write_callback, $val);
}
}
$qid = $this->dbhost->query($qry);
if (!$this->dbhost->affected_rows())
{
if (!empty($_SERVER['REMOTE_ADDR']))
{
$qry = "INSERT INTO " . $this->sessiontable . " VALUES ('$key', $expiry, '$value','" . @$_SESSION['login'] . "','$expiry','" . $_SERVER['REMOTE_ADDR'] . "','" . $_SERVER['HTTP_HOST'] . "')";
}
else
{
$qry = "INSERT INTO " . $this->sessiontable . " VALUES ('$key', $expiry, '$value','" . @$_SESSION['login'] . "','$expiry','\"\"','" . $_SERVER['HTTP_HOST'] . "')";
}
$qid = $this->dbhost->query($qry);
}
return $qid;
}
/**************************************
* sess_destroy
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $key STRING
*
* @return BOOL
*/
function sess_destroy($key)
{
$temp = time();
if (is_object($this->memcache))
{
$this->memcache->delete('sess_key_' . $key);
}
$qry = "SELECT userkey,started,ip,host FROM " . $this->sessiontable . " WHERE sesskey = '$key'";
$qid = $this->dbhost->query($qry);
$row = $qid->fetch_assoc();
$userkey = $row['userkey'];
$started = $row['started'];
$ip = $row['ip'];
$host = $row['host'];
if ($userkey <> "" AND $this->recordtable)
{
$qry = "INSERT INTO " . $this->recordtable . " VALUES ('$userkey','$started','$temp','$ip','$host')";
$qid = $this->dbhost->query($qry);
}
$qry = "DELETE FROM " . $this->sessiontable . " WHERE sesskey = '$key'";
$qid = $this->dbhost->query($qry);
return $qid;
}
/**************************************
* sess_gc
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $maxlifetime INT
*
* @return BOOL
*/
function sess_gc($maxlifetime)
{
$temp = time();
$qry = "SELECT sesskey FROM " . $this->sessiontable . " WHERE expiry < " . $temp;
$result = $this->dbhost->query($qry);
for ($i = 0; $i < $result->num_rows(); $i++)
{
$row = $result->fetch_assoc();
$key = $row['sesskey'];
if (is_object($this->memcache))
{
$this->memcache->delete('sess_key_' . $key);
}
$qry = "SELECT userkey,started,ip,host FROM " . $this->sessiontable . " WHERE sesskey = '$key'";
$qid = $this->dbhost->query($qry);
if ($qid)
{
$row = $qid->fetch_assoc();
$userkey = $row['userkey'];
$started = $row['started'];
$ip = $row['ip'];
$host = $row['host'];
if ($userkey <> "" AND $this->recordtable)
{
$qry = "INSERT INTO " . $this->recordtable . " VALUES ('$userkey','$started','$temp','$ip','$host')";
$qid = $this->dbhost->query($qry);
}
}
}
$qry = "DELETE FROM " . $this->sessiontable . " WHERE expiry < " . $temp;
$qid = $this->dbhost->query($qry);
return $this->dbhost->affected_rows();
}
/**************************************
* sess_isonline
***************************************
* Notes:
***************************************
* Used In
***************************************
* @author Richard Thomas
*
* @param $login STRING
*
* @return BOOL
*/
function session_isonline($login)
{
$temp = time();
$query = "SELECT userkey FROM " . $this->sessiontable . " WHERE userkey = '$login' AND expiry > $temp";
$result = $this->dbhost->query($query);
return $result->num_rows();
}
}