Running php script in background with session access - php

I need to call php script from main script that will run in background (i just want to call and proceed without waiting for response)
But I need access to user session in called script

My advice is don't use default PHP session because it might be tricky working with background process .... I would recommend session_set_save_handler http://www.php.net/manual/en/function.session-set-save-handler.php for a DB bases session
There is a good example here http://www.php.net/manual/en/function.session-set-save-handler.php#96305

Call
string file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] )
with $maxlen =0;
In filename you can give the url. In that url pass session id and in the called script set session id using session_id() and then call session_start().
Make sure that called script returns at least 520 dummy characters using flush() and ob_flush(), so that calling script do not wait.

The whole point behind a "session" is so that a user client can connect to the server multiple times in a "state-less" fashion, yet still maintain "state" like one single connection. "Session" data is shared between multiple connections from the same user client.
When you spawn off a background process on the server, whether or not you're using PHP, the "session" no longer has any real meaning. The user might even shut his client machine off with no effect on the server background process.
With that in mind, using Cookies as suggested elsewhere is totally useless. Cookies are saved on the client machine, and the background process will have Zero access to it.
If there is client information that your background process will need, then the calling process needs to pass it to the background process somehow, either as some kind of parameter or as some kind of a data file.
I would recommend saving the "$_SESSION" variable as a Json-encoded data string to a temporary file. The background process can read that file, Json-decode it back into an array, then use it just as if it were still a $_SESSION. Then remove the temporary file.

$_COOKIE['PHPSESSID'] = 'user_session_id';//Transfer parameters through $GLOBALS['argv']
session_start();

Related

Define php variable at php initialization

