Reputation: 37
As title says I don't understand how to use IPN.
This page https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/ says that I need to implement my IPN Listener and they provide samples. This is the sample for PHP:
IPN.php
<?php
class PaypalIPN
{
/** @var bool Indicates if the sandbox endpoint is used. */
private $use_sandbox = false;
/** @var bool Indicates if the local certificates are used. */
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* @return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* @return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
*
* @return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* @return bool
* @throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$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) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
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_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
}
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'User-Agent: PHP-IPN-Verification-Script',
'Connection: Close',
));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
?>
And they also provide an example:
Example.php
<?php
namespace Listener;
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
?>
I'm going to have Paypal buttons on my page to let users pay for a subscription based software (1/3/6/12 months). (They don't subscribe, they only pay the money needed for 1/3/6/12 months). I need to automate the process where I update the subscription expiration date on my DB after I get the payment.
I want to clarify that I already read what's on paypal guide but I got lost with so much information.
Upvotes: 0
Views: 763
Reputation: 2638
1) The code you have displayed is defining a class, so you can initiate an connection-instance, where you define different variables. So you shouldn't change that. You should upload it to your server and use it accordingly.
2) Ehm... That is a broad question. Like... Is a chain mail safe? Safe for people attacking you with a sword: Yes. Safe for people dropping nukes on you: No. And it also depends on how you use the chain mail.
But if I should try and answer the question that I think you're asking:
The script makes a safe connection to PayPal, yes. So you need to ensure, in the solution that you're making, that the script and your API-key is not stolen/abused; so people could access PayPal through your solution, doing stuff that you don't want them to do.
3) According to the documentation that you linked to, then:
When you have completed your listener, push it to your site and specify the listener URL or notification URL in your account settings. See IPN Setup for more information.
... I must admit that I haven't used this before. But it looks like here that is a way to pass notifications between your website and Paypal. So I assume that it's a path, that Paypal checks to get notifications, that will be displayed, ehm... somewhere(?). Sorry for the vague answer on this point.
4) My tip would be, to see if there are a solution (framework or something) that has the integration already. I think I would use Laravel or WordPress, if it was me, - but that's only because that is the tools the I'm confident using. But the both come with solutions (Laravel and WordPress) that are being maintained by people who (hopefully) know what they're doing. So that if PayPal comes out with a new API, deprecating the one you're using now, - that you don't necessarily have to start back at the documentation again. But getting to know a framework takes quite a bit of time (just a heads up).
However, - it all comes down to what you're trying to make. So the TL;DR-version of this fourth point: Use a framework.
Upvotes: 2