I’ve written a wordpress plugin that allows pages of the wordpress site to host data from a separate php/MySQL app on the server.
One function of the plugin is to give the website visitor a token in their session that allows them to download a file from the other app.
AFAIK, this has been functioning properly for several years. But after a recent server upgrade (which included PHP 5.4.43) several session-related bugs popped up. I solved those issues by introducing a custom save_path which is being used via php.ini in the custom app, and set manually in my wordpress plugin.
Here’s the operative code from the plugin initialization:
function myStartSession() {
if(!session_id()) {
session_save_path("/my/custom/save/path");
session_start();
}
}
add_shortcode( 'mypluginname', 'print_gadget' );
add_action('init', 'myStartSession', 1);
Here’s the operative code from when the plugin is triggered by a shortcode:
//make a call to the external app
$request = new RestRequest($apis['Playlist'], 'POST',$requestArgs);
$request->execute();
$data = json_decode($request->getResponseBody(),true);
//set the token in the session
$_SESSION['gueststamp'] = time();
//extract valid mediaIDs
$playlist = $data['Results'];
$validIDs = array();
foreach($playlist['Items'] as $row){
$validIDs[] = $row['ID'];
}
$_SESSION['guestvalidIDs'] = $validIDs;
//print out playlist template into buffered output
ob_start();
//DEBUG: print out session variable
print "<!--";
print_r($_SESSION);
print "-->" //END DEBUG
include 'playlistgadget.php'; //renders output text
$contents = ob_get_contents();
ob_end_clean();
//return the buffer
return $contents;
Note the debug code. When a user visits the wordpress page with this plugin’s shortcode, everything seems to work fine, and the page source includes the token in the HTML comment that I added for debugging purposes.
Next, the visitor can click on a button which links to download.php from the external app (on the same domain). Download.php checks for a valid token in the session and delivers a file if the token is found. The bug is that download.php executes the following codepath even though the user should have a valid token in their session:
//note: download.php actually references several utility functions, but I've simplified it to show only the codepath that is actually getting executed
session_start();
$mediaID = $_REQUEST['mediaID'];
if($mediaID == "" || !is_numeric($mediaID)){
print "invalid media ID";
die;
}
if(!isset($_SESSION['gueststamp']) || (time() - $_SESSION['gueststamp'] > 36000)){
print "no such media found.";
print session_id(); //debug
print_r($_SESSION); //debug
die;
}
When I run the download page, the session_id matches the ID from the wordpress page with the plugin, but the $_SESSION variable is empty.
I’ve tried a bunch of things, and I’m pretty stumped. Any ideas?
OK- I finally figured it out.
In the original post, I mentioned some weird session bugs I fixed last month by changing the
session.save_path
. I usedphp.ini
files to do that, and in order to get something that seemed to work, I updatedphp.ini
in the public root directory, and in the root directory of the app.For mysterious reasons, PHP was unhappy with having multiple nested
php.ini
files. Additionally, the shared hosting I’m using seems to really dislike using any folder other than the default/tmp
for sessions. I’m guessing this latter bit is a permissioning issue due to shared hosting.As best I can tell the problem chain was:
php.ini
files in place while the host’s config was broken, this messed up sessionssession.save_path
config to my customphp.ini
filessession.save_path
values from myphp.ini
config files, and others were pulling from the root config.phpinfo()
did not indicate that any scripts were referencing the root config.At one point, I managed to get all of the scripts reading from my shiny new
session.save_path
only to discover that new path was not saving ANY session data (probably due to permissions issues).Fortunately, my hosting company has since fixed the original problem with their config files. My fix was to remove ALL of the custom
php.ini
files so that all scripts are once again reading only the root config and using the samesession.save_path