PayPal IPN 问题,但在沙盒中工作正常 [英] PayPal IPN Issue, but works in Sandbox fine

查看:26
本文介绍了PayPal IPN 问题,但在沙盒中工作正常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 GitHub 上的代码:https://github.com/Quixotix/PHP-贝宝-IPN

好的,所以,我有一个像这样的 php 页面,我将它用作我的 ipnlistener,用于变量内 url 的 sa=paypal_verify 部分,在按钮创建的第 3 步中,如下所示:

notify_url=http://mydomain.com/index.php?page=paypaltest;sa=paypal_verifyreturn=http://mydomain.com/index.php?page=paypaltest;sa=thankyourm=2

这是链接到 http://mydomain.com/index.php?page= 的代码贝宝测试

if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] != 'thankyou'){//需要用于加载全局变量等的文件.可能不需要,但只是在这里以防万一.require_once('/public_html/Settings.php');全局 $smcFunc, $context, $scripturl, $boarddir, $modSettings, $txt;如果($_REQUEST['sa'] == 'paypal_verify'){ini_set('log_errors', true);ini_set('error_log', '/ipn_errors.log');//这里是定义实际 IpnListener 类的地方//并使用 cURL 或 fSocket 回发到 paypal.require_once($boarddir .'/ipn/ipnlistener.php');$listener = new IpnListener();尝试 {$listener->requirePostMethod();$verified = $listener->processIpn();} 捕获(异常 $e){error_log($e->getMessage());退出(0);}/*如果 IPN 为已验证",则 processIpn() 方法返回 true;如果 IPN 为已验证",则返回 false是无效".*/如果($已验证){$errmsg = '';//存储欺诈检查的错误//1. 确保付款状态为已完成"if ($_POST['payment_status'] != 'Completed') {//简单地忽略任何未完成的 IPN退出(0);}//此处(排除)中的数据库查询,根据来自 paypal 的 $_POST['item_name'] 从数据库中选择sellers_email、product_name 和 price 以进行实际购买.//如果数据库表中的返回结果为 0,则执行以下操作:$errmsg .= "在数据库中未找到产品:";$errmsg .= $_POST['item_name']."
";//手动调查欺诈检查中的错误$body = "IPN 欺诈检查失败:
$errmsg

";$body .= $listener->getTextReport();mail('myemail@address.com', 'IPN 欺诈警告', $body);退出(0);//从数据库表中设置 $sellers_email、$item_name 和 $price 变量.然后释放 mysql 结果.//2. 确保卖家电子邮件与您的主要帐户电子邮件匹配.如果 ($_POST['receiver_email'] != $sellers_email) {$errmsg .= "'receiver_email' 不匹配:";$errmsg .= $_POST['receiver_email']."
";}//3. 确保支付的金额匹配如果 ($_POST['mc_gross'] != $price) {$errmsg .= "'mc_gross' 不匹配:";$errmsg .= $_POST['mc_gross']."
";}//4. 确保货币代码匹配如果 ($_POST['mc_currency'] != 'USD') {$errmsg .= "'mc_currency' 不匹配:";$errmsg .= $_POST['mc_currency']."
";}//5. 确保事务不是重复的.//尝试从它去的表中获取一个事务 ID.该列是 id_txn,如果存在$errmsg .= "'txn_id' 已经被处理:".$_POST['txn_id']."
";//释放数据库结果.//将 $txn_id 从 paypal 设置为 $txn_id 变量.$txn_id = (string) $_POST['txn_id'];如果 (!empty($errmsg)) {//手动调查欺诈检查中的错误$body = "IPN 欺诈检查失败:
$errmsg

";$body .= $listener->getTextReport();mail('myemail@address.com', 'IPN 欺诈警告', $body);} 别的 {//发送电子邮件给买家.//为了确定,将它们发送到 sa=thankyou 页面!}} 别的 {//向 self 发送包含列出的错误的电子邮件}}}if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'thankyou')回声'<div class="信息">感谢您购买本产品.我们向您发送了一封电子邮件,其中包含您的详细信息和下载此软件的链接.<br/>';回声'<div class="cat_bar boardframe"><h3 class="catbg">贝宝测试销售

<div class="roundframe blockframe">这只是一个测试销售页面,以确保 PayPal 电子下载确实有效!

<span class="lowerframe"><span><!--//--></span></span><br/><div class="cat_bar boardframe"><h3 class="catbg">以 0.01 美元购买

<div class="roundframe blockframe"><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"><input type="hidden" name="cmd" value="_s-xclick"><input type="hidden" name="hosted_button_id" value="FJAGXAC7GCFSY"><input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_paynow_SM.gif" border="0" name="submit" alt="PayPal - 更安全、更简单网上支付方式!"样式=边框:无;背景:无;"><img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"></表单>

<span class="lowerframe"><span><!--//--></span></span><br class="clear"/>';

ipnlistener.php 文件中包含以下代码:

class IpnListener {/*** 如果为 true,则使用推荐的 cURL PHP 库将帖子发回* 到贝宝.如果 flase 则使用 fsockopen().默认为真.** @var 布尔值*/公共 $use_curl = true;/*** 如果为 true,则显式设置 cURL 以使用 SSL 版本 3.如果 cURL 使用此选项* 使用 GnuTLS SSL 编译.** @var 布尔值*/公共 $force_ssl_v3 = 真;/*** 如果为 true,cURL 将使用 CURLOPT_FOLLOWLOCATION 来跟随任何* "Location: ..." 响应中的标头.** @var 布尔值*/公共 $follow_location = false;/*** 如果为 true,则使用 SSL 安全连接(端口 443)进行回发* 由 PayPal 推荐.如果为 false,则为标准 HTTP(端口 80)连接*  用来.默认为真.** @var 布尔值*/公共 $use_ssl = true;/*** 如果为真,paypal 沙盒 URI www.sandbox.paypal.com 用于* 回贴.如果为 false,则使用实时 URI www.paypal.com.默认为假.** @var 布尔值*/公共 $use_sandbox = false;/*** 等待 PayPal 服务器响应的时间,以秒为单位* 超时前.默认 30 秒.** @var int*/公共 $timeout = 30;私人 $post_data = array();私人 $post_uri = '';私人 $response_status = '';私人 $response = '';const PAYPAL_HOST = 'www.paypal.com';const SANDBOX_HOST = 'www.sandbox.paypal.com';/*** 使用 cURL 回传** 使用 cURL 库将帖子发送回 PayPal.调用者* processIpn() 方法,如果 use_curl 属性为真.抛出一个* 如果帖子失败,则例外.填充响应,response_status,* 和 post_uri 属性成功.** @param string 帖子数据为 URL 编码字符串*/受保护的函数 curlPost($encoded_data) {如果 ($this->use_ssl) {$uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';$this->post_uri = $uri;} 别的 {$uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr';$this->post_uri = $uri;}$ch = curl_init();curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);curl_setopt($ch, CURLOPT_CAINFO,目录名(__FILE__)."/cert/api_cert_chain.crt");curl_setopt($ch, CURLOPT_URL, $uri);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HEADER, true);如果 ($this->force_ssl_v3) {curl_setopt($ch, CURLOPT_SSLVERSION, 3);}$this->response = curl_exec($ch);$this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));if ($this->response === false || $this->response_status == '0') {$errno = curl_errno($ch);$errstr = curl_error($ch);throw new Exception("cURL 错误:[$errno] $errstr");}}/*** 使用 fsockopen() 回发*/受保护的函数 fsockPost($encoded_data) {如果 ($this->use_ssl) {$uri = 'ssl://'.$this->getPaypalHost();$端口 = '443';$this->post_uri = $uri.'/cgi-bin/webscr';} 别的 {$uri = $this->getPaypalHost();//调用 fsockopen() 时没有http://"$端口 = '80';$this->post_uri = 'http://'.$uri.'/cgi-bin/webscr';}$fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);如果 (!$fp) {//fsockopen 错误throw new Exception("fsockopen 错误:[$errno] $errstr");}$header = "POST/cgi-bin/webscr HTTP/1.1
";$header .= "主机:".$this->getPaypalHost()."
";$header .= "内容类型:应用程序/x-www-form-urlencoded
";$header .= "内容长度:".strlen($encoded_data)."
";$header .= "连接:关闭

";fputs($fp, $header.$encoded_data."

");while(!feof($fp)) {如果(空($this->响应)){//从第一行提取 HTTP 状态$this->response .= $status = fgets($fp, 1024);$this->response_status = trim(substr($status, 9, 4));} 别的 {$this->response .= fgets($fp, 1024);}}fclose($fp);}私有函数 getPaypalHost() {if ($this->use_sandbox) 返回 self::SANDBOX_HOST;否则返回 self::PAYPAL_HOST;}/*** 获取 POST URI*/公共函数 getPostUri() {返回 $this->post_uri;}/*** 得到回应** 以字符串形式返回来自 PayPal 的整个响应,包括所有* HTTP 标头.** @return 字符串*/公共函数 getResponse() {返回 $this->response;}/*** 如果成功,获取响应状态 200*/公共函数 getResponseStatus() {返回 $this->response_status;}/*** 获取文本报告*/公共函数 getTextReport() {$r = '';//日期和POST urlfor ($i=0; $i<80; $i++) { $r .= '-';}$r .= "
[".date('m/d/Y g:i A').'] - '.$this->getPostUri();if ($this->use_curl) $r .= " (curl)
";否则 $r .= " (fsockopen)
";//HTTP 响应for ($i=0; $i<80; $i++) { $r .= '-';}$r .= "
{$this->getResponse()}
";//POST 变量for ($i=0; $i<80; $i++) { $r .= '-';}$r .= "
";foreach ($this->post_data as $key => $value) {$r .= str_pad($key, 25)."$value
";}$r .= "

";返回 $r;}/*** 处理IPN** 处理发回 PayPal 的 IPN 并解析响应.叫这个* 来自您的 IPN 侦听器脚本的方法.如果响应到来则返回真* 返回已验证",如果响应返回无效",则返回 false,以及* 如果有错误,则抛出异常.** @param 数组** @return 布尔值*/公共函数 processIpn($post_data=null) {$encoded_data = 'cmd=_notify-validate';如果($post_data === null){如果(!空($_POST)){$this->post_data = $_POST;$encoded_data .= '&'.file_get_contents('php://input');} 别的 {throw new Exception("未找到 POST 数据.");}} 别的 {$this->post_data = $post_data;foreach ($this->post_data as $key => $value) {$encoded_data .= "&$key=".urlencode($value);}}if ($this->use_curl) $this->curlPost($encoded_data);否则 $this->fsockPost($encoded_data);如果 (strpos($this->response_status, '200') === false) {throw new Exception("无效的响应状态:".$this->response_status);}如果 (strpos($this->response, "VERIFIED") !== false) {返回真;} elseif (strpos($this->response, "INVALID") !== false) {返回假;} 别的 {throw new Exception("来自 PayPal 的意外响应.");}}公共函数 requirePostMethod() {//需要 POST 请求如果 ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {header('允许:POST', true, 405);throw new Exception("无效的 HTTP 请求方法.");}}}

error_log 中没有记录错误(这个文件实际上是在发生错误时创建的,所以它甚至不存在).它从不向数据库中添加任何内容.我知道 item_name 在 PayPal 服务器上是正确的,并且在数据库表中也应该匹配.

ipnlistener 似乎有问题,或者它是如何链接到它的?或者从中返回什么?

有什么方法可以准确地从 ipnlistener.php 文件中测试返回值?这样我才能真正看到它?也许我什至可以看到发送到以​​下网址的内容(来自 Paypal):http://mydomain.com/index.php?page=paypaltest;sa=paypal_verify

我正在尝试能够跟踪此情况,以便我可以确切地找出问题所在......有什么想法吗?

也许与 cURL 中的这一行有关:

curl_setopt($ch, CURLOPT_CAINFO,目录名(__FILE__)."/cert/api_cert_chain.crt");

我从未听说过在服务器的实际文件结构中附加 SSL 证书.

另外,它可能是可能的,因为它在 notify_url 中有 index.php ,它正在添加额外的标题.如果是这样,我可以在它从 PayPal 获取编码数据并将其返回给 Paypal 进行验证之前以某种方式从文件中清除所有内容吗?这样,它肯定与 PayPal 将其发送到 notify_url 时完全相同.

我不明白为什么这必须如此复杂!我已经连续 7 天在这上面拔头发了,几乎没有睡觉!

我知道:在我的服务器上启用了 cURL.如果我浏览到实际的 notify_url 页面,它是空白的(就像一个完全空白的页面),我认为这是正确的.查看通知历史记录时,显示已发送,HTTP 响应代码为 200.

这个我不知道:它在哪里失败了?PayPal 通知究竟在哪里失败?为什么它不接触我的数据库?我在任何地方都没有错误...

解决方案

发现问题了,天哪,出在认证文件里:

只是更改了以下内容:

curl_setopt($ch, CURLOPT_CAINFO,目录名(__FILE__)."/cert/api_cert_chain.crt");

到我服务器上从/home/开始的实际文件路径

curl_setopt($ch, CURLOPT_CAINFO, "完整文件路径/cert/api_cert_chain.crt");

天哪,我傻了!现在完美运行!耶耶!

Using the code located on GitHub here: https://github.com/Quixotix/PHP-PayPal-IPN

Ok, so, I have a php page like so which I am using as my ipnlistener for the sa=paypal_verify part of the url within variables, in Step 3 of button creation like so:

notify_url=http://mydomain.com/index.php?page=paypaltest;sa=paypal_verify
return=http://mydomain.com/index.php?page=paypaltest;sa=thankyou
rm=2

Here is the code linking to http://mydomain.com/index.php?page=paypaltest

if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] != 'thankyou')
{
        // Require file for loading up global variables, etc.  Might not be needed, but just in here in case.
    require_once('/public_html/Settings.php');

    global $smcFunc, $context, $scripturl, $boarddir, $modSettings, $txt;

    if ($_REQUEST['sa'] == 'paypal_verify')
    {
        ini_set('log_errors', true);
        ini_set('error_log', '/ipn_errors.log');

        // Here is where the actual IpnListener Class is defined
        // and uses cURL or fSocket to post back to paypal.
        require_once($boarddir . '/ipn/ipnlistener.php');
        $listener = new IpnListener();

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


        /*
        The processIpn() method returned true if the IPN was "VERIFIED" and false if it
        was "INVALID".
        */
        if ($verified) {
            $errmsg = '';   // stores errors from fraud checks

            // 1. Make sure the payment status is "Completed" 
            if ($_POST['payment_status'] != 'Completed') { 
                // simply ignore any IPN that is not completed
                exit(0); 
            }

            // Database Query in here (excluded) that selects sellers_email, product_name, and price from within the database for the actual purchase, based on the $_POST['item_name'] from paypal.

            // If return results are 0 from database table than do following:
                $errmsg .= "Product Not Found in the database: ";
                $errmsg .= $_POST['item_name']."
";
                // manually investigate errors from the fraud checking
                $body = "IPN failed fraud checks: 
$errmsg

";
                $body .= $listener->getTextReport();
                mail('myemail@address.com', 'IPN Fraud Warning', $body);
                exit(0);

            // Set $sellers_email, $item_name, and $price variables from the database table.  And than free the mysql result.


            // 2. Make sure seller email matches your primary account email.
            if ($_POST['receiver_email'] != $sellers_email) {
                $errmsg .= "'receiver_email' does not match: ";
                $errmsg .= $_POST['receiver_email']."
";
            }

            // 3. Make sure the amount(s) paid match
            if ($_POST['mc_gross'] != $price) {
                $errmsg .= "'mc_gross' does not match: ";
                $errmsg .= $_POST['mc_gross']."
";
            }

            // 4. Make sure the currency code matches
            if ($_POST['mc_currency'] != 'USD') {
                $errmsg .= "'mc_currency' does not match: ";
                $errmsg .= $_POST['mc_currency']."
";
            }

            // 5. Ensure the transaction is not a duplicate.
            // Attempt to grab a transaction id from the table where it goes.  The column is id_txn, if it exists
                $errmsg .= "'txn_id' has already been processed: ".$_POST['txn_id']."
";

            // free database result.

            // Set $txn_id from paypal to the $txn_id variable.
            $txn_id = (string) $_POST['txn_id'];

            if (!empty($errmsg)) {

                // manually investigate errors from the fraud checking
                $body = "IPN failed fraud checks: 
$errmsg

";
                $body .= $listener->getTextReport();
                mail('myemail@address.com', 'IPN Fraud Warning', $body);

            } else {

                // send email to buyer.
                // and just to be sure, send them to the sa=thankyou page!
            }
        } else {
            // send email to self with the errors listed
        }
    }
}

if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'thankyou')
    echo '
    <div class="information">Thank you for purchasing this product.  We sent you an email with your details and link to download this software.<br />';

