tags:

views:

616

answers:

7

Hi everyone,

I am attempting to integrate an existing payment platform into my webshop. After making a succesful transaction, the payment platform sends a request to an URL in my application with the transaction ID included in the query parameters.

However, I need to do some post-processing like sending an order confirmation, etc. In order to do this, I'd need access to the user's session, since a lot of order-related information is stored there. To do this, I include the session_id in the intial request XML and do the following after the transaction is complete:

$sessionId = 'foo'; // the sessionId is succesfully retrieved from the XML response
session_id($sessionId);
session_start();

The above code works fine, but $_SESSION is still empty. Am I overlooking something or this simply not possible?

EDIT:

Thanks for all the answers. The problem has not been solved yet. As said, the strange thing is that I can succesfully start a new session using the session_id that belongs to the user that placed the order. Any other ideas?

A: 

Dirty, but has worked for me:

Tell the payment gateway to use

http://yourdomain.com/callbackurl.php?PHPSESSID=SESSIONIDHERE

PHP uses that method of passing a session around itself if you set certain config vars (session.use_trans_sid), and it seems to work even if PHP has been told not to do that. Its certainly always worked for me.

Edit:

Your problem may be that you have session.auto_start set to true - so the session is starting automatically using whatever ID it generates, before your code runs.

benlumley
I have not tried this solution yet, but passing the session ID is not the problem; this seems to work. The $_SESSION variable stays empty, though.
Aron Rotteveel
see the edit regarding session.auto_start .... that stop your method working, but allow mine to work.
benlumley
Thanks for your reply. session.auto_start is disabled. The request passes through my front controller though, where a session is automatically started. To prevent using this session, I call session_destroy() before setting the ID and starting a new session. Printing session_id() works fine.
Aron Rotteveel
try turning error_reporting/display_errors on - the second call to session_start could be failing when sending headers for a couple of reasons.
benlumley
Error reporting is enabled and does not display any errors.I use var_dump($_SESSION); and die(session_id()). The first is empty, the second displays the correct session_id (which SHOULD hold data)
Aron Rotteveel
are you using a framework or something? It may have some extra security on the session thats getting in the way. EG: limiting it to the IP address that started it.What you are doing should work - its definitely possible, so keep going!
benlumley
Thanks for your help so far; I am using Zend Framework, but I use a simple session_start() call for handling the sessions...The strange thing is that I am able to set the session ID and start the session with it, but the variables are not set...
Aron Rotteveel
Starting a session is never a problem, whats more important is if that session already existed or not.
jishi
it may not be relevant, but you can replace the built in code behind the session_start function (and all of the session functions) - http://uk3.php.net/manual/en/function.session-set-save-handler.php
benlumley
The session_id is equal to the one that has been assigned to the user placing the order.
Aron Rotteveel
I have now tried using PHPSESSID in my url. Again, session_id is set correctly, but $_SESSION is still empty...
Aron Rotteveel
+4  A: 

Not really what you ask for, but don't you need to persist the order into database before you send the customer to the payment-service? It's better to rely on persisted data in your post-processing of the order when you receive the confirmation of the payment.

Relying on sessions is not reliable since you will have no idea on how long this confirmation will take (usually it's instant, but in rare cases this will have a delay).

Also, in the event of your webserver restarting during this time span, will make you lose relevant data.

A third issue is if you have a load-balancing solution, with individual session-managment (very common) then you will have no guarantee that the payment-server and your client will reach the same webserver (since stickiness is usually source-ip based).

jishi
load balancing is a good point!another thing I've done before is to send the provider a hash value (just for added security, prevents users guessing the url) and id for the order, and then use that to identify the order on callback.
benlumley
Thanks for your answer. You provide a valid point, but my current order process only partially persists order data in the database. During the order process, some state-specific data is stored in the session, since this provides an easy solution to handling failed payments, for example.
Aron Rotteveel
A: 

How about do it in another PHP page, and you do a iframe include / redirect user to the second page?

Dennis Cheung
A: 

I'm not sure the exact length of time between your transaction and your check; but it certainly seems that your session cookie has expired. Sessions expire usually after 45 minutes or so by default. This is to free up more uniqid's for php to use and prevent potential session hijacking.

I'm not sure if you have a custom session handler and whether it's stored in the database but guessing from your posts and comments on this page I would assume it is stored in server side cookies.

Now the solution to your problem, would be to bite the bullet and store the necessary data in the database and access it via the session id, even if it means creating another table to sit along side your orders table.

If however you are doing the action immediately then the other explanation is that either the user logged out or committed an action which destroyed their session (removing the server side cookie).

You will see these cookies in your servers /tmp folder, try have a look for your cookie, it should be named 'sess' + $session_id.

Jay
+3  A: 

I will venture to guess that since domains are different from where the session is set to where you are trying to read it, php is playing it safe and not retrieving session data set by a different domain. It does so in an effort to preserve security in case somebody were to guess session ID and hijack the data.

Workaround for this, assuming the exchange happens on the same physical disk, is to temporary write order data to a serialized (and possibly encrypted depending on wether or not full credit card number is being tracked, which is a whole another story) file that once read by the receiving end is promptly removed.

In essence all that does is duplicates the functionality that you are trying to get out of sessions without annoying security side-effects.

smazurov
Thank you for your reply. It got me thinking and finally helped me solve the issue as explained in http://stackoverflow.com/questions/325836/how-to-re-initialize-a-session-in-php#328987.
Aron Rotteveel
A: 

Make sure you're closing the current session before you attempt to start the new one. So you should be doing:

$id = 'abc123';
session_write_close();
session_id($id);
session_start();
+1  A: 

Many thanks for all the replies.

Smazurov's answer got me thinking and made me overlook my PHP configuration once more.

PHP's default behaviour is not to encrypt the session-related data, which should make it possible to read out the session data after restarting an old session from another client. However, I use Suhosin to patch and prevent some security issues. Suhosin's default behaviour is to encrypt session data based on the User Agent, making it a lot harder to read out other people's sessions.

This was also the cause of my problems; disabling this behaviour has solved the issue.

Aron Rotteveel