Php IOS收据验证错误21002

Php IOS收据验证错误21002,php,ios,in-app-purchase,applepay,receipt-validation,Php,Ios,In App Purchase,Applepay,Receipt Validation,我正在尝试在服务器端使用收据验证。一切正常,但有时我会觉得奇怪:10次验证是可以的,但在11次时我得到21002个错误。我不知道该怎么办。有时,当我在启动应用程序后第一次验证收据时,会出现错误21002 应用程序端: func validateReceipt(productID: String) { let receipt = NSData(contentsOfURL: NSBundle.mainBundle().appStoreReceiptURL!)! let recei

我正在尝试在服务器端使用收据验证。一切正常,但有时我会觉得奇怪:10次验证是可以的,但在11次时我得到21002个错误。我不知道该怎么办。有时,当我在启动应用程序后第一次验证收据时,会出现错误21002

应用程序端:

func validateReceipt(productID: String) {

    let receipt = NSData(contentsOfURL: NSBundle.mainBundle().appStoreReceiptURL!)!

    let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))

    let request = NSMutableURLRequest(URL: NSURL(string: "my_server_url")!)

    let session = NSURLSession.sharedSession()
    request.HTTPMethod = "POST"

    request.HTTPBody = receiptdata.dataUsingEncoding(NSUTF8StringEncoding)

    let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in

        let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary

        if (error != nil) {
            print(error!.localizedDescription)
            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Error could not parse JSON: '\(jsonStr)'")
        }
        else {
            if let parseJSON = json {
                 if String(parseJSON["status"]! == "ok" {
                     //do something
                     print("Validate OK")
                        }else{
                            print("Validate NOK")
                    }
            }
            else {
                let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
                print("Receipt Error: \(jsonStr)")
            }
        }
    })

    task.resume()
}
服务器端php脚本:

function getReceiptData($receipt)
{
$endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';

$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $receipt);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
$msg = $response.' - '.$errno.' - '.$errmsg;
echo $response;
}

foreach ($_POST as $key=>$value){
$newcontent .= $key.' '.$value;
}

$new = trim($newcontent);
$new = trim($newcontent);
$new = str_replace('_','+',$new);
$new = str_replace(' =','==',$new);

if (substr_count($new,'=') == 0){
if (strpos('=',$new) === false){
    $new .= '=';
}
}

$new = '{"receipt-data":"'.$new.'"}';
$info = getReceiptData($new);
我所做的一切都是基于榜样


所以,有时我觉得应用程序发送到服务器端的回执是错误的,php脚本无法解析它,我收到21002错误状态。有什么建议吗?

代码21002表示您发送给苹果的JSON包含您的共享机密和收据数据“格式不正确”或不是苹果想要的格式

下面是一个带有后续错误代码及其含义的屏幕截图

我就是这样做的(目标C和局部验证)


尝试从
收据中删除“\n”和“\r”字符,并将“+”替换为“%2B”,然后再将其发送到服务器。大概是这样的:

 NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
 NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
 NSString *receiptDataString = [receipt base64EncodedStringWithOptions:0];
 receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
 receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
 receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
 NSString *postDataString = [NSString stringWithFormat:@"receipt-data=%@", receiptDataString];
 NSString *length = [NSString stringWithFormat:@"%lu", (unsigned long)[postDataString length]];
 [request setValue:length forHTTPHeaderField:@"Content-Length"];
 [request setHTTPBody:[postDataString dataUsingEncoding:NSASCIIStringEncoding]];

这已经很晚了,所以您现在很可能已经解决了这个问题-但是我注意到了一个输入错误-您在
条件==“ok”
中遗漏了一个“)”来转换字符串:


都是关于NSDatabase64编码选项的。使用类型
encodingendlinewithcareereturn
而不是
0

只要换一行就行了

let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
这条线

let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)

我自己也试过了,效果很好。

收据数据已经用base64编码了。指


在第10行中,我验证了收据,这是正常的,但在第11行它失败了。怎么可能?您是否实现了自动更新?不需要密码。:)对我有效的方法是在PHP代码中替换:$new='{“收据数据”:“.$new.”“}”;这样:$new=json_encode(“{”接收数据“:“.$new.”“}”);我假设你的Swift代码是正确的。@Heitor回答错了。你找到解决方案了吗?是的,我找到了,我的应用程序正在正确验证收据。你为什么说我的评论/回答是错的?@Heitor:如果我错了,请纠正我,但我认为你的意思是
json\u encode([“收据数据”=>$new])
。。。在你的评论中,你已经用JSON编码了一个JSON字符串。老实说,我已经不记得我发表评论时的上下文了,但是你试过那个代码吗?我现在所记得的是,在我的APNS完全开始工作之前,我所面临的最后一个挑战是UTF-8问题,可能是由于PHP 5.6+升级,当时我使用json_last_error()跟踪错误。我希望它能对您有用。我尝试过,但在沙盒模式下仍然出现上述错误。该解决方案确实对我有效,尽管处理字符串的其他方面随后以新的不同方式损坏了收据。:-)OBACTIVE-C:
NSString*encodedReceipt=[appReceipt base64EncodedStringWithOptions:[NSDatabase64EncodingEndlineWithCarineReturn]+1这是唯一提到将
+
替换为
%2B
的答案,这是罪魁祸首。。。接收端的PHP将
+
解释为一个空格(在URL语义中),它打破了base64编码。我非常感谢您,这真的救了我一命!花了3个小时摆弄正在发生的事情!在url编码post参数时,应提供“+”编码。如果您需要多部分/表单数据,我认为编码“+”应该是不必要的,@Jaybo-answer应该足够了
$receipt_data = "MII.................KY\/6oc9w==";

$data = "{\"receipt-data\":\"$receipt_data\"}";

$url = "https://buy.itunes.apple.com/verifyReceipt";        // if use this to test sandbox will return "{"status":21007}"
//$url = "https://sandbox.itunes.apple.com/verifyReceipt";  // for sandbox

var_dump(post($url,$data));

function post($url, $data, $headerArray = array())
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    if (array() === $headerArray)
        curl_setopt($curl, CURLOPT_HTTPHEADER,["Content-type:application/json;charset='utf-8'","Accept:application/json"]);

    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}