我已经在这工作了 24 小时,现在正要拔掉我的头发。我已经检查了整个 Web 和 Stackoverflow,但找不到任何帮助。我什至检查过以前的帖子,例如没有收到来自 Paypal IPN 沙盒的回复,但这些回复对我不起作用。也许我错过了对我有帮助的帖子;如果我有,请原谅我重复同样的问题,但这件事相当紧急,我已经走到尽头了。
无论如何,问题是这样的:
我有一个 PHP 购物车,它将客户发送到 Paypal。一切正常。在向他们发送所有代码时,我已经按照 Paypal 的说明构建了它。一切都很好,除了最后一步,POST
从 Paypal 返回到我的服务器以检查一切正常。即使在那里,我也照原样复制了整个 Paypal 代码,并添加了检查我的所有匹配项的功能。但是,我无法让它工作。我尝试将结果发送到数据库,但没有任何反应。Mail
因此,如果一切正常并且我没有收到电子邮件,我将一个 PHP命令放在最后一个操作应该在的位置。我Mail
几乎在其他任何地方都放置了同样的命令,试图找出什么'
首先,当我调用将 Paypal 应该发送回我的服务器的 vars 打印到电子邮件中时,我收到了包含除item_name
and之外的所有 vars 的电子邮件item_number
,我得到了空白;这很奇怪,因为到目前为止,Paypal Sandbox 正在向我展示我应该购买的每一件产品。我试着给 PHP 代码上的这些变量一个固定的值,因为 Paypal 没有向它们发布值,至少在那时。我想看看缺少这两个值是否是错误的原因;但是,即使使用设定值,错误仍然存在。
其次, Paypal 代码中有一个while
循环(上面给出的链接中的响应说应该替换为 的循环$res=stream_get_contents($fp, 1024);
,但是,这对我也不起作用),所以我把Mail
命令放在那里看看我回来了。我要求打印$res
var 和 the payment_status
,果然得到了几封 E-Mail,收集到的结果如下:
payment_status = Pending
$res = HTTP/1.0 302 Found
Location: https://www.sandbox.paypal.com
Server: BigIP
Connection: close
Content-Length: 0
所以我猜这个错误正在发生。有些事情正在发生(或没有发生),它不仅没有返回代码为继续检查等而寻找的Completed
状态payment_status
,而且甚至没有返回INVALID
响应。所以我没有得到任何回应,也没有任何东西可以告诉我一切是否正常。而且,奇怪的是,甚至更糟糕的是,Sandbox 仍然在每次付款尝试都向我收取虚假费用,即使很明显某处存在错误并且流程没有完成。(当然,这带来了另一个困境:一旦这一切都解决了,如果由于 X 原因在某个时候出现服务器错误,Paypal 是否仍会向我的客户收费,我赢了'
好吧,我想这就是我在这件事上所能解释的。在这一点上,我看不出我哪里出错了。代码应该使这变得非常简单。所以我真的不明白我怎么能搞砸复制和粘贴。我想至少应该没有错误,除非它们带有原始代码。此外,因为在那一点上其他一切都 100% 正常工作,所以这个错误可能出现的唯一地方是这个 PHP 文件中,一旦用户完成支付过程,Paypal 就必须调用它。
任何关于此事的想法将不胜感激!
这里是代码。
PHP代码:
include('../inc/db_fns.inc'); //<--All my DB work is in here.
include('../inc/shipping.inc');
$paypal_email = "seller_1360198925_biz@hotmail.com";
$paypal_currency = 'USD';
//Here begin the functions I'm using to check everything and pass data to DB.
function no_paypal_trans_id($trans_id) {
$connection = db_connect();
$query = sprintf("SELECT id FROM orders WHERE paypal_trans_id = '%s'", mysql_real_escape_string($trans_id));
$result = mysql_query($query);
$num_results = mysql_num_rows($result);
if($num_results == 0) {
return true;
}
return false;
}
function payment_amount_correct($shipping, $params) {
$amount = 0.00;
for ($i=1; $i <= $params['num_cart_items']; $i++) {
$query = sprintf("SELECT precio FROM products WHERE id='%s'", mysql_real_escape_string($params["item_number{$i}"]));
$result = mysql_query($query);
if($result) {
$item_price = mysql_result($result, 0, 'precio');
$amount += $item_price * $params["quantity{$i}"];
}
}
if(($amount+$shipping) == $params['mc_gross']) {
return true;
} else {
return false;
}
}
function create_order($params) {
db_connect();
$query = sprintf("INSERT INTO orders set orders.firstname = '%s', orders.lastname = '%s', orders.email = '%s', orders.country = '%s', orders.address = '%s', orders.city = '%s', orders.zip_code = '%s', orders.state = '%s', orders.status = '%s', orders.amount = '%s', orders.paypal_trans_id = '%s', created_at = NOW()", mysql_real_escape_string($params['first_name']), mysql_real_escape_string($params['last_name']), mysql_real_escape_string($params['payer_email']), mysql_real_escape_string($params['address_country']), mysql_real_escape_string($params['address_street']), mysql_real_escape_string($params['address_city']), mysql_real_escape_string($params['address_zip']), mysql_real_escape_string($params['address_state']), mysql_real_escape_string($params['payment_status']), mysql_real_escape_string($params['mc_gross']), mysql_real_escape_string($params['txn_id']));
$result = mysql_query($query);
if(!$result) {
return false;
}
$order_id = mysql_insert_id();
for ($i=1; $i <= $params['num_cart_items'] ; $i++) {
$product = find_product($params["item_number{$i}"]);
$query = sprintf("INSERT INTO items set order_id = '%s', product_id = '%s', title = '%s', price = '%s', qty = '%s'", mysql_real_escape_string($order_id), mysql_real_escape_string($product['id']), mysql_real_escape_string($product['title']), mysql_real_escape_string($product['price']), mysql_real_escape_string($params["quantity{$i}"]));
$result = mysql_query($query);
if(!$result) {
return false;
}
}
return true;
}
//Here begins the Paypal code as is
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30); //<--Here I also tried out the other response to the question linked above and it actually returned a 'Invalid host' into he $res var-
// assign posted variables to local variables
$item_name = $_POST['item_name']; //<--These are the two vars for which
$item_number = $_POST['item_number'];// Paypal Sandbox posts no value.
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
if ($_POST['payment_status'] == 'Completed' && no_paypal_trans_id($_POST['txn_id']) && $paypal_email == $_POST['receiver_email'] && $paypal_currency == $_POST['mc_currency'] && payment_amount_correct($shipping, $_POST)) {
// process payment
create_order($_POST);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
}
fclose ($fp);
}
编辑1:再试一次:不走运!
我刚刚尝试了原始的、未改动的 Paypal 代码。我刚刚将它复制并粘贴到这个 PHP 中,然后运行 Sandbox 购买。同样的结果。没有回应,没有数据插入表格,我无法知道有人真的从我的购物车上买了东西,但 Paypal 仍然对购买进行虚假收费。这支持了我的怀疑,即错误出现在原始代码中,与我添加的函数无关。希望有人能尽快理解这一点。千提前感谢那个人!
编辑 2:在第一个响应之后。
现在删除了他/她的回复的好心用户非常好心,可以先尝试一下。他/她建议在 Paypal 文档中提及https://www.sandbox.paypal.com/cgi-bin/webscr
我拥有的http://www.sandbox.paypal.com
. 也许我有旧版本的代码,所以我尝试了他/她的建议。现在我评论发生了什么:
首先,非常感谢您的回复。不幸的是,没有运气。用另一个地址替换了一个地址,现在该过程没有进入while
循环,它停止在fsockopen
. 我放置了一个Mail
命令来打印出该命令中包含的$errno
和$errstr
。https://www.sandbox.paypal.com/cgi-bin/webscr
替换后http://www.sandbox.paypal.com
我无法找到套接字传输“https” - 您在配置 PHP 时是否忘记启用它?所以我剥离了“https://”并再次尝试。现在我得到php_network_getaddresses: getaddrinfo failed: Name or service not known。有任何想法吗?
编辑 3:在评论部分与@hexacyanide 交谈后:
$req = cmd=_notify-validate&test_ipn=1&payment_type=instant&payment_date=20%3A55%3A22+Feb+08%2C+2013+PST&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&address_name=John+Smith&address_country=United+States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San+Jose&address_street=123%2C+any+street&receiver_email=seller%40paypalsandbox.com&receiver_id=TESTSELLERID1&residence_country=US&item_name1=something&item_number1=AK-1234&quantity1=1&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross_1=9.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=2229455¬ify_version=2.4&custom=xyz123&invoice=abc1234&charset=windows-1252&verify_sign=AsdNkKD2ktCz.aUB.9WYWy-g8MHoAa-TsvSjUgGstseJVdUhQTq3aCwW
对不起,那是$req
,不是$res
var。$res
var 由循环while
返回。我在那里放置了一个命令,我收到了几封带有这些值mail
的电子邮件。$res
这些都是:
X-Frame-Options: SAMEORIGIN
HTTP/1.0 200 OK
Strict-Transport-Security: max-age=14400
INVALID
Content-Type: text/html; charset=UTF-8
Date: Sat, 09 Feb 2013 05:44:33 GMT
Connection: close
Content-Length: 7
编辑 4:绝对目瞪口呆:即使是直接来自 Paypal 开发者网站并使用 Paypal 开发者网站 IPN 测试器进行测试的简单 Paypal IPN 代码也不能工作......
- 我使用了此处找到的 Paypal IPN 脚本生成器。
- 我选择生成一个脚本,该脚本将向我发送一个 VALID 或 INVALID 响应。
- 我将其全部复制并粘贴到我保存在服务器中的 PHP 文件中。
- 我检查并重新检查了代码的任何部分都没有留下。
- 我从这里找到的 IPN 模拟器将这个 PHP 文件定位在我的服务器上。
- 模拟器显示检查并显示“ IPN 已成功发送。 ”
- 我去查看我的邮件,看看我收到了什么回复,是有效的还是无效的……我根本没有收到任何回复。因此,IPN 在某些时候到达 PHP 购买,该过程被破坏,因此它甚至无法访问 VALID/INVALID 函数。然而,这正是 Paypal 为您提供的代码,并使用它为其设计的 sim 卡进行了测试。发生什么了?
这次奥德赛的第二天
OK 不用说:还没有运气。但我现在决定详尽地跟踪进入 PHP 代码并输出到 Paypal 的所有内容。这个想法是,VALID
当此代码以相同的顺序将 Paypal 插入其中的初始值发送回 Paypal 时,会发生响应(根据 Paypal 文档)。
第一个问题是我没有收到任何来自代码的响应。所以假设是代码在一开始就失败了。碰巧第一个问题是沙盒链接不起作用。(我在@hexacyanide 的帮助下做到了这一点,他昨天很乐意跟随我的进步或缺乏。每当我获得足够的声誉来积极地标记他/她的回应时,我会的。)所以我剥离了sandbox.
而且,瞧,它正在返回一个响应,但现在响应是INVALID
.
从那时到现在,我了解到 IPN 仅用于卖方交易检查和数据记录。Paypal 不关心 IPN 的结果。所以我的购物车是 100% 工作的。用户可以购买东西,Paypal 会向用户收费。如果购买信息实际上来自 Paypal 并且一切正常,IPN 只会为我检查,然后(在我的脚本中)将所有这些信息发送到数据库中,以便我可以完成我的服务。因此,即使交易在没有 IPN 的情况下成功进行,IPN 仍将是促进整个销售过程的宝贵机制。但是,所有这些最后的信息都解决了我的怀疑,即我所有的购物车代码都正常,问题仅出在此处,使用此代码或 Paypal 处理它的方式。(Paypal 的“处女”代码通过 Paypal 的事实
所以,所有进出这个 PHP 的日志。为了创建检查点,我Mail
在代码中的每个重要点都放置了命令。在foreach()
命令中,我包含了一个增量变量,以便获得进入的 POSTED 数据的有序列表。这就是我得到的:
这是 Paypal 发布到代码中的数据(按照发布的顺序)
test_ipn=1
payment_type=instant
payment_date=08%3A42%3A23+Feb+09%2C+2013+PST
payment_status=Completed
payer_status=verified
first_name=John
last_name=Smith
payer_email=buyer%40paypalsandbox.com
payer_id=TESTBUYERID01
business=seller%40paypalsandbox.com
receiver_email=seller%40paypalsandbox.com
receiver_id=TESTSELLERID1
residence_country=US
item_name1=something
item_number1=AK-1234
quantity1=1
tax=2.02
mc_currency=USD
mc_fee=0.44
mc_gross=15.34
mc_gross_1=12.34
mc_handling=2.06
mc_handling1=1.67
mc_shipping=3.02
mc_shipping1=1.02
txn_type=cart
txn_id=23291642
notify_version=2.4
custom=xyz123
invoice=abc1234
charset=windows-1252
乍一看,我似乎从 Paypal 获得了我应该得到的所有数据。这是PP发送它的顺序。所以如果我按这个顺序发回这个数据,而 PP 实际上确实检查了这个相同的顺序,那么理论上我应该得到一个VALID
响应。
所以代码所做的是添加“cmd=_notify-validate”,这是唯一的添加(PP 文档明确指出这是必要的添加是必要的),并将所有这些数据传递到$req
以这种方式调用的 var 中:A=X&B=Y&C=Z...
.
这是来自下一个检查点的消息,在foreach()
命令关闭后添加。
$req = cmd=_notify-validate&test_ipn=1&payment_type=instant&payment_date=08%3A42%3A23+Feb+09%2C+2013+PST&payment_status=Completed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=TESTSELLERID1&residence_country=US&item_name1=something&item_number1=AK-1234&quantity1=1&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=15.34&mc_gross_1=12.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=23291642¬ify_version=2.4&custom=xyz123&invoice=abc1234&charset=windows-1252&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31ACyRxUQ6LVDwUz.i78mjQLsN9aKb
注意最后verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31ACyRxUQ6LVDwUz.i78mjQLsN9aKb
。foreach()
我无法解释那段数据,因为它在循环期间没有以电子邮件的形式吐出。那么它是从哪里来的呢?INVALID
这可能是返回响应的罪魁祸首吗?开放式问题。但是此时,所有这些数据都由代码在“ DATA COMING IN ”检查点传递;所以如果这个数据是进来的,我的代码把它发回,那么一切都应该没问题。
所以下一个检查点将是“ DATA COMING OUT ”。fputs ($fp, $header . $req);
我在写$req
回 PP的代码之前找到了这个检查点。这就是代码的结果:
$req = cmd=_notify-validate&test_ipn=1&payment_type=instant&payment_date=08%3A42%3A23+Feb+09%2C+2013+PST&payment_status=Completed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=TESTSELLERID1&residence_country=US&item_name1=something&item_number1=AK-1234&quantity1=1&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=15.34&mc_gross_1=12.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=23291642¬ify_version=2.4&custom=xyz123&invoice=abc1234&charset=windows-1252&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31ACyRxUQ6LVDwUz.i78mjQLsN9aKb
哼!我错过了什么吗?我的眼睛是否跳过了导致此代码旅行的最微小的打嗝?输出似乎与输入完全相同。让我们假设 PP 很好地处理了他们的代码,POST 数据以 PP 期望的方式转换为字符串,因此,检查......假设所有这些,可能有什么问题?
让我们再看一遍:开放式问题:
- 会不会是标题的问题?根据文档,这是应该使用的标题......所以除非他们对此关闭,否则它应该可以正常工作。
- 给定的 URL 可能有问题吗?好的,这实际上是一个问题,或者更确切地说是在某些时候。互联网上至少有 6 或 7 个不同的 URL,它们应该可以工作,但不能工作。有些人为某些人工作而不为其他人工作,有些人似乎永远不会工作,等等。甚至 PP 自己也不确定应该使用什么 URL,因为在他们自己的文档中它会有所不同。很清楚的是,使用
sandbox.
URL 将不会返回任何内容——假设这些 URL 已损坏。 - 可能是字符集的问题吗?会不会有不兼容?当我看到数据以十六进制代码进出时,我突然想到了这一点。问题是这应该使它兼容,对吧?然而,昨天,当我检查
while()
循环中发生了什么,并将从 PP 发回的信息捕获到$res
var 中时,我没有得到十六进制代码,正如你在本遗嘱中进一步看到的那样。
下一个检查点是if()
VALID 和if()
INVALID 的经典检查点。而且,当然,我得到一个告诉我这一切都再次无效的消息。
希望我提供的这些详细信息能让某人的灯泡闪闪发光!至于我,我还是傻眼了。
提前致谢!
非常感谢你们的回复!
我还没有尝试过第二个,虽然它听起来很明智。听起来这可能是我从 PayPal 获得的原始代码的问题。如果我有时间尝试一下,看看代码是否适用,我会在这里发布我的反馈。希望有人会发现这一切都很有用。
经过一个星期的头撞墙和一点时间来冷静大脑中的问题后,我终于在几天前找到了另一种解决问题的方法,该方法与第二种方法非常相似六氰化物反应的一部分。我在下面为任何关注此字符串的人发布它。但是,我必须说,PayPal 代码有很多错误。至少我收到的那个。从那以后,我遇到了其他几个必须通过变通方法解决的问题。最糟糕的是,PayPal 根本不支持。我什至打了三次:第一次,那个人挂了我;然后,他们告诉我这可能是病毒问题(当他们真的不知道发生了什么时的典型反应)。
无论如何,我希望我能评价你的两个回答,但我需要超过 +15 分,所以我会在这里口头表扬他们。我按原样尝试了 Hexacynide 的响应代码,但它对我不起作用,所以我无法将其标记为已检查。如果我将来有时间尝试另一个,并且它有效,我会将其标记为正确。
在那之前,这是我使用 CURL 进行的代码更新。
$ch = curl_init('https://www.paypal.com/pe/cgi-bin/webscr');
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'));
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
注意:这里它针对的是真实的东西,因为它现在已经启动并运行,但是,使用它也可以sandbox.
工作。