CodeIgniter PaymentWall响应正文与预期的模式不匹配:确定

时间:2015-04-30 01:41:53

标签: php codeigniter design-patterns pingback

  

Pingback没有成功。原因:响应体不匹配   预期模式:好的

     

签名基本字符串   UID =货币=类型= 0ref = 369e67e903ca0b2261cd342575b8979e

     

签名= MD5(签名基本字符串)   2aa9f1c847d1492b18cd017cdf78290b

这是model.donate.php

<?php

in_file();

class Mdonate{
    protected $registry, $db, $config;
    private $vars = array();
    protected $hash_item = '';
    protected $paypal_ipn_url = 'https://www.paypal.com/cgi-bin/webscr';
    protected $paypal_ipn_url_ssl = 'www.paypal.com';
    protected $req = 'cmd=_notify-validate';
    protected $post = array();
    protected $paypal_response;
    public $order_details = array();
    protected $pw_ip_white_list = array('174.36.92.186', '66.220.10.3', '174.36.92.186', '174.36.96.66', '174.36.92.187', '174.36.92.192', '174.37.14.28');
    protected $pw_reason_list = array(0     => 'Invalid Reason',
                                      1     => 'Chargeback',
                                      2     => 'Credit Card fraud',
                                      3     => 'Order fraud',
                                      4     => 'Bad data entry',
                                      5     => 'Fake / proxy user',
                                      6     => 'Rejected by advertiser',
                                      7     => 'Duplicate conversions',
                                      8     => 'Goodwill credit taken back',
                                      9     => 'Cancelled order',
                                      10    => 'Partially reversed transaction');

    public function __construct(){
        $this->registry = registry::getInstance();
        $this->db = $this->registry->db;
        $this->config = $this->registry->config;
    }

    public function __set($key, $val){
        $this->vars[$key] = $val;
    }

    public function __get($name){
        return $this->vars[$name];
    }

    public function __isset($name){
        return isset($this->vars[$name]);
    }

    public function get_paypal_packages(){
        return $this->db->query('SELECT id, package, reward, price, currency FROM dmncms_donate_paypal_packages WHERE status = 1 ORDER BY orders ASC')->fetch_all();
    }

    public function check_package($id){
        $count = $this->db->snumrows('SELECT COUNT(id) as count FROM dmncms_donate_paypal_packages WHERE id = '.$this->db->escape($id).' AND status = 1');
        return ($count == 1);
    }

    public function insert_paypal_order($reward, $price, $currency){
        $this->hash_item = md5($_SESSION['name'].$price.$currency.uniqid(microtime(),1));
        $stmt = $this->db->prepare('INSERT INTO dmncms_donate_paypal_orders (amount, currency, credits, account, hash) VALUES(:amount, :currency, :credits, :account, :hash)');
        return $stmt->execute(array(':amount'   => $price, ':currency'  => $currency, ':credits'    => $reward, ':account'  => $_SESSION['name'], ':hash'   => $this->hash_item));  
    }

    public function get_paypal_data(){
        return array('email' => $this->config->load_xml_config('donate|pp_email'), 'item' => $this->hash_item, 'user' => $_SESSION['name']);
    }

    public function gen_post_fields($data){
        $data_array = explode('&', $data);
        foreach($data_array as $value){
            $value = explode ('=', $value);
            if(count($value) == 2)
                $this->post[$value[0]] = urldecode($value[1]);
        }
        foreach($this->post as $key => $value) {        
            $this->req .= "&".$key."=".urlencode($value);
        }
    }

    public function post_back_paypal_fsock(){
        $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";  
        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $header .= "Host: ".$this->paypal_ipn_url_ssl."\r\n";
        $header .= "Content-Length: " . strlen($this->req) . "\r\n";
        $header .= "Connection: close\r\n\r\n";
        $fp = fsockopen('ssl://'.$this->paypal_ipn_url_ssl, 443, $errno, $errstr, 30);
        if(!$fp){
            $this->writelog('PayPal sent fsockopen error no. '.$errno.': '.$errstr.'','Paypal');
            return false;
        } 
        else{
            fputs($fp, $header.$this->req);
            while(!feof($fp)){
                $this->paypal_response = fgets($fp, 1024);
            }
            fclose($fp);
        }
        return true;
    }

