我需要使用PHP验证在Windows 8应用程序服务器端进行的应用内购买。 MSDN的documentation page仅在C#中有一个例子。现在我花了一整天的时间来寻找一种在PHP中实现它的方法。没有成功。在整个互联网上,只有这个主题的.NET例子。
我发现了一些有关已签名XML和x509的部分信息,有些库(xmlseclibs - 无用,使用不支持sha256的openssl_ *函数; phpseclib - 看起来很有前景,但是他们的文档和示例很差,没有任何帮助)。< / p>
有可能在不学习有关签名XML,RSA和x509的所有内容的情况下以某种方式完成吗?现在我几乎阅读了所有内容,但到处都是关于编码的信息。没有关于验证的事。
答案 0 :(得分:1)
我设法使用xmlseclibs库来验证WP8 IAP收据。
此外,您需要启用php curl。
do {
$doc = new DOMDocument();
$xml = $_POST['receipt_data']; // your receipt xml here!
// strip unwanted chars - IMPORTANT!!!
$xml = str_replace(array("\n","\t", "\r"), "", $xml);
//some (probably mostly WP8) receipts have unnecessary spaces instead of tabs
$xml = preg_replace('/\s+/', " ", $xml);
$xml = str_replace("> <", "><", $xml);
$doc->loadXML($xml);
$receipt = $doc->getElementsByTagName('Receipt')->item(0);
$certificateId = $receipt->getAttribute('CertificateId');
$ch = curl_init("https://lic.apps.microsoft.com/licensing/certificateserver/?cid=$certificateId");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$publicKey = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
if ($errno != 0) {
$verifyFailed = true;
break;
}
// Verify xml signature
require('./xmlseclibs.php');
$objXMLSecDSig = new XMLSecurityDSig();
$objDSig = $objXMLSecDSig->locateSignature($doc);
if (!$objDSig) {
$verifyFailed = true;
break;
}
try {
$objXMLSecDSig->canonicalizeSignedInfo();
$retVal = $objXMLSecDSig->validateReference();
if (!$retVal) {
throw new Exception("Error Processing Request", 1);
}
$objKey = $objXMLSecDSig->locateKey();
if (!$objKey) {
throw new Exception("Error Processing Request", 1);
}
$key = NULL;
$objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
if (! $objKeyInfo->key && empty($key)) {
$objKey->loadKey($publicKey);
}
if (!$objXMLSecDSig->verify($objKey)) {
throw new Exception("Error Processing Request", 1);
}
} catch (Exception $e) {
$verifyFailed = true;
break;
}
$productReceipt = $doc->getElementsByTagName('ProductReceipt')->item(0);
$prodictId = $productReceipt->getAttribute('ProductId');
$purchaseDate = $productReceipt->getAttribute('PurchaseDate');
} while(0);
if ($verifyFailed) {
// invalid receipt
} else {
// valid receipt
}
答案 1 :(得分:-1)
为自己说话。我喜欢phpseclib的“构建你自己的例子”文档的方法。
那就是说,我不认为在这种情况下真的可以使用phpseclib。所以你有SignatureValue标签。那个签名虽然涵盖了什么?使用XML签名,我的理解是签名涵盖了XML的规范化形式。 xmlseclibsnormalizes一个XML文档,但phpseclib没有,因为它是一个加密的lib - 而不是一个XML库。