我创建了一个类来处理应用程序内购买的购买以及验证收据.前一段时间我曾经在SKPaymentTransaction上使用transactionReceipt属性,但已经更新了我的代码,现在在[NSBundle mainBundle]上使用了appStoreReceiptURL.

基本上似乎我的收据是以可接受的方式发送到Apple的服务器,但我一直得到21002的状态代码.在自动续订订阅中我知道这意味着收据不是可接受的格式,但我有不知道这个状态对于应用程序内购买收据的意义.

以下是验证收据的本地方法:

/**

* Validates the receipt.

*

* @param transaction The transaction triggering the validation of the receipt.

*/

- (void)validateReceiptForTransaction:(SKPaymentTransaction *)transaction

{

// get the product for the transaction

IAPProduct *product = self.internalProducts[transaction.payment.productIdentifier];

// get the receipt as a base64 encoded string

NSData *receiptData = [[NSData alloc] initWithContentsOfURL:[NSBundle mainBundle].appStoreReceiptURL];

NSString *receipt = [receiptData base64EncodedStringWithOptions:kNilOptions];

NSLog(@"Receipt: %@", receipt);

// determine the url for the receipt verification server

NSURL *verificationURL = [[NSURL alloc] initWithString:IAPHelperServerBaseURL];

verificationURL = [verificationURL URLByAppendingPathComponent:IAPHelperServerReceiptVerificationComponent];

NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:verificationURL];

urlRequest.HTTPMethod = @"POST";

NSDictionary *httpBody = @{@"receipt" : receipt,

@"sandbox" : @(1)};

urlRequest.HTTPBody = [NSKeyedArchiver archivedDataWithRootObject:httpBody];

[NSURLConnection sendAsynchronousRequest:urlRequest

queue:[[NSOperationQueue alloc] init]

completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)

{

// create a block to be called whenever a filue is hit

void (^failureBlock)(NSString *failureMessage) = ^void(NSString *failureMessage)

{

[[NSOperationQueue mainQueue] addOperationWithBlock:

^{

// log the failure message

NSLog(@"%@", failureMessage);

// if we have aready tried refreshing the receipt then we close the transaction to avoid loops

if (self.transactionToValidate)

product.purchaseInProgress = NO,

[[SKPaymentQueue defaultQueue] finishTransaction:transaction],

[self notifyStatus:@"Validation failed." forProduct:product],

self.transactionToValidate = nil;

// if we haven't tried yet, we'll refresh the receipt and then attempt a second validation

else

self.transactionToValidate = transaction,

[self refreshReceipt];

}];

};

// check for an error whilst contacting the server

if (connectionError)

{

failureBlock([[NSString alloc] initWithFormat:@"Failure connecting to server: %@", connectionError]);

return;

}

// cast the response appropriately

NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

// parse the JSON

NSError *jsonError;

NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];

// if the data did not parse correctly we fail out

if (!json)

{

NSString *responseString = [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode];

NSString *failureMessage = [[NSString alloc] initWithFormat:@"Failure parsing JSON: %@\nServer Response: %@ (%@)",

data, responseString, @(httpResponse.statusCode)];

failureBlock(failureMessage);

return;

}

// if the JSON was successfully parsed pull out status code to check for verification success

NSInteger statusCode = [json[@"status"] integerValue];

NSString *errorDescription = json[@"error"];

// if the verification did not succeed we fail out

if (statusCode != 0)

{

NSString *failureMessage = [[NSString alloc] initWithFormat:@"Failure verifying receipt: %@", errorDescription];

failureBlock(failureMessage);

}

// otherwise we have succeded, yay

else

NSLog(@"Successfully verified receipt."),

[self provideContentForCompletedTransaction:transaction productIdentifier:transaction.payment.productIdentifier];

}];

}

服务器上重要的PHP函数执行此操作:

/**

* Validates a given receipt and returns the result.

*

* @param receipt Base64-encoded receipt.

* @param sandbox Boolean indicating whether to use sandbox servers or production servers.

*

* @return Whether the reciept is valid or not.

*/

function validateReceipt($receipt, $sandbox)

