网站向Sagepay提交加密代码工作,但现在服务器php升级后失败



我完成了我的网站的v.3Sagepay于今年4月升级,目前运行良好。

但是现在我的虚拟主机提供商已经将其PHP版本从5.2.4升级到5.5.9,这导致了网站的严重中断。

我已经设法修复了最戏剧性的(像所有的动态产品列表和详细信息页面显示空白),我留下了一个失败提交给Sagepay。

更确切地说,只要按下Submit按钮,就会出现一个页面,其中包含一个文本字符串,其中显示了处理提交到Sagepay的加密的functions.php页面中的大部分代码;并解密Sagepay的响应。(幸运的是,该字符串不包括加密密码。)提交当然不能进行了。

本页中的代码混合了以前版本的SagePay文档的脚本,混合或替换为版本3的更新脚本-事实上,我记得它在很大程度上使用了来自Stackoverflow贡献者的加密示例。

这是页面中的代码(我很抱歉,如果我遗漏了评论,这些评论主要来自SagePay -我不确定它是否不适合这里的帖子):

//************ NEW CRYPT STUFF COPIED FRON SAGEPAY KIT util.php
//DH added class definition as shown in stackoverflow page - trying to fix error when run, on line static private function etc
class DHclassInFunc{
/**
* PHP's mcrypt does not have built in PKCS5 Padding, so we use this.
*
* @param string $input The input string.
*
* @return string The string with padding.
*/
static protected function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";
// Pad input to an even block size boundary.
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}
return $input . $padd;
}
/**
* Remove PKCS5 Padding from a string.
*
* @param string $input The decrypted string.
*
* @return string String without the padding.
* @throws SagepayApiException
*/
static protected function removePKCS5Padding($input)
{
$blockSize = 16;
$padChar = ord($input[strlen($input) - 1]);
/* Check for PadChar is less then Block size */
if ($padChar > $blockSize)
{
throw new SagepayApiException('Invalid encryption string');
}
/* Check by padding by character mask */
if (strspn($input, chr($padChar), strlen($input) - $padChar) !=           $padChar)
{
throw new SagepayApiException('Invalid encryption string');
}
$unpadded = substr($input, 0, (-1) * $padChar);
/* Chech result for printable characters */
if (preg_match('/[[:^print:]]/', $unpadded))
{
throw new SagepayApiException('Invalid encryption string');
}
return $unpadded;
}
/**
* Encrypt a string ready to send to SagePay using encryption key.
*
* @param  string  $string  The unencrypyted string.
* @param  string  $key     The encryption key.
*
* @return string The encrypted string.
*/
static public function encryptAes($string, $key)
{
// AES encryption, CBC blocking with PKCS5 padding then HEX encoding.
// Add PKCS5 padding to the text to be encypted.
$string = self::addPKCS5Padding($string);
// Perform encryption with PHP's MCRYPT module.
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
// Perform hex encoding and return.
return "@" . strtoupper(bin2hex($crypt));
}
/**
* Decode a returned string from SagePay.
*
* @param string $strIn         The encrypted String.
* @param string $password      The encyption password used to encrypt the string.
*
* @return string The unecrypted string.
* @throws SagepayApiException
*/
static public function decryptAes($strIn, $password)
{
// HEX decoding then AES decryption, CBC blocking with PKCS5 padding.
// Use initialization vector (IV) set from $str_encryption_password.
$strInitVector = $password;
// Remove the first char which is @ to flag this is AES encrypted and HEX decoding.
$hex = substr($strIn, 1);
// Throw exception if string is malformed
if (!preg_match('/^[0-9a-fA-F]+$/', $hex))
{
throw new SagepayApiException('Invalid encryption string');
}
$strIn = pack('H*', $hex);
// Perform decryption with PHP's MCRYPT module.
$string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC, $strInitVector);
return self::removePKCS5Padding($string);
}
}
/* The getToken function.                                                                                                      **
** NOTE: A function of convenience that extracts the value from the     "name=value&name2=value2..." VSP reply string **
** Works even if one of the values is a URL containing the & or = signs. */
function getToken($thisString) {
// List the possible tokens
$Tokens = array(
"Status",
"StatusDetail",
"VendorTxCode",
"VPSTxId",
"TxAuthNo",
"Amount",
"AVSCV2", 
"AddressResult", 
"PostCodeResult", 
"CV2Result", 
"GiftAid", 
"3DSecureStatus", 
"CAVV" );
// Initialise arrays
$output = array();
$resultArray = array();
// Get the next token in the sequence
for ($i = count($Tokens)-1; $i >= 0 ; $i--){
// Find the position in the string
$start = strpos($thisString, $Tokens[$i]);
// If it's present
if ($start !== false){
// Record position and token name
$resultArray[$i]->start = $start;
$resultArray[$i]->token = $Tokens[$i];
}
}
// Sort in order of position
sort($resultArray);
// Go through the result array, getting the token values
for ($i = 0; $i<count($resultArray); $i++){
// Get the start point of the value
$valueStart = $resultArray[$i]->start + strlen($resultArray[$i]->token) + 1;
// Get the length of the value
if ($i==(count($resultArray)-1)) {
$output[$resultArray[$i]->token] = substr($thisString, $valueStart);
} else {
$valueLength = $resultArray[$i+1]->start - $resultArray[$i]->start -      strlen($resultArray[$i]->token) - 2;
$output[$resultArray[$i]->token] = substr($thisString, $valueStart, $valueLength);
}      
}
// Return the ouput array
return $output;
}
// Randomise based on time
function randomise() {
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
?>

我想提一下这个页面之前的一个问题,我认为这是相关的,也许可以帮助指出问题的根源——

在服务器尝试切换到新PHP版本后-产品显示全部消失-我恢复到旧版本的PHP(在测试期间允许恢复,但现在升级是最终的)。返回后,站点显示恢复正常,但Sagepay函数不能正常工作-尽管在这种情况下,Submit to Page工作正常,但当它击中function.php页面

时,响应失败。在这种情况下,错误消息引用了下面段中的'throw new SagepayApiException('Invalid encryption string');'行,这是在页面脚本的返回部分。

// Throw exception if string is malformed
if (!preg_match('/^[0-9a-fA-F]+$/', $hex))
{
throw new SagepayApiException('Invalid encryption string');
}
$strIn = pack('H*', $hex);

以我最低的php技能,特别是调试,在我看来,实际上它是在几行之前出现问题,而不是返回的crypt字符串本身有问题。

我从显示返回错误的页面上的url复制了crypt字符串,并通过硬编码返回字符串作为输入而不是$hex,对preg-match函数中的匹配字符串进行了测试,然后脚本运行超出了错误陷阱,而不是停在行'throw new SagepayApiException('无效加密字符串');'的其他实例

这让我得出结论,前面的部分有问题,即-

static public function decryptAes($strIn, $password)
{
// HEX decoding then AES decryption, CBC blocking with PKCS5 padding.
// Use initialization vector (IV) set from $str_encryption_password.
$strInitVector = $password;
// Remove the first char which is @ to flag this is AES encrypted and HEX decoding.
$hex = substr($strIn, 1);

然而,我不能弄清楚为什么会这样,因为这个页面中的代码没有被触摸,因此应该像以前一样工作,在临时切换到php 5.5之前。X . X .

最后我想再试一件事:在服务器php版本更改期间,服务器自动禁用了我的站点php。(除了它可以用来改变服务器运行的php版本的某些默认特征外,我对它知之甚少)。我已经恢复了php.ini文件,但现在有相当多的禁用2.2的踢在那个位置。

试试别的怎么样?ZAP,问题解决了。

然而,我不能看到(或者更确切地说理解)是否有任何东西在新的默认5.5.9服务器ini文件设置,这可能是加密代码的最新问题的根源,除了我的本地php.ini文件设置default_charset为iso-8859-1 2.2.4,而5.5.9的默认值是utf-8。

我现在已经在5.5.9 ini文件中设置了default_charset为iso-8859-1,但是尽管它已经固定了£s显示为?在网站内容中,它对SagePay提交错误没有影响。

有什么建议来解决这个严重的问题(网站目前无法处理任何付款…)?

UPDATE 23/10/16 -问题已经改变;但仍然需要帮助

提交到Sagepay现在解决了,但我仍然需要帮助,因为现在我无法处理Sagepay的响应。响应从SagePay发送并由我的响应文件接收,但是它在处理返回的加密字符串期间导致错误。

结果,用户的浏览器窗口似乎挂起-它是空白的-用户不能返回到我的网站。由于解密过程中出现错误,网站对支付结果的自动处理都没有启动。

错误发生在function .php文件的行,其中包含我已经在这个问题中发布的代码。它在第184行生成,错误是:

PHP Fatal error:  Class 'SagepayApiException' not found in /web/sites/user/3/84/42307/public/www/My_folder/protx/functions.php on line 184

第184行是下面一行:

throw new SagepayApiException('Invalid encryption string');

:

// Throw exception if string is malformed
if (!preg_match('/^[0-9a-fA-F]+$/', $hex))
{
throw new SagepayApiException('Invalid encryption string');
}
$strIn = pack('H*', $hex);

在致命错误之前,web服务器日志中有这样一行:

PHP Notice:  Undefined variable: crypt in /web/sites/user/3/84/42307/public/www/myfolder/protx/completed.php on line 30

completed.php是返回url中的文件,Sagepay响应将指向该文件(其中包含functions.php文件)。

complete .php文件中的第30行是:

$Decoded = DHclassInFunc::decryptAes($crypt,$EncryptionPassword);

我整个周末都在做这件事,昨晚我把提交给Sageway的内容再次提交给了Sageway,我觉得我快到了(至少网站又可以接受付款了)。

顺便说一下,这方面的修复关键是替换了加密文件之前的文件中的许多函数htmlspecialchars的实例,以便它们现在使用php 5.5.9所需的新语法,可以包括字符集,如下面的例子所示:
htmlspecialchars($rs->Fields($kartProps['Korders']['orders']['email']), ENT_COMPAT,'ISO-8859-1', true);

我还通过.ini文件中的本地character_set设置将php.ini文件中的默认UTF-8编码更改为ISO-8859-1。

我的推理是,在Sagepay响应文件的解密中仍然发生某种字符集冲突,这导致preg_match函数失败。

我已经绞尽脑汁想弄清楚到底发生了什么,如果有任何建议,我将不胜感激。

解密脚本不工作,因为它们没有从Sagepay发送的响应中的url内容中接收任何数据。

此响应应该在文件'completed.php'中接收,然后将响应字符串传递给包含解密代码的'functions.php'。

在completed.php文件中,提取了php 5.2.4下使用的url内容的下面一行:

$Decoded = DHclassInFunc::decryptAes($crypt,$EncryptionPassword);  this worked in 5.5.3 but not 5.5.59

我把它改成:

$Decoded = DHclassInFunc::decryptAes(($_GET['crypt']),$EncryptionPassword);// HURRAH ! finally the scripts get the url contents so now works in php 5.5.9.

可能是一个称职的php编码员的基础;但至少我做到了。

SOLVED

解密脚本不工作,因为它们没有从Sagepay发送的响应中的url内容中接收任何数据。

此响应应该在文件'completed.php'中接收,然后将响应字符串传递给包含解密代码的'functions.php'。

在completed.php文件中,提取了php 5.2.4下使用的url内容的下面一行:

$Decoded = DHclassInFunc::decryptAes($crypt,$EncryptionPassword);  this worked in 5.5.3 but not 5.5.59

我把它改成:

$Decoded = DHclassInFunc::decryptAes(($_GET['crypt']),$EncryptionPassword);// HURRAH ! finally the scripts get the url contents so now works in php 5.5.9.

可能是一个称职的php编码员的基础;但至少我做到了。

最新更新