echo '
<div class="cat_bar boardframe">
    <h3 class="catbg">
        PayPal Test Sale
    </h3>
</div>
<div class="roundframe blockframe">
This is just a Test Selling Page to be sure that the PayPal electronic downloads actually work!
</div>
<span class="lowerframe"><span><!-- // --></span></span>
<br />
<div class="cat_bar boardframe">
    <h3 class="catbg">
        Purchase at 0.01 USD
    </h3>
</div>
<div class="roundframe blockframe">
    <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
        <input type="hidden" name="cmd" value="_s-xclick">
        <input type="hidden" name="hosted_button_id" value="FJAGXAC7GCFSY">
        <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_paynow_SM.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" style="border: none; background: none;">
        <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
    </form>
</div>
<span class="lowerframe"><span><!-- // --></span></span>
<br class="clear" />';

The ipnlistener.php file has the following code in it:

class IpnListener {

    /**
     *  If true, the recommended cURL PHP library is used to send the post back 
     *  to PayPal. If flase then fsockopen() is used. Default true.
     *
     *  @var boolean
     */
    public $use_curl = true;

    /**
     *  If true, explicitly sets cURL to use SSL version 3. Use this if cURL
     *  is compiled with GnuTLS SSL.
     *
     *  @var boolean
     */
    public $force_ssl_v3 = true;     