{

// determine url for store based on if this is production or development

if ($sandbox)

$store = 'https://sandbox.itunes.apple.com/verifyReceipt';

else

$store = 'https://buy.itunes.apple.com/verifyReceipt';

// set up json-encoded dictionary with receipt data for apple receipt validator

$postData = json_encode(array('receipt-data' => $receipt));

// use curl library to perform web request

$curlHandle = curl_init($store);

// we want results returned as string, the request to be a post, and the json data to be in the post fields

curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);

curl_setopt($curlHandle, CURLOPT_POST, true);

curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $postData);

$encodedResponse = curl_exec($curlHandle);

curl_close($curlHandle);

// if we received no response we return the error

if (!$encodedResponse)

return result(ERROR_VERIFICATION_NO_RESPONSE, 'Payment could not be verified - no response data. This was sandbox? ' . ($sandbox ? 'YES' : 'NO'));

// decode json response and get the data

$response = json_decode($encodedResponse);

$status = $response->{'status'};

$decodedReceipt = $response->{'receipt'};

// if status code is not 0 there was an error validation receipt

if ($status)

return result(ERROR_VERIFICATION_FAILED, 'Payment could not be verified (status = ' . $status . ').');

// log the returned receipt from validator

logToFile(print_r($decodedReceipt, true));

// pull out product id, transaction id and original transaction id from infro trurned by apple

$productID = $decodedReceipt->{'product_id'};

$transactionID = $decodedReceipt->{'transaction_id'};

$originalTransactionID = $decodedReceipt->{'original_transaction_id'};

// make sure product id has expected prefix or we bail

if (!beginsWith($productID, PRODUCT_ID_PREFIX))

return result(ERROR_INVALID_PRODUCT_ID, 'Invalid Product Identifier');

// get any existing record of this transaction id from our database

$db = Database::get();

$statement = $db->prepare('SELECT * FROM transactions WHERE transaction_id = ?');

$statement->bindParam(1, $transactionID, PDO::PARAM_STR, 32);

$statement->execute();

// if we have handled this transaction before return a failure

if ($statement->rowCount())

{

logToFile("Already processed $transactionID.");

return result(ERROR_TRANSACTION_ALREADY_PROCESSED, 'Already processed this transaction.');

}

// otherwise we insert this new transaction into the database

else

{

logToFile("Adding $transactionID.");

$statement = $db->prepare('INSERT INTO transactions(transaction_id, product_id, original_transaction_id) VALUES (?, ?, ?)');

$statement->bindParam(1, $transactionID, PDO::PARAM_STR, 32);

$statement->bindParam(2, $productID, PDO::PARAM_STR, 32);

$statement->bindParam(3, $originalTransactionID, PDO::PARAM_STR, 32);

$statement->execute();

}

return result(SUCCESS);

}

正在执行的PHP脚本是:

$receipt = $_POST['receipt'];

$sandbox = $_POST['sandbox'];

$returnValue = validateReceipt($receipt, $sandbox);

header('content-type: application/json; charset=utf-8');

echo json_encode($returnValue);

解决方法:

将PHP与我的(我知道有效)进行比较很困难,因为我使用的是HTTPRequest,而不是原始的curl API.但是,在我看来,您将“{receipt-data:..}”JSON字符串设置为POST数据中的字段而不是原始POST数据本身,这正是我的代码所做的.

curl_setopt($curlHandle, CURLOPT_POST, true);

curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $postData); // Possible problem

$encodedResponse = curl_exec($curlHandle);

相比:

$postData = '{"receipt-data" : "'.$receipt.'"}'; // yay one-off JSON serialization!

$request = new HTTPRequest('https://sandbox.itunes.apple.com/verifyReceipt', HTTP_METH_POST);

$request->setBody($postData); // Relevant difference...

$request->send();

$encodedResponse = $request->getResponseBody();

我已经更改了我的变量名称,使它们与您的示例匹配.

标签:php,ios,objective-c,receipt

来源: https://codeday.me/bug/20190624/1281575.html

