I'm working on a recurrent payment system and currently have it nearly working on the sandbox site. The IPN simulator works and sends the test data back to my server, but I can't get the actual test payment to send any data back to the server. Once the user presses the subscribe button, they can make a payment. This works, and I actually receive the funds but I can't seem to find anywhere to send the user back to the server with a conformation string allowing me to update the database as 'user subscribed' Here is what I have so far: index.php <?php require('Paypal_IPN.php'); $paypal = new Paypal_IPN('sandbox'); $paypal->run(); ?> PHP: Paypal_IPN.php <?php class Paypal_IPN { /** @var string $_url The paypal url to go to through cURL private $_url; /** * @param string $mode 'live' or 'sandbox' */ public function __construct($mode = 'live') { if ($mode == 'live') $this->_url = 'https://www.paypal.com/cgi-bin/webscr'; else $this->_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'; } public function run() { $postFields = 'cmd=_notify-validate'; foreach($_POST as $key => $value) { $postFields .= "&$key=".urlencode($value); } $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => $this->_url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $postFields )); $result = curl_exec($ch); curl_close($ch); $fh = fopen('newfile.txt', 'w'); fputs($fh, $result . ' -- ' . $postFields); echo $result; } } ?> PHP: newfile.txt VERIFIED -- cmd=_notify-validate&address_state=CA&quantity=1&txn_id=566886121&last_name=Smith&mc_currency=USD&payer_status=verified&address_status=confirmed&tax=2.02&invoice=abc1234&shipping=3.04&address_street=123%2C+any+street&payer_email=buyer%40paypalsandbox.com&mc_gross1=9.34&item_name=something&first_name=John&business=seller%40paypalsandbox.com&verify_sign=r43f4t3453tg54g45ghg4&payer_id=TESTBUYERID01&payment_date=06%3A33%3A34+12+Apr+2013+PDT&address_country=United+States&payment_status=Completed&receiver_email=seller%40paypalsandbox.com&payment_type=instant&address_zip=95131&address_city=San+Jose&mc_gross=12.34&mc_fee=0.44&residence_country=US&address_country_code=US¬ify_version=2.1&receiver_id=seller%40paypalsandbox.com&txn_type=web_accept&custom=xyz123&item_number=AK-1234&address_name=John+Smith&test_ipn=1 PHP: I then added a subscribe button to index.php <?php require('Paypal_IPN.php'); $paypal = new Paypal_IPN('sandbox'); $paypal->run(); ?> <form name="_xclick" action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <input type="hidden" name="cmd" value="_xclick-subscriptions"> <input type="hidden" name="business" value="sales@sales.com"> <input type="hidden" name="currency_code" value="GBP"> <input type="hidden" name="no_shipping" value="1"> <input type="image" src="http://www.paypal.com/en_GB/i/btn/x-click-but20.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!"> <input type="hidden" name="a3" value="5.00"> <input type="hidden" name="p3" value="1"> <input type="hidden" name="t3" value="M"> <input type="hidden" name="src" value="1"> <input type="hidden" name="sra" value="1"> </form> PHP: Does anybody know of a way for me to send the user back to the website with information saying they have paid. Also, what would be the process for me to check on the next pay date that the user has paid?
Try adding the following hidden form element: <input name="notify_url" value="http://yourdomain.com/notify_url.php" type="hidden"> Code (markup): Where notify_url.php is the script you want paypal to hit you up with the following info on a transaction when its done: mc_gross invoice settle_amount protection_eligibility address_status payer_id tax address_street payment_date payment_status charset address_zip mc_shipping mc_handling first_name mc_fee address_country_code exchange_rate address_name notify_version settle_currency custom payer_status business address_country address_city verify_sign payer_email txn_id payment_type Source
It's been a while since I worked on PayPal IPN, but in my old code, I used: <input type="hidden" name="return" value="<?=$return?>" /><!-- Return to site URL --> Code (markup):
Thanks for your help. I've tried what you both said but to no avail. I figured out that I also needed to set up the IPN notification url in the profile tab on the Sandbox website. I did this but still not getting a redirect. Any ideas?
EDIT I can get it to work using a standard 1 off payment, but for the life of me I can't get it to work with a subscription. Updated index.php: <form action="https://sandbox.paypal.com/cgi-bin/webscr" method="post" id="paypalpost" name="paypalpost"> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="admin@domain.com"> <input type="hidden" name="item_name" value="Your Subscription"> <input type="hidden" name="currency_code" value="GBP"> <input type="hidden" name="return" value="http://website.com/paypal/thankyou.php"> <input type="hidden" name="p3" value="1"> <input type="hidden" name="t3" value="M"> <input type="hidden" name="src" value="1"> <input type="hidden" name="sra" value="1"> <input type="submit" name="submit" id="pay" class="buttonBlueBg" value="Checkout" > </form> PHP: updated thankyou.php <?php print_r('<pre>'); print_r($_POST); // read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; foreach ($_POST as $key => $value) { $value = urlencode(stripslashes($value)); $req .= "&$key=$value"; } // post back to PayPal system to validate $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Host: www.sandbox.paypal.com\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($req) . "\r\n\r\n"; $fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30); // assign posted variables to local variables $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $payment_status = $_POST['payment_status']; $payment_amount = $_POST['mc_gross']; $payment_currency = $_POST['mc_currency']; $txn_id = $_POST['txn_id']; $receiver_email = $_POST['receiver_email']; $payer_email = $_POST['payer_email']; if (!$fp) { // HTTP ERROR echo "HTTP Error"; } else { fputs ($fp, $header . $req); while (!feof($fp)) { $res = fgets ($fp, 1024); echo $res; if (strcmp ($res, "VERIFIED") == 0) { // check the payment_status is Completed // check that txn_id has not been previously processed // check that receiver_email is your Primary PayPal email // check that payment_amount/payment_currency are correct // process payment echo("verified"); } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation echo ("invalid"); } } fclose ($fp); } echo "end"; ?> PHP: On a standard 1 off payment, it returns the correct array, but if I set it up as above with a subscription it returns invalid.
Okay, I now have it working and sending back a "Completed" variable which is great. I can now authenticate the user using this variable. So next question... What can I do for next months payment? I need to do 1 of 3 things, but I don't know how I can handle them using Paypal as the user will not do anything, the billing is automatic isn't it? 1. Paypal notifies me that user has cancelled 2. Paypal notifies me of successful payment 3. Paypal notifies me of unsuccessful payment Is there a way I can do 1 of the above? Thanks
You need to grab the txn type... $type = $_POST['txn_type']; Then write a case for each.. <?php //ensure payment is valid and what you expected.. //then you can process based on trans type $type = $_POST['txn_type']; if($type == 'subscr_signup'){ // for new subscriptions }elseif ($type == 'subscr_cancel'){ //for canceled subscriptions.. }elseif ($type == 'subscr_modify'){ // if they modify the subscription }elseif ($type == 'subscr_payment'){ // monthly subscription payment }else{ // for a non subscription payment } ?> PHP: