我已经设置了paypal ipn,握手工作:我可以使用paypal支付。但是,weirldy它没有经过验证返回并且返回无效。
付款也已经过去了?
paypal按钮的代码:
<form action="https://www.paypal.com/cgi-bin/webscr" name="gateway_form" method="post">
<input type="hidden" value="2" name="rm">
<input type="hidden" value="_xclick" name="cmd">
<input type="hidden" value="<?=base_url()?>stationery/paypal_accepted" name="return">
<input type="hidden" value="<?=base_url()?>stationery/paypal_cancelled" name="cancel_return">
<input type="hidden" value="<?=base_url()?>stationery/paypal_ipn" name="notify_url">
<input type="hidden" value="vish90@hotmail.com" name="business">
<input type="hidden" value="GBP" name="currency_code">
<input type="hidden" value="<?=$basket_total?>" name="amount">
<input type="hidden" value="John Browns Stationery Order" name="item_name">
<input type="hidden" value="<?=$random_invoice_no?>" name="invoice">
<input type="hidden" value="<?=$user_id?>" name="custom">
<input class="btn btn-default" type="submit" value="Checkout by Paypal">
</form>
ipn侦听器代码:
<?php
/**
* PayPal IPN Listener
*
* A class to listen for and handle Instant Payment Notifications (IPN) from
* the PayPal server.
*
* https://github.com/Quixotix/PHP-PayPal-IPN
*
* @package PHP-PayPal-IPN
* @author Micah Carrick
* @copyright (c) 2012 - Micah Carrick
* @version 2.1.0
*/
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 = false;
/**
* 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 = 60;
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';
const SANDBOX_HOST = 'www.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()
*
* Sends the post back to PayPal using the fsockopen() function. Called by
* the processIpn() method if the use_curl property is false. 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 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\r\n";
$header .= "Host: ".$this->getPaypalHost()."\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: ".strlen($encoded_data)."\r\n";
$header .= "Connection: Close\r\n\r\n";
fputs($fp, $header.$encoded_data."\r\n\r\n");
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
*
* Returns the URI that was used to send the post back to PayPal. This can
* be useful for troubleshooting connection problems. The default URI
* would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
*
* @return string
*/
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
*
* Returns the HTTP response status code from PayPal. This should be "200"
* if the post back was successful.
*
* @return string
*/
public function getResponseStatus() {
return $this->response_status;
}
/**
* Get Text Report
*
* Returns a report of the IPN transaction in plain text format. This is
* useful in emails to order processors and system administrators. Override
* this method in your own class to customize the report.
*
* @return string
*/
public function getTextReport() {
$r = '';
// date and POST url
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
if ($this->use_curl) $r .= " (curl)\n";
else $r .= " (fsockopen)\n";
// HTTP Response
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n{$this->getResponse()}\n";
// POST vars
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n";
foreach ($this->post_data as $key => $value) {
$r .= str_pad($key, 25)."$value\n";
}
$r .= "\n\n";
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) {
// use raw POST data
if (!empty($_POST)) {
$this->post_data = $_POST;
$encoded_data .= '&'.file_get_contents('php://input');
} else {
throw new Exception("No POST data found.");
}
} else {
// use provided data array
$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.");
}
}
/**
* Require Post Method
*
* Throws an exception and sets a HTTP 405 response header if the request
* method was not POST.
*/
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.");
}
}
}
和ipn处理程序代码:
function paypal_ipn(){
/**
* PHP-PayPal-IPN Example
*
* This shows a basic example of how to use the IpnListener() PHP class to
* implement a PayPal Instant Payment Notification (IPN) listener script.
*
* For a more in depth tutorial, see my blog post:
* http://www.micahcarrick.com/paypal-ipn-with-php.html
*
* This code is available at github:
* https://github.com/Quixotix/PHP-PayPal-IPN
*
* @package PHP-PayPal-IPN
* @author Micah Carrick
* @copyright (c) 2011 - Micah Carrick
* @license http://opensource.org/licenses/gpl-3.0.html
*/
/*
Since this script is executed on the back end between the PayPal server and this
script, you will want to log errors to a file or email. Do not try to use echo
or print--it will not work!
Here I am turning on PHP error logging to a file called "ipn_errors.log". Make
sure your web server has permissions to write to that file. In a production
environment it is better to have that log file outside of the web root.
*/
ini_set('log_errors', true);
ini_set('error_log', base_url() . 'add_ons/ipn/ipn_errors.log');
// instantiate the IpnListener class
include('./add_ons/ipn/ipnlistener.php');
$listener = new IpnListener();
/*
When you are testing your IPN script you should be using a PayPal "Sandbox"
account: https://developer.paypal.com
When you are ready to go live change use_sandbox to false.
*/
$listener->use_sandbox = false;
/*
By default the IpnListener object is going going to post the data back to PayPal
using cURL over a secure SSL connection. This is the recommended way to post
the data back, however, some people may have connections problems using this
method.
To post over standard HTTP connection, use:
$listener->use_ssl = false;
To post using the fsockopen() function rather than cURL, use:
$listener->use_curl = false;
*/
/*
The processIpn() method will encode the POST variables sent by PayPal and then
POST them back to the PayPal server. An exception will be thrown if there is
a fatal error (cannot connect, your server is not configured properly, etc.).
Use a try/catch block to catch these fatal errors and log to the ipn_errors.log
file we setup at the top of this file.
The processIpn() method will send the raw data on 'php://input' to PayPal. You
can optionally pass the data to processIpn() yourself:
$verified = $listener->processIpn($my_post_data);
*/
try {
$listener->requirePostMethod();
$verified = $listener->processIpn();
mail('vish90@hotmail.com', 'what is the verified value?', $verified);
} catch (Exception $e) {
mail('vish90@hotmail.com', 'error', $e->getMessage());
error_log($e->getMessage());
exit(0);
}
/*
The processIpn() method returned true if the IPN was "VERIFIED" and false if it
was "INVALID".
*/
if ($verified) {
/*
Once you have a verified IPN you need to do a few more checks on the POST
fields--typically against data you stored in your database during when the
end user made a purchase (such as in the "success" page on a web payments
standard button). The fields PayPal recommends checking are:
1. Check the $_POST['payment_status'] is "Completed"
2. Check that $_POST['txn_id'] has not been previously processed
3. Check that $_POST['receiver_email'] is your Primary PayPal email
4. Check that $_POST['payment_amount'] and $_POST['payment_currency']
are correct
Since implementations on this varies, I will leave these checks out of this
example and just send an email using the getTextReport() method to get all
of the details about the IPN.
*/
foreach($this->input->post() as $key => $value){
$data[$key] = $value;
}
$this->ipn_verified($data);
mail('vish90@hotmail.com', 'Verified IPN', $listener->getTextReport());
} else {
/*
An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's
a good idea to have a developer or sys admin manually investigate any
invalid IPN.
*/
mail('vish90@hotmail.com', 'IPN is invalid', $listener->getTextReport());
}
}
更新
我创建了一个文本报告:
HTTP/1.1 200 OK
Server: Apache
X-Frame-Options: SAMEORIGIN
Paypal-Debug-Id: f12b436ba34fc
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
DC: dcg12-origin-www-2.paypal.com
Date: Tue, 15 Mar 2016 11:35:50 GMT
Content-Length: 7
Connection: close
Set-Cookie: cwrClyrK4LoCV1fydGbAxiNL6iG=AJGAy4asx-VKRgNsi6tOcBzPvUpJE9YTQbT7LjGvLd-hcG94uHT60TPzfOxn7psnIrKUTpm7Uhx1EuFm_dN5UmgmCIBhkbYG3UFQLQ0kAyJNq-4F2YHhtPqLlJJ-nAPKKNHp4-9na-9KedRj8tKnSadxd-rkQffpEdJ3a-olWxDgCXbiCS3m8GUxs9whYlM4j9fC44XtdKa6tVAEyxnlXvTZT_tPjsmRusPIwe508NVz8mOiTYDIjWWgYTcLgb6N6__WHncNHihk4vD-VA3PVWhBIH4W0Zku-29-r2vcHZILfLlowv-b3s6jqu4HHdsTV1vkBTXcRFHQKeHl6INVuZ8AUa10N30il814CCVMQrMMf9oHtoQ2HLDls2g24vFuiQa1w5U-R-v_MhPsJj5Sgdtz8t5K2Dl3Wtp_-h8b2MEI8Sn-YzrdtpfYzy8; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: cookie_check=yes; expires=Fri, 13-Mar-2026 11:35:49 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: navlns=0.0; expires=Thu, 15-Mar-2018 11:35:49 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: X-PP-SILOVER=name%3DLIVE11.WEB.1%26silo_version%3D880%26app%3Dappdispatcher%26TIME%3D2515789654; domain=.paypal.com; path=/; Secure; HttpOnly
Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
Set-Cookie: AKDC=dcg12-origin-www-2.paypal.com; expires=Tue, 15-Mar-2016 12:05:50 GMT; path=/; secure
Strict-Transport-Security: max-age=63072000
INVALID
--------------------------------------------------------------------------------
mc_gross 30.60
invoice pDz0Nun6H29xdGuI
protection_eligibility Ineligible
address_status confirmed
payer_id 9SU8DB98AZDKU
tax 0.00
address_street 1 Main Terrace
payment_date 04:35:46 Mar 15, 2016 PDT
payment_status Pending
charset windows-1252
address_zip W12 4LQ
first_name Vish
address_country_code GB
address_name Vish Patel's Test Store
notify_version 3.8
custom 501
payer_status verified
address_country United Kingdom
address_city Wolverhampton
quantity 1
verify_sign AzFmRN2alSXsVcRQ-bkJDjsW0iFTAt2a-oBGJoFYjl.qfx0QiRc9VT6j
payer_email testee@test.com
txn_id 37U96690JH140125B
payment_type instant
payer_business_name Vish Patel's Test Store
last_name Patel
address_state West Midlands
receiver_email TEST@test.com
pending_reason unilateral
txn_type web_accept
item_name ipn test Order
mc_currency GBP
item_number
residence_country GB
test_ipn 1
handling_amount 0.00
transaction_subject
payment_gross
shipping 0.00
ipn_track_id d243782521d47
另外,查看ipn历史记录日志,令人担忧的是没有http状态代码,其空白和状态显示已禁用。
答案 0 :(得分:0)
商家帐户意外收到了关闭的ipn消息。因此,登录此帐户并启用此选项可以正常运行。