status 21002 php,php – 验证appReceiptStoreURL返回21002状态相关推荐

  1. ajax提交手机号到php,ajax怎样申请手机号到数据库验证并且返回数据的状态值

    这次给大家带来ajax怎样申请手机号到数据库验证并且返回数据的状态值,ajax申请手机号到数据库验证并且返回数据状态值的注意事项有哪些,下面就是实战案例,一起来看一下. 本文实例为大家分享了ajax提 ...

  2. sendrequest ajax数据返回,jquery ajax 还没有调用send()方法 返回的状态码XMLHttpRequest.status 是0 ,怎么解决?...

    jquery ajax 还没有调用send()方法 返回的状态码XMLHttpRequest.status 是0 ,怎么解决?0 嗲女错cbn2013.04.29浏览451次分享举报 function ...

  3. 统一登录验证统一返回格式统一异常处理的实现

    统一登录验证&统一返回格式&统一异常处理的实现 一.用户登录权限效验 1.1 最初的用户登录验证 1.2 Spring AOP 用户统一登录验证的问题 1.3 Spring 拦截器 1 ...

  4. 【转】“数据提供程序或其他服务返回 E_FAIL 状态” 或者 Data provider or other service returned an E_FAIL status.

    "数据提供程序或其他服务返回 E_FAIL 状态"  或者  Data provider or other service returned an E_FAIL status. 使 ...

  5. php 503解决办法,php设置页面返回503状态-php设置503http状态的方法-吾爱编程网

    最近有小伙伴问PHP的网页如何返回503的代码,其实返回这些状态码在开发的时候会经常用到,接下来吾爱编程为大家介绍一下php设置页面返回503状态方法,有需要的小伙伴可以参考一下: 1.503状态码定 ...

  6. 详细Http状态查询返回 HTTP 状态代码以响应请求

    如果向您的服务器发出了某项请求要求显示您网站上的某个网页,那么,您的服务器会返回 HTTP 状态代码以响应该请求. 如果向您的服务器发出了某项请求要求显示您网站上的某个网页(例如,当用户通过浏览器访问 ...

  7. 接口请求返回的状态码总览

    HTTP状态码(英语:HTTP Status Code),用以表示网页服务器超文本传输协议响应状态的3位数字代码. 作用:服务器告诉客户端当前请求响应的状态,通过状态码就能判断和分析服务器的运行状态 ...

  8. axios请求失败,response.data返回的状态码及错误信息获取

    axios请求失败,后端接口返回的状态码及错误信息获取 使用封装的elementUI后台框架,后台框架自定义封装并返回的code码转态(全部的返回数据,如下所示): 浏览器查看:返回的 error 信 ...

  9. vue 下载文件流和捕获后端返回的状态码和错误信息的方法

    文件流下载需要注意的是 responseType: 'blob' ,否则下载的文件不能正确打开.但是当数据库返回400时,捕获不到error的错误信息,因为responseType设置了固定的返回格式 ...

最新文章

  1. igstk 学习笔记
  2. python 难度-python上手难度算较低
  3. PM——视屏操作软件
  4. python 图形界面库对比
  5. c# 联合halcon 基于相关性 模板匹配_机器视觉之halcon入门(5)-字符识别exe生成...
  6. Windows内核函数
  7. 为Tueri.io构建React图像优化组件
  8. 怎么判断一个字符串的最长回文子串是否在头尾_最长回文字串/子序列问题(leetcode5,9,519)
  9. [skill] C与C++对于类型转换的验证
  10. 无缝世界网游服务器架构的设计思路
  11. openresty查看log
  12. MATLAB教程(一)matlib介绍
  13. WPF 程序加载PGIS性能问题
  14. 蒙特卡罗类型概率算法
  15. ember.js mysql_Ember.js 入门指南——控制器(controller)
  16. geth 搭建 私有链节点
  17. linux运维工作内容及岗位要求
  18. 微信小程序解析后台返回的html格式
  19. orm之peewee
  20. 【解决】无法为JSP编译类: Enumeration cannot be resolved to a variable

热门文章

  1. 长安大学 计算机专业分数线,2018长安大学录取分数线 历年分数线及专业排名
  2. 将虚拟机网络适配器改为仅主机模式,Vmware弹出“仅主机模式适配器驱动程序似乎未运行”
  3. class-dump 和 iOSOpenDev 的使用
  4. 06世界杯8强备忘录
  5. android 定时器封装
  6. B2B电子竞价有什么好处?
  7. iPad和iPhone各机型屏幕长宽和长宽比
  8. ANSYS多相流的单向流固耦合(2022R1版)
  9. php调度服务,cron自动调度服务配置详解
  10. 现代农业|AIRIOT智慧农业管理解决方案