Why am I not seeing HTTP responses for IPN?

rightway77
Contributor
Contributor

I hope someone can help guide me on this.  I've had IPNs working for years with Paypal and suddenly they just stopped working one day.  MY IPNs are enabled and my URL endpoint has not changed.  It is using SSL.  I'm using the PHP examples I found on GitHub but they're no longer working.  Here is my code.  If you have any ideas please let me know.  It's driving me bananas.  I have IPNs from other processors working fine.

<?php

	error_reporting(E_ALL);
	date_default_timezone_set('America/New_York');
	$today = date("H:i:s M d, Y");
	
function writeToLog($text) {
	$handle = fopen('log_paypal.txt', 'a');
	if ($handle) {
		$logData = "\n\n----[" . date('Y-m-d') . ' ' . date('H:i:s') . "]-------------\n";
		$logData .= $text;
		fwrite($handle, $logData);
	}
}
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');

# If you have an initial trial period set it here. For example one 
# month would be '1 M'
$PER1 = ''; 

# If you have a second trial period set it here. For example one 
# month would be '1 M'
$PER2 = ''; 

# Set this to your recurring or normal period. For example one 
# month would be '1 M'
$PER3 = '1 Y'; 

# Set this to the dollar amount for your initial trial period. For
# example a free trial would be '0.00'
$AMT1 = ''; 

# Set this to the dollar amount for your second trial period. For
# example a $1.00 trial would be '1.00'
$AMT2 = ''; 

# Set this to the dollar amount for your recurring or normal period. 
# For example $1.00 would be '1.00'
$AMT3 = '1.99';

include('paypal_ipn.php');
$listener = new PaypalIPN();

try {
    $listener->requirePostMethod();
	$verified = $listener->verifyIPN();
    //$verified = $listener->processIpn();
} catch (Exception $e) {
    error_log($e->getMessage());
    exit(0);
}

if ($verified) {
$status = $_POST['payment_status'];
$amount = $_POST['payment_gross'];
$txn = $_POST['txn_type'];
$email = $_POST['payer_email'];
$id = $_POST['subscr_id'];
$reason = $_POST['pending_reason'];
$paydate = $_POST['payment_date'];

}

 

And here is paypal_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 = false;

    /** 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 = false;
    }

    /**
     * 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 ( ! (trim($res=="VERIFIED"))) {
            $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");
			error_log("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;
        }
    }
	
	    public function requirePostMethod() {
        // require POST requests
        if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
            header('Allow: POST', true, 405);
            throw new Exception("Invalid HTTP request method.");
        }
    }
}

 

Login to Me Too
2 REPLIES 2

rightway77
Contributor
Contributor

this is what I see in IPNs

romeo18302_1-1701828421897.png

 

 

 

Login to Me Too

Kavyar
Moderator
Moderator

Good day @rightway77 

 

Thank you for posting to the PayPal community.

 

PayPal system will send the IPN response logs to the specific IPN endpoint URL which merchant passed in their website API request call.

 

If your(merchant) IPN listener server fails to return HTTP 200 OK response to PayPal POST, system will retry sending the IPN details for 16 times by auto alerting the merchant via email.

 

Please refer the detailed guide link to resolve the issue:

 

https://developer.paypal.com/docs/api-basics/notifications/ipn/IPNTesting/?mark=ipn%20trou#ipn-troub...

 

If you notice many Failed or Retrying entries, it is likely that the reason behind the delay in IPN failure to send HTTP 200 OK responses. To resolve this issue, you should review your server logs to identify why the required HTTP 200 OK responses are not being sent and fix your listener accordingly. Once your listener starts sending the required HTTP 200 OK responses, PayPal will post IPNs from the faster-cycling server.

 

If you are still experiencing issues, please create an MTS ticket via the following URL - https://www.paypal-support.com/s/?language=en_US . Please ensure that you provide detailed information and error details when submitting the ticket.

 

Sincerely,

Kavya

PayPal MTS

 

If this post or any other was helpful, please enrich the community by giving kudos or accepting it as a solution.

Login to Me Too

Haven't Found your Answer?

It happens. Hit the "Login to Ask the community" button to create a question for the PayPal community.