php - 无法提交贝宝和验证按钮
问题描述
我在使用 paypal 按钮时遇到了一些问题。
这是我用于创建、参数化和加密按钮的 php 类:
<?php
class paypal {
public $config;
public $payPalCertID = "myCertID";
public $myPrivateKeyFile;
public $myPublicCertFile;
public $paypalCertFile;
public $caCertFile;
public $openSSL;
/**
* @var bool $use_sandbox Indicates if the sandbox endpoint is used.
*/
private $use_sandbox = false;
/**
* @var bool $use_local_certs Indicates if the local certificates are used.
*/
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
public function __construct($conf) {
$this->config=$conf;
$this->myPrivateKeyFile = "../my-prvkey.pem";
$this->myPublicCertFile= "../my-pubcert.pem";
$this->paypalCertFile = "../paypal_cert.pem";
$this->caCertFile = "../cacert.pem";
$this->openSSL = "/usr/bin/openssl";
}
function getEncryptedForm($title, $id_item, $price, $promoCodeValidity) {
$form = array("cmd" => "_xclick",
"business" => $this->config->payPalMail,
"cert_id" => $this->payPalCertID,
"lc" => "IT",
"item_name" => $title,
"item_number" => $id_item,
"amount" => $price,
"currency_code" => "EUR",
"no_note" => "1",
"shipping" => "0",
"address_override" => "0",
"return" => "myreturnurl.php"
);
$encryptedData = $this->paypal_encrypt($form);
if ($encryptedData != null) {
return '<form class="center" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="encrypted" value="'.$encryptedData.'">
<input type="image" src="../paypalPayNow.png"
border="0" name="submit"
style="width: 174px;height: 47px;"/>
</form>';
}
}
private function paypal_encrypt($hash) {
if (!file_exists($this->myPrivateKeyFile)) {
echo "ERROR: MY_KEY_FILE $this->myPrivateKeyFile not found\n";
return null;
}
if (!file_exists($this->myPublicCertFile)) {
echo "ERROR: MY_CERT_FILE $this->myPublicCertFile not found\n";
return null;
}
if (!file_exists($this->paypalCertFile)) {
echo "ERROR: PAYPAL_CERT_FILE $this->paypalCertFile not found\n";
return null;
}
if (!file_exists($this->openSSL)) {
echo "ERROR: OPENSSL $this->openSSL not found\n";
return null;
}
//Assign Build Notation for PayPal Support
$hash['bn']= $config->secret_world;
$data = "";
foreach ($hash as $key => $value) {
if ($value != "") {
//echo "Adding to blob: $key=$value\n";
$data .= "$key=$value\n";
}
}
$openssl_cmd = "($this->openSSL smime -sign -signer $this->myPublicCertFile -inkey $this->myPrivateKeyFile " .
"-outform der -nodetach -binary <<_EOF_\n$data\n_EOF_\n) | " .
"$this->openSSL smime -encrypt -des3 -binary -outform pem $this->paypalCertFile";
exec($openssl_cmd, $output, $error);
if (!$error) {
return implode("\n",$output);
} else {
return null;
}
}
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* @return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* @return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
* @return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* @return bool
* @throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost 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";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
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_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . $this->caCertFile);
}
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
?>
我不知道 PayPal 方面是否有任何更改,但现在使用上面的代码,在提交表单后,我在 PayPal 页面上收到以下错误:
X-PP-Simple-Handler: ?cmd=_dispatch-failed 状态: 200 内容长度: 382 internal_cmd=_dispatch-simple-handler&simple_handler_cmd=_dispatch-failed&reason=ERROR%20--%20exception%20during%20dispatch.THashException%3a% 20operator%5b%5d%20illegal%20on%20duplicate-okay%20hashtable%20Backtrace%3a%201935125b%201933c13f%2018a0cd5c%2018a05399%20100001af%20d70d033%20d7b01b0%2018a47a27%2018a28429%2018a2a53e%20807d42b%20f6b59647%20d7094e9&failed_application=webscr
谁能给我一些反馈或提示?
谢谢
解决方案
推荐阅读
- json - 在核心数据中存储 JSON (Swift)
- graph - 使用存储在共享首选项中的值的片段中的图形
- hyperlink - 是否可以从 Epub 内的外部链接打开灯箱?
- android - TextField 中的文本问题 - Android Jetpack Compose
- unity3d - Unity URP 无法覆盖虚函数
- sql - WPF DataGrid 问题 - 在 RowDetailsTemplate 中引用文本框
- flutter - 我无法更改下拉按钮中的提示文本
- python - 如何使用 python 将 2.7 GB gct 文件转换为数据框?
- reactjs - React Native - 使用 ref 的 TextInput 值(不受控制的组件)
- python - 条形图绘图问题:TypeError:'AxesSubplot' 对象不可迭代