    /**
     *  If true, cURL will use the CURLOPT_FOLLOWLOCATION to follow any 
     *  "Location: ..." headers in the response.
     *
     *  @var boolean
     */
    public $follow_location = false;     

    /**
     *  If true, an SSL secure connection (port 443) is used for the post back 
     *  as recommended by PayPal. If false, a standard HTTP (port 80) connection
     *  is used. Default true.
     *
     *  @var boolean
     */
    public $use_ssl = true;

    /**
     *  If true, the paypal sandbox URI www.sandbox.paypal.com is used for the
     *  post back. If false, the live URI www.paypal.com is used. Default false.
     *
     *  @var boolean
     */
    public $use_sandbox = false; 

    /**
     *  The amount of time, in seconds, to wait for the PayPal server to respond
     *  before timing out. Default 30 seconds.
     *
     *  @var int
     */
    public $timeout = 30;       

    private $post_data = array();
    private $post_uri = '';     
    private $response_status = '';
    private $response = '';

    const PAYPAL_HOST = 'www.paypal.com';
    const SANDBOX_HOST = 'www.sandbox.paypal.com';

    /**
     *  Post Back Using cURL
     *
     *  Sends the post back to PayPal using the cURL library. Called by
     *  the processIpn() method if the use_curl property is true. Throws an
     *  exception if the post fails. Populates the response, response_status,
     *  and post_uri properties on success.
     *
     *  @param  string  The post data as a URL encoded string
     */
    protected function curlPost($encoded_data) {

        if ($this->use_ssl) {
            $uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
            $this->post_uri = $uri;
        } else {
            $uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr';
            $this->post_uri = $uri;
        }

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_CAINFO, 
                    dirname(__FILE__)."/cert/api_cert_chain.crt");
        curl_setopt($ch, CURLOPT_URL, $uri);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);

        if ($this->force_ssl_v3) {
            curl_setopt($ch, CURLOPT_SSLVERSION, 3);
        }

        $this->response = curl_exec($ch);
        $this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));

        if ($this->response === false || $this->response_status == '0') {
            $errno = curl_errno($ch);
            $errstr = curl_error($ch);
            throw new Exception("cURL error: [$errno] $errstr");
        }
    }

    /**
     *  Post Back Using fsockopen()
     */
    protected function fsockPost($encoded_data) {

        if ($this->use_ssl) {
            $uri = 'ssl://'.$this->getPaypalHost();
            $port = '443';
            $this->post_uri = $uri.'/cgi-bin/webscr';
        } else {
            $uri = $this->getPaypalHost(); // no "http://" in call to fsockopen()
            $port = '80';
            $this->post_uri = 'http://'.$uri.'/cgi-bin/webscr';
        }

        $fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);

        if (!$fp) { 
            // fsockopen error
            throw new Exception("fsockopen error: [$errno] $errstr");
        } 

        $header = "POST /cgi-bin/webscr HTTP/1.1