I'm currently coding one of my first php applications.
The application has to connect to a LDAP server and change some user attributes in the directory.
That application has some parameters to read in a mySQL Database in order to run.
Some examples of these parameters could be:
-LDAP Address
-LDAP Service Account
-LDAP Password
there are much more parameters, which rule, for example, the way users authenticate to my application,...
Currently, the database is read at each user session initialization, but, it doesn't have any sense because parameters do not vary from a session to another.
So, i'm looking for a way to load these parameters from the database, only one time (for example, at the php service initialization), and access to these parameters in the "normal" php code through variables.
What would be the best way to do this?
Thank you in advance.
You are looking for a persistent cross-request storage. There are many options for this.
The simplest is APCu (which can be used in conjunction with Zend OpCache, or for PHP < 5.5, APC).
Simply:
if (apc_exists('mykey')) {
$data = apc_fetch('mykey');
} else {
// create it from scratch
apc_store('mike', $data);
}
$data can be most any PHP type, arrays, objects, or scalars.
You can even put this code in the auto_prepend_file INI setting so it is run automatically on every request.
However: this is per server (and per SAPI, so mod_php/php-fpm/cli don't share the cache) so you will have to create it once per server.
Alternatively, for a multi-server setup you can use something like memcached or redis. These are stand-alone daemons that will let you store arbitrary key/value pairs of string data (so you may need to serialize()/unserialize() on the values).
I personally prefer memcache, which has two extensions for PHP, pecl/memcached and pecl/memcache (I prefer pecl/memcached, it has more features).
Both of them are pretty simple.
pecl/memcached:
$memcache = new Memcached();
$memcache->addServer('localhost', '11211');
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
pecl/memcache:
$memcache = new Memcache();
$memcache->connect(); // uses localhost:11211, the default memcache host/port
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
Both extensions support storage of arrays and objects without serialization.
You can of course store multiple keys with any of these solutions and just pull them all, instead of using one, or one with an array/object.
You can use Memcache do cache database requests. See here how to use.
Another way is using Php Sessions.
<?php
session_start(); // need to be before any html code
$_SESSION['something'] = 'Something here...';
echo $_SESSION['something']; // will show "Something here..."
And you can remove using...
unset($_SESSION['something']);
You also can use cookies, using the function setcookie. See here.
And you can get cookies using...
echo $_COOKIE['something'];
Production mode
In a production mode, this will work as set_transient of Wordpress. You will do the first db request to get the value and will cache this value using cookies, sessions or memcache.
If you want to show this values inside of your page, you can use a standard caching library.
My understanding of the question is that you have some SQL data that is more or less constant and you don't want to have to read that in from the SQL connection on every request.
If that is the case you can use memcache to store the data:
http://php.net/manual/en/book.memcache.php
The data will still be persistent and you will only need to go to the database if the cached data isn't there or needs to be refreshed.
If the data is specific to a particular user you can just use a session.
http://php.net/manual/en/book.session.php
http://php.net/manual/en/session.examples.basic.php
If this is only to be used when starting up your server (so once and done) and you don't want to bother to with memcached/xcache (as they would be over kill) you can still use environment variables. See get_env

Javascript AJAX call shows empty $_SESSION in PHP program

I am using AJAX to store the first 4 digits of a credit card in $_SESSION["first4"] number during the onBlur event. I have a sample which works flawlessly. Then I take that good code and stick it a shopping cart we purchased from Clearcart (we now own the code). The issue is that the $_SESSION variable is always empty in the AJAX php receiver program. Here is the entirety of the program:
$sessionName = "ClearCart20UserSession";
if (isset($_REQUEST[$sessionName])) session_id($_REQUEST[$sessionName]);
$started = session_start();
$_SESSION["first4"] = isset($_GET["first4"])?$_GET["first4"]:"";
After that fourth line of code the following variables are dumped: (i.e. these are output values not assignment statements)
$started = 1
session_id=4f920c1fe5e2078d95f7700ece674659
$_REQUEST=Array
(
[first4] => 5554
[PHPSESSID] => 4f920c1fe5e2078d95f7700ece674659
[ClearCart20UserSession] => 4f920c1fe5e2078d95f7700ece674659
)
$_SESSION=Array
(
[first4] => 5554
)
$_SESSION in the calling program literally contains thousand of variables. Yet, here in the receiver it is empty except for the variable I set.
Notes:
1) That is the same session_id/PHPSESSID as in the calling program - I have dumped it. (When I say calling program I mean the php program which generated the html form; obviously the actual 'calling' program is the javascript in the browser)
2) The http type and domain are identical (both are https:). I have put the receiver ajax program in the same directory as the caller just to eliminate any cross-domain issues.
3) The session save path is /tmp and when I look in that folder the sess_4f920c1fe5e2078d95f7700ece674659 file exists. (Although it seems smaller than I would expect with thousands of variables).
4) When I go back a page in my browser and then forward to re-show formerly saved session variables (i.e. things like form input values) they still exist so the AJAX recipient is not clearing $_SESSION as the empty array might imply.
5) The shopping cart uses cookies and the cookie values are correctly reflected in $_REQUEST as expected.
6) I added session_write_close() to the end of the main/caller program to ensure the session file is not open. Should not matter as the caller php terminates and nothing happens till the javascript event fires AJAX.
7) FWIW session.upload_progress.enabled is on.
8) Curiously the shopping cart uses AJAX for its own purposes which I believe is working fine. Regardless, I don't see how that could impact me - its completely different AJAX called and received by different javascript and php respectively.
9) As mentioned above, this virtually identical code works in a test sample I developed where I even mimic using cookies.
10) I have read several dozen postings on this issue but none have fixed my problem. Most seem to be related to not using session_start or having the right session_id.
What else can I try?
Found the problem: the shopping cart software changed the session folder with this line of code:
session_save_path("tmpsession");
Hence, even though the session_id's were identical the session files were stored in two different folder locations (the AJAX file was in /tmp and the main calling program was using www/tmpsession).

Setting session_id unreliable when using flash to send data