    public function post_back_paypal_curl(){
        $request = curl_init();
        curl_setopt_array($request, array(CURLOPT_URL => $this->paypal_ipn_url,
                                          CURLOPT_POST => TRUE,
                                          CURLOPT_POSTFIELDS => $this->req,
                                          CURLOPT_RETURNTRANSFER => TRUE,
                                          CURLOPT_HTTPHEADER => array('Connection: Close'),
                                          CURLOPT_SSL_VERIFYPEER => TRUE,
                                          CURLOPT_SSL_VERIFYHOST => 2,
                                          CURLOPT_FORBID_REUSE => TRUE,
                                          CURLOPT_CAINFO => APP_PATH.DS.'data'.DS.'cacert.pem'));
        $this->paypal_response = curl_exec($request);
        if(curl_errno($request)){
            $this->writelog(curl_error($request), 'Paypal');
            return false;
        }
        curl_close($request);
        return true;
    }

    public function validate_paypal_payment(){
        if(stripos($this->paypal_response, "VERIFIED") !== false){
            if(!$this->check_email()){
                return false;   
            }
            if(!$this->check_order_number()){
                return false;
            }
            switch($this->vars['payment_status']){
                case 'Completed':
                    if($this->vars['tax'] > 0){
                        $this->vars['mc_gross'] -= $this->vars['tax']; 
                    }                   
                    if($this->vars['mc_gross'] == $this->order_details['amount']){
                        if($this->vars['mc_currency'] == $this->order_details['currency']){
                            if($this->check_completed_transaction()){
                                return false;
                            }   
                            if($this->check_pending_transaction()){
                                if($this->update_transaction_status()){
                                    return true;
                                }
                            }
                            else{
                                if($this->insert_transaction_status()){
                                    return true;
                                }
                            }
                        }
                    }
                break;
                case 'Pending':
                    if($this->vars['tax'] > 0){
                        $this->vars['mc_gross'] -= $this->vars['tax']; 
                    }
                    if(!$this->check_completed_transaction() && !$this->check_pending_transaction()){
                        $this->insert_transaction_status();
                    }
                break;
                case 'Reversed': case 'Refunded':
                    $this->decrease_credits($this->order_details['account'], $this->order_details['credits']);
                    $this->update_transaction_status();
                    if($this->config->load_xml_config('donate|pp_punish_player') == 1){
                        $this->block_user($this->order_details['account']);
                    }
                break;
            }
        }
        if(stripos($this->paypal_response, "INVALID") !== false){
            $this->writelog('PayPal sent [status: INVALID] [transaction id: '.$this->vars['txn_id'], 'Paypal');
        }
    }

    private function check_email(){
        if(strtolower($this->vars['receiver_email']) != strtolower($this->config->load_xml_config('donate|pp_email'))){
            $this->writelog('PayPal sent invalid reciever email: '.$this->vars['receiver_email'].'', 'Paypal');
            return false;
        }
        return true;
    }

    private function check_order_number(){
        $count = $this->db->snumrows('SELECT COUNT(id) AS count FROM dmncms_donate_paypal_orders where hash = '.$this->db->escape($this->vars['item_number']));
        if($count == 1){
            $this->order_details = $this->db->query('SELECT amount, currency, account, credits FROM dmncms_donate_paypal_orders where hash = '.$this->db->escape($this->vars['item_number']))->fetch();
            return true;
        }
        else{
            $this->writelog('PayPal sent invalid order [transaction id: '.$this->vars['txn_id'].']', 'Paypal');
            return false;
        }
    }

    private function check_completed_transaction(){
        $count = $this->db->snumrows('SELECT COUNT(id) AS count FROM dmncms_donate_paypal_transactions where transaction_id = '.$this->db->escape($this->vars['txn_id']).' and status = \'Completed\'');
        if($count > 0){
            return true;
        }
        return false;
    }