";
        $header .= "Host: ".$this->getPaypalHost()."
";
        $header .= "Content-Type: application/x-www-form-urlencoded
";
        $header .= "Content-Length: ".strlen($encoded_data)."
";
        $header .= "Connection: Close

";

        fputs($fp, $header.$encoded_data."

");

        while(!feof($fp)) { 
            if (empty($this->response)) {
                // extract HTTP status from first line
                $this->response .= $status = fgets($fp, 1024); 
                $this->response_status = trim(substr($status, 9, 4));
            } else {
                $this->response .= fgets($fp, 1024); 
            }
        } 

        fclose($fp);
    }

    private function getPaypalHost() {
        if ($this->use_sandbox) return self::SANDBOX_HOST;
        else return self::PAYPAL_HOST;
    }

    /**
     *  Get POST URI
     */
    public function getPostUri() {
        return $this->post_uri;
    }

    /**
     *  Get Response
     *
     *  Returns the entire response from PayPal as a string including all the
     *  HTTP headers.
     *
     *  @return string
     */
    public function getResponse() {
        return $this->response;
    }

    /**
     *  Get Response Status 200 if Successful
     */
    public function getResponseStatus() {
        return $this->response_status;
    }

    /**
     *  Get Text Report
     */
    public function getTextReport() {

        $r = '';

        // date and POST url
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "
[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
        if ($this->use_curl) $r .= " (curl)
";
        else $r .= " (fsockopen)
";

        // HTTP Response
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "
{$this->getResponse()}
";

        // POST vars
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "
";

        foreach ($this->post_data as $key => $value) {
            $r .= str_pad($key, 25)."$value
";
        }
        $r .= "

";

        return $r;
    }

    /**
     *  Process IPN
     *
     *  Handles the IPN post back to PayPal and parsing the response. Call this
     *  method from your IPN listener script. Returns true if the response came
     *  back as "VERIFIED", false if the response came back "INVALID", and 
     *  throws an exception if there is an error.
     *
     *  @param array
     *
     *  @return boolean
     */    
    public function processIpn($post_data=null) {

        $encoded_data = 'cmd=_notify-validate';

        if ($post_data === null) {
            if (!empty($_POST)) {
                $this->post_data = $_POST;
                $encoded_data .= '&'.file_get_contents('php://input');
            } else {
                throw new Exception("No POST data found.");
            }
        } else {
            $this->post_data = $post_data;

            foreach ($this->post_data as $key => $value) {
                $encoded_data .= "&$key=".urlencode($value);
            }
        }

        if ($this->use_curl) $this->curlPost($encoded_data); 
        else $this->fsockPost($encoded_data);

        if (strpos($this->response_status, '200') === false) {
            throw new Exception("Invalid response status: ".$this->response_status);
        }

        if (strpos($this->response, "VERIFIED") !== false) {
            return true;
        } elseif (strpos($this->response, "INVALID") !== false) {
            return false;
        } else {
            throw new Exception("Unexpected response from PayPal.");
        }
    }

    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.");
        }
    }
}