I'm using PHP version 5.3.2 on both my local development server and remote web server.
I'm trying to use uploadify to upload several files to the server. In the receiving script, I would like to use data stored in the session, however because uploadify sends files to the script using flash it doesn't send the session cookie.
The workaround for this problem is to get uploadify to GET or POST the session id to the script, however I'm finding this very unreliable.
In my script I have the following:
<?php
ini_set('session.use_only_cookies', FALSE);
ini_set('session.use_trans_sid', TRUE);
session_name('SESSNAME');
session_start();
print_r($_SESSION);
The script url is something like script.php?SESSNAME=sessionid and I have tried using transparent session ids as above and also manually setting the id using session_id($_GET['SESSNAME']).
This always works when accessing the script directly with the browser and sending the current session id along, even if I manually delete the session cookie. It also always works with uploadify on my local server. However when using uploadify on the remote server, it works about 20% of the time, completely randomly. There is no pattern. It seemed to work with greater frequency when I added
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1);
to the script, however this may have been just coincidence.
Local server info: http://www.dur.ac.uk/n.r.brook/info_local.php
Remote server info: http://www.dur.ac.uk/n.r.brook/info.php
Some speculation...
Doing some digging around and looking at the headers the script is receiving, I think I may have determined the issue.
You need to send the session id when using uploadify because flash does not send cookies when using the FileReference.upload() (I think!) method. However, as well as the session id, in load balanced environments (such as the remote server) there is also the BALANCEID cookie which determines which server the user is currently working with. Flash doesn't send this cookie so the load balancer sometimes sends the request to a different server, and on this server the session does not exist.
I have tested this behaviour by setting a session variable after I have printed the session. Doing this and repeatedly sending files exhibits the issue - at first I get an empty array, but a few repeats in the variable starts appearing.
So, if the above is all true, then my question is what can I do to get flash to send this data with the upload so the load balancer knows which server to use? Or is this a lost cause?
The answer?
After further research, I found the following post - http://swfupload.org/forum/generaldiscussion/977
This suggests there is no way cookies can be sent with FileReference.upload() and therefore uploadify cannot be used with load balanced servers if you want to use session data. However, I think I will now attempt a solution which saves data linked to the session id to a file. The uploadify receiving script can open this file and pull out the required data.
This is my first experience working with anything Flash based, it has not improved my opinion of the technology!
My solution to this problem is:
In the 'upload' page:
file_put_contents($some_folder.'/'.session_id(), serialize($just_the_vars_you_will_be_using));
In your javascript that loads uploadify:
var start = document.cookie.indexOf("PHPSESSID=");
var end = document.cookie.indexOf(";", start); // First ; after start
if (end == -1) end = document.cookie.length; // failed indexOf = -1
var cookie = document.cookie.substring(start+10, end);
$('#fileInput').uploadify({
'uploader' : 'uploadify.swf',
'script' : 'uploadify.php',
'cancelImg' : 'cancel.png',
'auto' : true,
'multi' : true,
'scriptData': { SESSID : cookie }
});
In the script that receives the files:
$vars = unserialize(file_get_contents($some_folder.'/'.$_POST['SESSID']));
If you want to write back to the 'session' in this script, at the end:
file_put_contents($some_folder.'/'.$_POST['SESSID'], serialize($vars));
As far as I know, there shouldn't be any security issues associated with this, as you will only be using a handful of variables stored in the file (I only store an incrementing value and a temporary file path). Make sure there is an index.html in $some_folder to prevent file listing.
There is a way you can use cookies when sending from flash.
Cookies is needed for php to find the session storage id. The value that is stored in the cookie is actual the session id and the cookie name is in most cases the session name.
To get the session in php canĀ“t be done by typing $_SESSION['name'] but you can make your own session library that you include. This will let php get all of the nassery values and you can continue.
Here is a session library that I put together in php:
function SESSION_OPEN($PATH,$NAME){
global $SESSION_PATH, $SESSION_NAME;
$SESSION_PATH=$PATH;
$SESSION_NAME=$NAME;
return(true);
}
function SESSION_CLOSE(){
return(true);
}
function SESSION_GET($ID){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
if($RESOURCE = #fopen($STR_PATH,"r")){
$CONTENT = #fread($RESOURCE ,filesize($STR_PATH));
return($CONTENT);
}else{
return(false);
}
}
function SESSION_PUT($ID,$VALUE){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
if($RESOURCE = #fopen($STR_PATH,"w")){
fwrite($RESOURCE , $VALUE );
return(true);
}else{
return(false);
}
}
function SESSION_DEST($ID){
global $SESSION_PATH, $SESSION_NAME;
$STR_PATH="$SESSION_PATH/USES_".session_id()."_$ID";
return(#unlink($STR_PATH));
}
function SESSION_GC($MAX_EXECUTION){
return(true);
}
session_set_save_handler("SESSION_OPEN","SESSION_CLOSE","SESSION_GET","SESSION_PUT","SESSION_DEST","SESSION_GC");

Saving variables (not sessions)

This may be a silly question, but how do I save variables that are not specific to a particular session. An simple example of why you might want to do this would be a visitor counter - a number that increases by one each time someone visits a web page (note - I'm not actually doing that, my application is different, but that is the functionality I need). The only ways I can think of doing this are either writing the variables to a file, or putting the variables into a database. Both seem a bit inelegant. Is there a better way to to this kind of thing?
If you need to save global state, you need to save global state. This is typically done in either a file or a database as you already noted.
It's not "inelegant" at all. If you need to save something (semi-)permanently, you put it in a database. That's what databases are for.
Have a look at the serialize() function in PHP http://uk3.php.net/serialize where you'll be able to write an array or such to a file and re-retrieve:
<?php
// Save contents
$var = array('pageCounter' => 1);
file_put_contents('counter.txt', serialize($var));
// Retrieve it
$var = unserialize(file_get_contents('counter.txt'));
?>
Otherwise save the value to a database.
Given that PHP is stateless and that each pageload is essentially re-running your page anew, if you're going to be saving variables that will increment over multiple pageloads (e.g., number of distinct users), you'll have to use some form of server-end storage - file-based, database, whatever - to save the variable.
You could try installing APC (Alternative PHP Cache) which has cool features for sharing data between all PHP scripts, you could try using shared memory too or like you said, use a file or database
I think I've found the answer - session_name('whatever') can be used to have a fixed name for a session, I can refer to that data as well as the session specific session.
If you want it to be permanent, database and files are really your only two choices.
If you only want to temporarily store these values in memory, if APC is installed, you can do this:
// Fetch counter value back from memory
$success = false;
$counter = apc_fetch('counter', &$success);
if ($success) {
// fetch succeeded
} else {
// fetch failed
$counter = 0;
}
// Increment the counter and store again
// Note that nothing stops another request/page from changing this value
// between the fetch and store calls.
$counter++;
apc_store('counter', $counter);
That was just an example.
For a counter, you're better off using apc_inc('counter') / apc_dec('counter').
Presumably other opcode caches have similar methods. If you're not running an opcode cache... really? You want PHP to recompile a page every time its requested?
Elegant, no database and no file ?
Store it in your server memory with shmop and hope your server does not reboot !

Accessing php $_SESSION from python (wsgi) - is it possible?

I've got a python/WSGI app which needs to check to see if a user has logged on to a PHP web app. The problem is that the PHP app checks if a user has logged on by comparing a value in the $_SESSION variable to a value in the cookie from the user's browser. I would prefer to avoid changing the behavior of the php app if at all possible.
My questions:
Is there anyway I can access the session variables from within python? Where should I start to look?
Are there any obvious security/performance issues I should be aware of when taking this approach?
yep. session (in default) is a regular file. so all what you need is look over session directory and find file with name of session cookie value. then - you have to implement php-like serialize/unserialize and do whatever you want.
nope
Depends on the PHP app, if it's keeping session data in a database (MySQL maybe) you can just connect to the database and get the data, if it's using native PHP sessions you should look to the session.save_path config setting in php.ini, that's the place where the runtime saves files with the session data.
Once you have the data you can parse it to get it unserialized, take a look at how serialize() and unserialize() work in PHP.
I'm currently in the process of trying to run a python server side by side with an existing Apache/php one. A custom solution I arrived at was to save the $_SESSION as an encrypted cookie, letting the php authentication operate as before, then share a private key between the two servers.
Two issues:
Up to you how to handle session expiry stuff.
I haven't bothered with an Initialization Vector, assuming the time stamp from my expiry stuff is enough. See https://stackoverflow.com/a/12486940/4495503 for why I might be being too security lax...
Anyway, my php encrypted cookie function:
session_start();
$encryptToCookie = function($varToEncode,$cookieName,$privateKey){
$iv = $privateKey;
$pass = $privateKey;
$method = 'aes-128-cbc';
$encryptedString = openssl_encrypt(json_encode($varToEncode), $method, $pass, true, $iv);
setcookie($cookieName,bin2hex($encryptedString));
};
$encryptToCookie($_SESSION,"sessionEncrypted","yohoyohoyohoyoho"); // private key must be 16bit
And my python side decryption:
from subprocess import Popen, PIPE
import binascii
def decrypt(encryptedString,privateKey):
encryptedString = binascii.unhexlify(encryptedString)
pathToOpenSSL = 'C:\pysrc\openssl\openssl.exe' # MODIFY THIS!!
openssl = Popen([pathToOpenSSL,
'enc','-aes-128-cbc','-d',
'-nosalt','-nopad','-K',
privateKey.encode('hex'),
'-iv',
privateKey.encode('hex')],
stdin=PIPE,stdout=PIPE)
decryptedString = openssl.communicate(encryptedString)[0].replace('\x04','')
return decryptedString
decrypt(encryptedString,'yohoyohoyohoyoho')
Hope this is of help to someone, remember all the usual stuff about generating private keys and then being careful with them!

Categories