您必须以某种方式创建一个流程,以确保用户按照正确的顺序执行所需的步骤,并防止他跳出这个顺序。
跟踪用户会话中的步骤似乎是很自然的事情。如果会话不允许请求的步骤,请将他重定向到其他地方而不是询问贝宝。
豪华版是您实现了一个状态机,以便以后更容易改进。状态机的缺点是一开始看起来开销很大,如果您最初采用不同的方法,以后实现起来会很麻烦。这就是为什么从一开始就考虑使用一个很重要的原因。
如果您想稍后添加另一个支付提供商怎么办?为此可以轻松扩展状态机 - 其他任何事情都可能是一团糟。
编辑:实际上,贝宝希望您在用户回到您的网站后发送给他们的唯一内容是您要收取的金额。此信息可以通过将其放入您发送到贝宝的返回 url 中来传递。尝试在那里添加一些校验和以防止数据错误和容易被篡改(如果金额不正确,Paypal 会让过程失败),你基本上就完成了。根本不需要会话。
Edit2:这是我的代码的摘录,它定义了贝宝第一步的 nvp 参数。您也需要内部必要的身份验证内容。
public function preparePayment(...) {
$nvp = array(
'METHOD' => 'SetExpressCheckout',
'VERSION' => '52.0',
'RETURNURL' => 'https://'.$request->server['HTTP_HOST'].'/'.$request->getLanguage().'/paypal/success/'.$this->hashAmount($amount),
'CANCELURL' => 'https://'.$request->server['HTTP_HOST'].'/'.$request->getLanguage().'/paypal/cancel',
'CURRENCYCODE' => $amount->getCurrency(),
'AMT' => number_format($amount->getAmount(), 2, '.', ''),
'ITEMAMT' => number_format($amount->getNettoAmount(), 2, '.', ''),
'TAXAMT' => number_format($amount->getVatAmount(), 2, '.', ''),
'PAYMENTACTION' => 'Sale',
'LOCALECODE' => strtoupper($request->getLanguage())
);
}
protected function hashAmount(Currency_Class $amount) {
return urlencode(
sprintf(
'%s-%s-%s-%u',
number_format($amount->getNettoAmount(), 2, '', ''),
number_format($amount->getVatAmount(), 2, '', ''),
strtoupper($amount->getCurrency()),
$this->makeChecksumString(number_format($amount->getNettoAmount(), 2, '', ''), strtoupper($amount->getCurrency()))
)
);
}
protected function makeChecksumString($amount, $currency) {
return crc32(sprintf('%sSaltValue%s', $amount, $currency));
}
protected function dehashAmount($string) {
$parts = array();
$found = preg_match('/^(\d+)\-(\d+)\-([A-Z]+)\-(\d+)$/', $string, $parts);
if ($found) {
$check = sprintf('%u', $this->makeChecksumString($parts[1], $parts[3]));
if ($check == $parts[4]) {
$netto = floatval(substr($parts[1], 0, -2) .'.'. substr($parts[1], -2));
$vat = floatval(substr($parts[2], 0, -2) .'.'. substr($parts[2], -2));
}
}
return ...
}