There are no errors recorded in the error_log (this file actually gets created if an error occurs, so it doesn't even exist). And it never adds anything into the database. I know that the item_name is correct on the PayPal Server and should match in the database table as well.

Seems there is a problem with the ipnlistener or how it is linking to it? Or what is being returned from it?

Is there a way I can test the return value exactly from the ipnlistener.php file? So that I can actually see it? Maybe if I could even see what gets sent to the following url (from Paypal): http://mydomain.com/index.php?page=paypaltest;sa=paypal_verify

I'm trying to be able to track this so that I can figure out exactly where it is going wrong at... Any ideas?

Perhaps it has something to do with this line in the cURL:

curl_setopt($ch, CURLOPT_CAINFO, 
                    dirname(__FILE__)."/cert/api_cert_chain.crt");

I never heard tell of attaching an SSL Certificate within the actual file structure of a server.

Also, it might be possible, because it has index.php within the notify_url that it is adding additional headers. If so, can I somehow flush everything out of the file before it grabs the encoded data from PayPal and returns it back to paypal for verification? That way it's sure to be exactly the same as when PayPal sent it to the notify_url.

I don't understand why this has to be so damn complicated! I've been pulling out my hair now on this for 7 days straight with almost no sleep!

This I know: cURL is enabled on my server. If I browse to the actual notify_url page it is BLANK (Like a completely empty page), which I believe is correct. When viewing the Notification History, it says, Sent, and HTTP Response code is 200.

This I don't know: Where it is failing at? Where is the PayPal Notification failing at exactly? Why is it not touching my database? I get no errors anywhere...

解决方案

I found the problem, OMG, it was in the certification file:

Just changed the following:

curl_setopt($ch, CURLOPT_CAINFO, 
    dirname(__FILE__)."/cert/api_cert_chain.crt");

To the actual filepath on my server starting at /home/

curl_setopt($ch, CURLOPT_CAINFO, "FULL FILE PATH/cert/api_cert_chain.crt");

OMG I'm stupid! Works perfectly now! Yayyy!

这篇关于PayPal IPN 问题,但在沙盒中工作正常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