    private function check_pending_transaction(){
        $count = $this->db->snumrows('SELECT COUNT(id) AS count FROM dmncms_donate_paypal_transactions where transaction_id = '.$this->db->escape($this->vars['txn_id']).' and status = \'Pending\'');
        if($count > 0){
            return true;
        }
        return false;
    }

    private function update_transaction_status(){
        $stmt = $this->db->prepare('UPDATE dmncms_donate_paypal_transactions SET status = :status WHERE transaction_id = :trans_id');
        return $stmt->execute(array(':status' => $this->vars['payment_status'], ':trans_id' => $this->vars['txn_id']));
    }

    private function insert_transaction_status(){
        $stmt = $this->db1->prepare('INSERT INTO dmncms_donate_paypal_transactions (transaction_id, amount, currency, acc, credits, order_date, status, payer_email) VALUES (:trans_id, :gross, :currency, :account, :credits, :time, :payment_status, :payer_email)');
        return $stmt->execute(array(':trans_id' => $this->vars['txn_id'], ':gross' => $this->vars['mc_gross'], ':currency' => $this->vars['mc_currency'], ':account' => $this->order_details['account'], ':credits' => $this->order_details['credits'], ':time' => time(), ':payment_status' => $this->vars['payment_status'], ':payer_email' => $this->vars['payer_email']));
    }

    public function reward_user($acc, $credits){
        $stmt = $this->db->prepare('UPDATE bg_user SET cash = cash + :credits WHERE bg_user = :account');
        $stmt->execute(array(':account' => $acc, ':credits' => str_replace('-', '', $credits)));
    }

    private function decrease_credits($acc, $credits){
        $stmt = $this->db1->prepare('UPDATE bg_user SET cash = cash - :credits WHERE bg_user = :account');
        $stmt->execute(array(':credits' => str_replace('-', '', $credits), ':account' => $acc));
    }

    private function block_user($acc){
        return;
    }

    public function validate_ip_list(){
        return (in_array($_SERVER['REMOTE_ADDR'], $this->pw_ip_white_list));
    }

    public function validate_pw_signature(){
        return (md5('uid='.$this->vars['uid'].'currency='.$this->vars['currency'].'type='.$this->vars['type'].'ref='.$this->vars['ref'].$this->config->load_xml_config('donate|pw_secretkey')) == $this->vars['sig']);
    }

    public function validate_pw_payment(){
        if(!$this->check_reference()){
            if($this->log_pw_transaction()){
                return true;
            }
        }
        else{
            if($this->vars['type'] == 2){
                $this->change_pw_transaction_status();
                if($this->vars['reason'] == 2 || $this->vars['reason'] == 3){
                    $this->block_user($this->vars['uid']);
                }       
                $this->decrease_credits($this->vars['uid'], $this->vars['currency']);   
            }
        }
    }

    private function check_reference(){
        $count = $this->db->snumrows('SELECT COUNT(uid) AS count FROM dmncms_donate_paymentwall WHERE uid = '.$this->db->escape($this->vars['uid']).' AND ref = '.$this->db->escape($this->vars['ref']).'');
        if($count > 0){ 
            return true;
        }
        return false;
    }

    private function log_pw_transaction(){
        $prepare = $this->db->prepare('INSERT INTO dmncms_donate_paymentwall (uid, currency, type, ref, reason, order_date) VALUES (:uid, :currency, :type, :ref, :reason, :time)');
        return $prepare->execute(array(':uid' => $this->vars['uid'], ':currency' => $this->vars['currency'], ':type' => $this->vars['type'], ':ref' => $this->vars['ref'], ':reason' => 'Complete', ':time' => time()));
    }

