Smashden Posted September 16, 2015 Share Posted September 16, 2015 Hey, I'm trying to integrate paypal into my site. When the purchase is complete, I want update my mysql database with the relevant values. However, when I test, the database does not update.I don't get any errors. This is my paypal.htm and ipn.php <?php $acc = $_SESSION["acc"] ?> <b>PayPal Shop System.</b><br><br> The shop costs:<ul><li> 5 EUR (for 1000 points)</li><li> 10 EUR (for 2500 points)</li><li> 20 EUR (for 6000 points)</li><br> <b>Here are the steps you need to make:</b> <br> 1. A PayPal account with a required balance [5, 10 or 20 EUR] or a creditcard. <br> 2. Fill in your account number. <br> 3. Click on the Buy Now button or your creditcard brand. <br> 4. Make a transaction. <br> 5. After the transaction 1000, 2500 or 6000 points will be automatically added to your account. <br> 6. Go to Item shop and use your points <br> <br> <br> </b> <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="my business email from sandbox mode(for testing)"> <input type="hidden" name="lc" value="US"> <input type="hidden" name="item_name" value="Premium Points"> <b>Account number: </b> <font color="black"><?php echo $acc ?></font> <select name="amount"> <option value="5.00">1000 PP - 5 EUR</option> <option value="10.00">2500 PP - 10 EUR</option> <option value="20.00">6000 PP - 20 EUR</option> </select> <input type="hidden" name="button_subtype" value="products"> <input type="hidden" name="no_shipping" value="1"> <input type="hidden" name="no_note" value="1" /> <input type="hidden" name="currency_code" value="EUR"> <input type="hidden" name="rm" value="0"> <input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynowCC_LG.gif:NonHostedGuest"> <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"> </form> <? baza(); // -- connecting with database ob_start(); $account = $_SESSION["acc"]; if ($_SERVER['REQUEST_METHOD'] == "POST") { if ($account == "111111" || $account == "1") { $error='Dla bezpieczeństwa ten numer jest zablokowany!'; } elseif (empty($account)) { $error='Podaj Numer Konta!'; } elseif (!is_numeric($account)) { $error='Numer konta może składać się wyłącznie z cyfr!'; } if (empty($error)) {$query=mysql_query('SELECT * FROM accounts WHERE (id = '.$account.')'); if (mysql_num_rows($query) == 0) {$error= "Numer nie istnieje";} } $query2 = mysql_query("SELECT `bonus` FROM `accounts` WHERE (`id` = '$account') ") or die(mysql_error()); if($_REQUEST['debug']) { ini_set('display_errors', true); error_reporting(E_ALL); } // Variables, don't touch! $receiverEmail = $_REQUEST['receiver_email']; $paymentStatus = $_REQUEST['payment_status']; $mcGross = $_REQUEST['mc_gross']; $mcCurrency = $_REQUEST['mc_currency']; // Prices $prices = array('5.00' => 1000, '10.00' => 2500, '20.00' => 6000); // Setup $receiver = 'my business email from sandbox mode(for testing)'; $currency = 'EUR'; if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency) { $data = date("U"); mysql_query("INSERT INTO archiwum(user, kod, data, typ) values('$account', 'Paypal', '$data', '1')"); // Process payment $data = mysql_select_single("SELECT `bonus` AS `old_bonus` FROM `accounts` WHERE (`id` = '$account');"); // Give points to user $new_points = $data['old_bonus'] + $prices[$mcGross]; mysql_query("UPDATE `accounts` SET `bonus`='$new_points' WHERE (`id` = '$account')); } else { exit(); } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/ Share on other sites More sharing options...
mac_gyver Posted September 16, 2015 Share Posted September 16, 2015 (edited) when paypal makes a http request to your ipn php page, the only input will be the $_POST data. there will be no $_SESSION data, because the request isn't coming from the visitor. your ipn script must also go through a data verification process with the paypal server to insure that the ipn request actually came from paypal. i recommend that you research the ipn documentation and search the web for existing ipn php scripts to see how they are coded. Edited September 16, 2015 by mac_gyver Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1520971 Share on other sites More sharing options...
Smashden Posted September 16, 2015 Author Share Posted September 16, 2015 Hmm, I rewrite some piece of code and nothing changed :/ <?php $acc = $_SESSION["acc"] ?> <b>PayPal Shop System.</b><br><br> The shop costs:<ul><li> 5 EUR (for 1000 points)</li><li> 10 EUR (for 2500 points)</li><li> 20 EUR (for 6000 points)</li><br> <b>Here are the steps you need to make:</b> <br> 1. A PayPal account with a required balance [5, 10 or 20 EUR] or a creditcard. <br> 2. Fill in your account number. <br> 3. Click on the Buy Now button or your creditcard brand. <br> 4. Make a transaction. <br> 5. After the transaction 1000, 2500 or 6000 points will be automatically added to your account. <br> 6. Go to Item shop and use your points <br> <br> <br> </b> <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="business email from sandbox mode"> <input type="hidden" name="lc" value="US"> <input type="hidden" name="item_name" value="Premium Points"> <b>Account number: </b> <font color="black"><?php echo $acc ?></font> <select name="amount"> <option value="5.00">1000 PP - 5 EUR</option> <option value="10.00">2500 PP - 10 EUR</option> <option value="20.00">6000 PP - 20 EUR</option> </select> <input type="hidden" name="button_subtype" value="products"> <input type="hidden" name="no_shipping" value="1"> <input type="hidden" name="no_note" value="1" /> <input type="hidden" name="currency_code" value="EUR"> <input type="hidden" name="rm" value="2"> <input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynowCC_LG.gif:NonHostedGuest"> <input type="hidden" name="return" value="http://127.0.0.1/sms_shop/"> <input type="hidden" name="cancel_return" value="http://127.0.0.1/sms_shop/"> <input type="hidden" name="notify_url" value="http://127.0.0.1/sms_shop/shop/ipn/ipn.php" /> <input type="hidden" name="custom" value="<?php echo $acc; ?>"> <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"> </form> <?php baza(); ob_start(); $account = $_SESSION["acc"]; if ($_SERVER['REQUEST_METHOD'] == "POST") { if ($account == "111111" || $account == "1") { $error='Dla bezpieczeństwa ten numer jest zablokowany!'; } elseif (empty($account)) { $error='Podaj Numer Konta!'; } elseif (!is_numeric($account)) { $error='Numer konta może składać się wyłącznie z cyfr!'; } if (empty($error)) {$query=mysql_query('SELECT * FROM accounts WHERE (id = '.$account.')'); if (mysql_num_rows($query) == 0) {$error= "Numer nie istnieje";} } $query2 = mysql_query("SELECT `bonus` FROM `accounts` WHERE (`id` = '$account') ") or die(mysql_error()); //reading raw POST data from input stream. reading pot data from $_POST may cause serialization issues since POST data may contain arrays $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $myPost[$keyval[0]] = urldecode($keyval[1]); } // read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; if(function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exits = true; } foreach ($myPost as $key => $value) { if($get_magic_quotes_exits == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://www.sandbox.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com')); // In wamp like environment where the root authority certificate doesn't comes in the bundle, you need // to download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path // of the certificate as shown below. // curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); $res = curl_exec($ch); curl_close($ch); 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 // Assign posted variables to local variables $item_name = mysql_real_escape_string($_POST['item_name']); $item_number = mysql_real_escape_string($_POST['item_number']); $payment_status = mysql_real_escape_string($_POST['payment_status']); $mcGross = mysql_real_escape_string($_POST['mc_gross']); $mcCurrency = mysql_real_escape_string($_POST['mc_currency']); $txn_id = mysql_real_escape_string($_POST['txn_id']); $receiver_email = mysql_real_escape_string($_POST['receiver_email']); $payer_email = mysql_real_escape_string($_POST['payer_email']); $user_id = $_POST['custom']; // Our user's ID // Prices $prices = array('5.00' => 1000, '10.00' => 2500, '20.00' => 6000); // Setup $receiver = 'business email from sandbox mode'; $currency = 'EUR'; if ($payment_status == 'Completed') { // Builds a string to insert into the db so you can see everything that has come across from paypal. // Pairs are separated by commas and paired key-to-value with a / forward slash foreach($_POST as $k => $v) { $valu.= $k.' / '.$v.', '; } $txn_id_check = mysql_query("SELECT `txn_id` FROM `log` WHERE `txn_id` = '".$txn_id."'"); if (mysql_num_rows($txn_id_check) !=1) { if ($receiver_email == $receiver) { if (isset($prices[$mcGross]) && $mcCurrency == $currency) { $data = date("U"); // Process payment // add txn_id to database // Add a column to hold the $valu var info $log_query = mysql_query("INSERT INTO `paypal_log` VALUES ('', '".$user_id."', '".$txn_id."', '".$payer_email."', '".$valu."', '".$data."') "); $data = mysql_select_single("SELECT `bonus` AS `old_bonus` FROM `accounts` WHERE `id` = '".$user_id."';"); $new_points = $data['old_bonus'] + $prices[$mcGross]; $update_bobus = mysql_query("UPDATE `accounts` SET `bonus` = ".$new_points." WHERE `id` = '".$user_id."'"); } } } } } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation //$db->query("INSERT INTO `".PURCHASES."` SET `test` = 'not valid response'"); } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1520974 Share on other sites More sharing options...
secweb Posted September 17, 2015 Share Posted September 17, 2015 You're still using the session stuff, the IPN backend process will have a separate session, so all this will be in error So at the top of your code it looks like this: $account = $_SESSION["acc"]; if ($_SERVER['REQUEST_METHOD'] == "POST") { if ($account == "111111" || $account == "1") { $error='Dla bezpieczeństwa ten numer jest zablokowany!'; } elseif (empty($account)) { $error='Podaj Numer Konta!'; } elseif (!is_numeric($account)) { $error='Numer konta może składać się wyłącznie z cyfr!'; } if (empty($error)) {$query=mysql_query('SELECT * FROM accounts WHERE (id = '.$account.')'); if (mysql_num_rows($query) == 0) {$error= "Numer nie istnieje";} } $query2 = mysql_query("SELECT `bonus` FROM `accounts` WHERE (`id` = '$account') ") or die(mysql_error()); ... On my test server here if I try to access a non existent $_SESSION variable I get an error printed to screen,in your case that'll break the whole process because its sending output back to PayPal that it isn't expecting, so they won't then confirm it. $account = $_SESSION["acc"]; When I did this I made a new database table that I dumped feedback to, or in the PayPal example I believe they log to a file. Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1521015 Share on other sites More sharing options...
Smashden Posted September 17, 2015 Author Share Posted September 17, 2015 Thanks for answer. I changed some piece of code and again not working. Can you tell me why I can't find ipn.log in my server(tested on VPS)? <b>PayPal Shop System.</b><br><br> <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="email"> <input type="hidden" name="lc" value="US"> <b>Account number: </b> <font color="black"><?php echo $_SESSION["acc"]; ?></font></br> <select id="item_name" name="item_name" style="width:256px; height:32px;"></select> <input id="amount" name="amount" type="hidden" value=""> <script> var items = [ { name: "1000 PP", amount: 5.00 }, { name: "2500 PP", amount: 10.00 }, { name: "6000 PP", amount: 20.00 } ]; var itemNameElement = document.getElementById("item_name"); itemNameElement.onchange = (function(){ var amount = items[this.selectedIndex].amount; document.getElementById("amount").value = amount; }).bind(itemNameElement); document.getElementById("amount").value = items[0].amount; for(var i=0; i<items.length; i++){ var item = document.createElement("option"); item.value = items[i].name; item.text = items[i].name+" - "+items[i].amount+" EUR"; itemNameElement.add(item); } </script> <input type="hidden" name="button_subtype" value="products"> <input type="hidden" name="no_shipping" value="1"> <input type="hidden" name="no_note" value="1"> <input type="hidden" name="currency_code" value="EUR"> <input type="hidden" name="rm" value="2"> <input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynowCC_LG.gif:NonHostedGuest"> <input type="hidden" name="return" value="http://site/sms_shop/"> <input type="hidden" name="cancel_return" value="http://site/sms_shop/"> <input type="hidden" name="notify_url" value="http://site/sms_shop/shop/ipn-test.php" /> <input type="hidden" name="custom" value='<?php echo $_SESSION["acc"]; ?>'> <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"> <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"> </form> <?php baza(); ob_start(); // CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory. // Especially useful if you encounter network errors or other intermittent problems with IPN (validation). // Set this to 0 once you go live or don't require logging. define("DEBUG", 1); // Set to 0 once you're ready to go live define("USE_SANDBOX", 1); define("LOG_FILE", "./ipn.log"); // Read POST data //reading raw POST data from input stream. reading pot data from $_POST may cause serialization issues since POST data may contain arrays $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $myPost[$keyval[0]] = urldecode($keyval[1]); } // read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; if(function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exits = true; } foreach ($myPost as $key => $value) { if($get_magic_quotes_exits == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } // Post IPN data back to PayPal to validate the IPN data is genuine // Without this step anyone can fake IPN data if(USE_SANDBOX == true) { $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"; } else { $paypal_url = "https://www.paypal.com/cgi-bin/webscr"; } $ch = curl_init($paypal_url); if ($ch == FALSE) { return FALSE; } curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); if(DEBUG == true) { curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLINFO_HEADER_OUT, 1); } // CONFIG: Optional proxy configuration //curl_setopt($ch, CURLOPT_PROXY, $proxy); //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); // Set TCP timeout to 30 seconds curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); // CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path // of the certificate as shown below. Ensure the file is readable by the webserver. // This is mandatory for some environments. //$cert = __DIR__ . "./cacert.pem"; //curl_setopt($ch, CURLOPT_CAINFO, $cert); $res = curl_exec($ch); if (curl_errno($ch) != 0) // cURL error { if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE); } curl_close($ch); exit; } else { // Log the entire HTTP response if debug is switched on. if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE); error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE); } curl_close($ch); } // Inspect IPN validation result and act accordingly // Split response headers and payload, a better way for strcmp $tokens = explode("\r\n\r\n", trim($res)); $res = trim(end($tokens)); if (strcmp($res, "VERIFIED") == 0) { // check whether the payment_status is Completed // check that txn_id has not been previously processed // check that receiver_email is your PayPal email // check that payment_amount/payment_currency are correct // process payment and mark item as paid. // assign posted variables to local variables $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $payment_status = $_POST['payment_status']; $mcGross = $_POST['mc_gross']; $mcCurrency = $_POST['currency_code']; $currency = 'EUR'; $txn_id = $_POST['txn_id']; $receiver_email = $_POST['receiver_email']; $receiver = 'email'; $payer_email = $_POST['payer_email']; $user_id = $_POST['custom']; $prices = array('5.00' => 1000, '10.00' => 2500, '20.00' => 6000); if ($payment_status == 'Completed') { $txn_id_check = mysql_query("SELECT `txn_id` FROM `paypal_log` WHERE `txn_id` = '".$txn_id."'"); if (mysql_num_rows($txn_id_check) !=1) { if ($receiver_email == $receiver) { if (isset($prices[$mcGross]) && $mcCurrency == $currency) { // Process payment // add txn_id to database $data = date("U"); /* CREATE TABLE `paypal_log` ( `id` int(10) NOT NULL auto_increment, `account` int(15) NOT NULL, `email` varchar(20) NOT NULL, `prices` int(15) NOT NULL, `txn_id` varchar(20) NOT NULL, `data` timestamp NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; */ $log_query = mysql_query("INSERT INTO `paypal_log` VALUES ('', '".$user_id."', '".$payer_email."'', '".$prices[$mcGross]."', '".$txn_id."', '".$data."') "); // add points to user $data = mysql_result(mysql_query("SELECT `bonus` AS `old_bonus` FROM `accounts` WHERE `id` = '".$user_id."' LIMIT 1"),0); $new_points = $data['old_bonus'] + $prices[$mcGross]; $update_bonus = mysql_query("UPDATE `accounts` SET `bonus` = ".$new_points." WHERE `id` = '".$user_id."'"); } } } } if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE); } } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation // Add business logic here which deals with invalid IPN messages if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE); } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1521021 Share on other sites More sharing options...
mac_gyver Posted September 17, 2015 Share Posted September 17, 2015 for debugging purposes, you can make a test page with a form that submits some dummy post data to your ipn.php script so that you can SEE what your script is doing. you would also temporarily set php's error_reporting to E_ALL and display_errors to ON in your ipn.php code. doing this will run your code and let you see any php errors (i suspect you may have a permission problem with the log file) and let you see if the curl statements are producing errors. this will at least get you to the point of having an "INVALID" response back from paypal and getting the error logging to work, since the dummy post data won't match a real transaction. you can also use this test method and 'fake' a "VERIFIED" response in your logic to let you test and debug your database code. Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1521032 Share on other sites More sharing options...
Smashden Posted September 17, 2015 Author Share Posted September 17, 2015 I have many problems with add this to site but finally I do it Thanks secweb and mac gyver. Quote Link to comment https://forums.phpfreaks.com/topic/298191-paypal-ipn-script-not-updating-database/#findComment-1521043 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.