为什么我的paypal ipn验证总是返回INVALID


Why do my paypal ipn validations always return INVALID?

我使用的是一个PHP类,它是我根据贝宝网站上的示例代码创建的。我也在CodeIgniter中使用这个。我用IPN模拟器测试了IPN监听器。我的电子邮件已经发送,所以我知道它正在被访问。问题是,我总是得到INVALID的回复,我不知道为什么。这是我第一次将PayPal集成到我的一个网站中。是什么原因导致了这个问题?

这是我的课:

<?php
class Paypal {
    public $sandbox = false;
    private $_url;
    public $verified = false;
    public $fields = array();
    public $post_fields = array();
    public $result;
    public function __construct($params = array()){
        $this->sandbox = (isset($params['sandbox'])) ? $params['sandbox'] : false;
        $this->_url = ($this->sandbox) ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
    }
    public function run(){
        $this->verified = false;
        // STEP 1: read POST data
        // Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
        // Instead, read raw POST data from the input stream.
        $raw_post_data = file_get_contents('php://input');
        $raw_post_array = explode('&', $raw_post_data);
        foreach ($raw_post_array as $keyval) {
          $keyval = explode ('=', $keyval);
          if (count($keyval) == 2)
            $this->post_fields[$keyval[0]] = urldecode($keyval[1]);
        }
        // read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
        $req = 'cmd=_notify-validate';
        if (function_exists('get_magic_quotes_gpc')) {
          $get_magic_quotes_exists = true;
        }
        foreach ($this->post_fields 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";
        }
        // Step 2: POST IPN data back to PayPal to validate
        $ch = curl_init($this->_url);
        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);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
        // In wamp-like environments that do not come bundled with root authority certificates,
        // please 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, FCPATH.'cacert.pem');
        if ( !($res = curl_exec($ch)) ) {
          // error_log("Got " . curl_error($ch) . " when processing IPN data");
          curl_close($ch);
          die('curl did not work<br>'.FCPATH.'cacert.pem');
        }
        curl_close($ch);
        if (strcmp ($res, "VERIFIED") == 0) {
            $this->verified = true;            
        }
        $this->result = $res;
    }

这是我的CI控制器:

function paypalipn(){
        $this->load->model('subscription');
        $this->load->library('paypal', array('sandbox' => true));;
        $this->paypal->run();
        $fields = $this->paypal->post_fields;
        if($this->paypal->verified){
            $data = array(
                'user_id' => $fields['buyer_id'],
                'txn_id' => $fields['txn_id'],
                'payment_gross' => $fields['mc_gross'],
                'currency_code' => $fields['mc_currency'],
                'payer_email' => $fields['payer_email'],
                'plan_id' => $fields['item_number'],
                'payment_status' => $fields['payment_status']
            );
            $this->subscription->create_payment($data);
        }
        $this->load->library('email');
        $this->email->to('*******@gmail.com');
        $this->email->from('**************');
        $this->email->subject('PayPal IPN');
        $this->email->message($this->paypal->result."'nAmount: ".$fields['mc_gross']."'nCurrency: ".$fields['mc_currency']."'nUser ID: ".$fields['buyer_id']);
        $this->email->send();
    }

电子邮件中的所有字段都为空,$this->paypal->result总是返回"INVALID"。有人有什么想法吗?谢谢你抽出时间。

在您的CI控制器中,如果您编写了这样的代码:

function paypalipn(){
        $this->load->model('subscription');
        $this->load->library('paypal', array('sandbox' => true));;
        $this->paypal->run();
        $fields = $this->paypal->post_fields;
        if($this->paypal->verified){
            $data = array(
                'user_id' => $fields['buyer_id'],
                'txn_id' => $fields['txn_id'],
                'payment_gross' => $fields['mc_gross'],
                'currency_code' => $fields['mc_currency'],
                'payer_email' => $fields['payer_email'],
                'plan_id' => $fields['item_number'],
                'payment_status' => $fields['payment_status']
            );
            $this->subscription->create_payment($data);
        $this->load->library('email');
        $this->email->to('*******@gmail.com');
        $this->email->from('**************');
        $this->email->subject('PayPal IPN');
        $this->email->message($this->paypal->result."'nAmount: ".$fields['mc_gross']."'nCurrency: ".$fields['mc_currency']."'nUser ID: ".$fields['buyer_id']);
        $this->email->send();
        }
    } 

或者,如果if语句在失败的情况下停止了脚本

if($this->paypal->verified){
            $data = array(
                'user_id' => $fields['buyer_id'],
                'txn_id' => $fields['txn_id'],
                'payment_gross' => $fields['mc_gross'],
                'currency_code' => $fields['mc_currency'],
                'payer_email' => $fields['payer_email'],
                'plan_id' => $fields['item_number'],
                'payment_status' => $fields['payment_status']
            );
            $this->subscription->create_payment($data);
} else {
exit("We are sad to inform you that verification FAILED. Bye!");
}

你不会收到任何电子邮件。这个问题在你的贝宝类的public function run()中,这很可能是失败的部分。

       if ( !($res = curl_exec($ch)) ) {
          curl_close($ch);
          die('curl did not work<br>'.FCPATH.'cacert.pem');
        }
        curl_close($ch);
       if (strcmp ($res, "VERIFIED") == 0) {   
            $this->verified = true;                
        }

试着像这个一样重写

       $res=curl_exec($ch); // define $res
       if($res==null){  // check if $res is null
            exit('curl did not work<br>'.FCPATH.'cacert.pem');
        }
       curl_close($ch);
       if (strcmp ($res, "VERIFIED") === 0) {   
            $this->verified = true;                
       }

关于使用strcmp()的最后3行,并基于strcmp()文档中的用户注释。

  • strcmp()失败时将返回NULL
  • 当使用相等比较(==)时,这会产生等同于匹配的副作用
  • 相反,您可能希望使用相同的比较(==)来测试匹配,这不应该捕获NULL返回

以上是什么意思?举个小例子。

if(null==0) {
echo "1";
}
if(null===0) {
echo "2";
}

上面的示例将只输出=>1,在您的情况下,这意味着如果strcmp()失败,您将把verified设置为true,这是不正确的。