    private function change_pw_transaction_status(){
        $stmt = $this->db->prepare('UPDATE dmncms_donate_paymentwall SET currency = :currency, reason = :reason, order_date = :order_date WHERE uid =:uid AND ref = :ref');
        $stmt->execute(array(':currency' => $this->vars['currency'], ':reason' => $this->pw_reason_list[$this->vars['reason']], ':order_date' => time(), ':uid' => $this->vars['uid'], ':ref' => $this->vars['ref']));
    }

    public function writelog($logentry, $lgname) {
        $log = '['.$_SERVER['REMOTE_ADDR'].'] ['.(isset($_SESSION['name']) ? $_SESSION['name'] : 'Unknown').'] '.$logentry.'';
        $log_name = APP_PATH.DS.'logs'.DS.$lgname.'_'.date("m-d-y").'.txt';
        $logfile = @fopen($log_name, "a+");
        if($logfile){
            fwrite($logfile, "[".date ("h:iA")."] $log\r\n");
            fclose($logfile);
        }
    }
}

这是view.paymentwall.php / http://domain.com/donate/paymentwall - 即时使用它进行pingback地址

<?php 
    if(load::get('errors') != false){
        foreach(load::get('errors') as $errors){
            echo '<div class="notification-box notification-box-error">'.$errors.'</div>';
        }
    }
    if(load::get('pw') == false || load::get('pw') == 0){
        echo '<div class="notification-box notification-box-error">This donation method is disabled.</div>';
    }
    else{
        echo '<div style="/* border: 1px dotted black; *//* -webkit-border-radius: 5px; */-moz-border-radius: 5px;/* border-radius: 5px; */margin-top: 10px;    padding: 10px;    height: auto;    background: rgba(55, 52, 55, 1);    box-shadow: 0 0 4px rgba(0,0,0,.6), 0 1px 1px rgba(0,0,0,.5), inset 0 0 0 1px rgba(255,255,255,.015), inset 0 1px 0 rgba(255,255,255,.05);    -webkit-border-radius: 5px;    -moz-border-radius: 5px;    border-radius: 5px;    /* margin-left: -38px; */    z-index: 1;">
                <div style="padding: 2px; text-align: center;"><iframe src="http://wallapi.com/api/ps/?key='.load::get('pw_apikey').'&uid='.$_SESSION['name'].'&widget='.load::get('pw_widget').'" width="'.load::get('pw_w_width').'" height="'.load::get('pw_w_height').'" frameborder="0"></iframe></div>
              </div>';
    }
?>

2 个答案:

答案 0 :(得分:0)

根据您要使用的版本,有必要使用适当的算法和参数进行签名计算:

https://www.paymentwall.com/en/documentation/Signature-Calculation/2313

如果版本为2或3,则应按字母顺序对参数进行排序。

对于pingback,你只需返回字符串&#34; OK&#34;在成功pingback /否定pingback的情况下从您的服务器。

答案 1 :(得分:0)

当Paymentwall发送Pingback时,它希望您的服务器使用HTTP状态代码200进行响应,并且响应正文仅包含OK https://www.paymentwall.com/en/documentation/Virtual-Currency-API/711#http_pingback_return_value

看起来目前您的脚本会返回付款页面的HTML代码作为对Paymentwall的Pingback的回复,因此问题是响应正文不包含OK。

我建议拆分付款页面和pingback处理脚本,并将pingback处理脚本移动到域/ paymentwall-pingback

之类的内容

另外,要更轻松地验证Paymentwal pingback,请随时使用Paymentwall PHP Library。 使用Paymentwall PHP库,验证pingback签名,pingback源和参数只需几行即可完成:

require_once('/path/to/paymentwall-php/lib/paymentwall.php');
Paymentwall_Config::getInstance()->set(array(
  'api_type' => Paymentwall_Config::API_VC, //OR API_GOODS or API_CART
  'public_key' => 'YOUR_PUBLIC_KEY',
  'private_key' => 'YOUR_PRIVATE_KEY'
));
$pingback = new Paymentwall_Pingback($_GET, $_SERVER['REMOTE_ADDR']);
if ($pingback->validate()) {
  //product delivery logic
}