先来简单介绍一下何为苹果内购
众所周知,苹果的支付流程大致如下
1.在苹果商店添加商品(并且审核通过),
2.用户购买商品—》提交接口到服务端(服务端创建订单)——》返回数据(苹果内购产品的id)
3.app获取到苹果内购的id,提交产品到苹果商店(一般情况下苹果商店会和支付宝绑定)
4.苹果商店返回支付凭证——》提交到服务端(验证支付是否成功或失败)
5.更新订单状态
好了,闲话不多说直接开始给大家上代码
以下是苹果商店返回的支付凭证(仅供参考)
{
"signature" = "A3CFuTtYr91pW6e4Z4bHJMa9zTuQepf1Mhe/KFq+k8HOkkjmhTI42qUNzfw+sBJnHFXdWyuNSh9PKQ9tQkLBN+QYN725qQq9oejxh5UyChUV9Td9l03FPIFr2p7KNE3r6xmukJi+jK7PG+7iRaE72iFD4ktMEbwjxyBRVYFUcW475EP4ivoWzm9vFN7ipXmKu70W5BXjnmIMbf8KimRTEubZx5kQf4tUy6nIOxh2zajVzN265enHOcM74x1/FWdekUbpg2qYzqFD80+yk2S64KKBTU2enFRoPaJM+UwoiRiaZS0lep0d41+owf3KB7tUc5yhKh9Rx5/9eqppy4sUiPgAAAWAMIIFfDCCBGSgAwIBAgIIDutXh+eeCY0wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMTEzMDIxNTA5WhcNMjMwMjA3MjE0ODQ3WjCBiTE3MDUGA1UEAwwuTWFjIEFwcCBTdG9yZSBhbmQgaVR1bmVzIFN0b3JlIFJlY2VpcHQgU2lnbmluZzEsMCoGA1UECwwjQXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApc+B/SWigVvWh+0j2jMcjuIjwKXEJss9xp/sSg1Vhv+kAteXyjlUbX1/slQYncQsUnGOZHuCzom6SdYI5bSIcc8/W0YuxsQduAOpWKIEPiF41du30I4SjYNMWypoN5PC8r0exNKhDEpYUqsS4+3dH5gVkDUtwswSyo1IgfdYeFRr6IwxNh9KBgxHVPM3kLiykol9X6SFSuHAnOC6pLuCl2P0K5PB/T5vysH1PKmPUhrAJQp2Dt7+mf7/wmv1W16sc1FJCFaJzEOQzI6BAtCgl7ZcsaFpaYeQEGgmJjm4HRBzsApdxXPQ33Y72C3ZiB7j7AfP4o7Q0/omVYHv4gNJIwIDAQABo4IB1zCCAdMwPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLXd3ZHIwNDAdBgNVHQ4EFgQUkaSc/MR2t5+givRasdasdN9Y82Xe0rBIUwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIJxcJqbYYYIvs67r2R1nFUlSjtzCCAR4GA1UdIASCARUwggERMIIBDQYKKoZIhvdjZAUGATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMA4GA1UdDwEB/wQEAwIHgDAQBgoqhkiG92NkBgsBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEADaYb0y4941srB25ClmzT6IxDMIJf4FzRjb69D70a/CWS24yFw4BZ3+Pi1y4FFKwN27a4/vw1LnzLrRdrjn8f5He5sWeVtBNephmGdvhaIJXnY4wPc/zo7cYfrpn4ZUhcoOAoOsAQNy25oAQ5H3O5yAX98t5/GioqbisB/KAgXNnrfSemM/j1mOC+RNuxTGf8bgpPyeIGqNKX86eOa1GiWoR1ZdEWBGLjwV/1CKnPaNmSAMnBjLP4jQBkulhgwHyvj3XKablbKtYdaG6YQvVMpzcZm8w7HHoZQ/Ojbb9IYAYMNpIr7N4YtRHaLSPQjvygaZwXG56AezlHRTBhL8cTqA==";
"purchase-info" = "ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDE5LTAyLTI3IDE4OjA1OjUwIEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInF1YW50aXR5IiA9ICIxIjsKCSJ1bmlxdWUtdmVuZG9yLWlkZW50aWZpZXIiID0gIkQ3MDExMzU1LTZGNkYtNDY3Mi1CQjk1LTAwMDlDNzlFNjA2NCI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZS1tcyIgPSAiMTU1MTMxOTU1MDAwMCI7CgkiZXhwaXJlcy1kYXRlLWZvcm1hdHRlZCIgPSAiMjAxOS0wMi0yOCAwNDowNjo0OSBFdGMvR01UIjsKCSJpcy1pbi1pbnRyby1vZmZlci1wZXJpb2QiID0gImZhbHNlIjsKCSJwdXJjaGFzZS1kYXRlLW1zIiA9ICIxNTUxMzIzMjA5NDIxIjsKCSJleHBpcmVzLWRhdGUtZm9ybWsadasdasddF0dGVkLXBzdCIgPSAiMjAxOS0wMi0yNyAyMDowNjo0OSBBbWVyaWNhL0xvc19BbmdlbGVzIjsKCSJpcy10cmlhbC1wZXJpb2QiID0gImZhbHNlIjsKCSJpdGVtLWlkIiA9ICIxNDUyNzQyMjk5IjsKCSJ1bmlxdWUtaWRlbnRpZmllciIgPSAiZGJmYzc4MDY2NjJhMTNmNGNmZmNmYjQ0NWJjNjg1ZmM2OTYzMjViMiI7Cgkib3JpZ2luYWwtdHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDA1MDYzNTAyNTIiOwoJImV4cGlyZXMtZGF0ZSIgPSAiMTU1MTMyNjgwOTQyMSI7CgkidHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDA1MDYzNjQ2NjAiOwoJImJ2cnMiID0gIjciOwoJIndlYi1vcmRlci1saW5lLWl0ZW0taWQiID0gIjEwMDAwMDAwNDI5NjkyOTQiOwoJInZlcnNpb24tZXh0ZXJuYWwtaWRlbnRpZmllciIgPSAiMCI7CgkiYmlkIiA9ICJjb20uY2hyaXN0aWFuaXR5LmFwcHAiOwoJInByb2R1Y3QtaWQiID0gIjQiOwoJInB1cmNoYXNlLWRhdGUiID0gIjIwMTktMDItMjggMDM6MDY6NDkgRXRjL0dNVCI7CgkicHVyY2hhc2UtZGF0ZS1wc3QiID0gIjIwMTktMDItMjcgMTk6MDY6NDkgQW1lcmljYS9Mb3NfQW5nZWxlcyI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZSIgPSAiMjAxOS0wMi0yOCAwMjowNTo1MCBFdGMvR01UIjsKfQ==";
"environment" = "Sandbossdasdx";
"pod" = "100";
"signing-status" = "0";
}
以下是php服务端验证支付凭证的代码
public function upIosApp(Request $request)
{
//其中 receipt_data 表示支付凭证
$redata = $request->only('receipt_data');
$receipt_data = $redata['receipt_data'];
// 验证参数
if (strlen($receipt_data)<20){
$result=array(
'status'=>false,
'message'=>'非法参数'
);
return json_encode($result);
}
// 请求验证
$data = $this->acurl($receipt_data);
// 如果是沙盒数据 则验证沙盒模式
if($data['status']=='21007'){
// 请求验证
$data = $this->acurl($receipt_data, 1);
$data['sandbox'] = '1';
}
if (isset($_GET['debug'])) {
exit(json_encode($data));
}
// 判断是否购买成功
if(intval($data['status'])===0){
。。。。处理更新订单状态的逻辑。。。。。
$result=array(
'status'=>true,
'message'=>‘购买成功’,
);
}else{
$result=array(
'status'=>false,
'message'=>'购买失败 status:'.$data['status']
);
}
return json_encode($result);
}
/**
* 21000 App Store不能读取你提供的JSON对象
* 21002 receipt-data域的数据有问题
* 21003 receipt无法通过验证
* 21004 提供的shared secret不匹配你账号中的shared secret
* 21005 receipt服务器当前不可用
* 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
* 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
* 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
*/
function acurl($receipt_data, $sandbox=0){
//小票信息
$secret = "e947476b619f4db88abc37757b61f03c";// APP固定密钥,在itunes中获取
**此处是重点,重点,重点(需将凭证转为base64格式)**
$POSTFIELDS = array("receipt-data" => $receipt_data,'password'=>$secret);
$POSTFIELDS = json_encode($POSTFIELDS);
//正式购买地址 沙盒购买地址
$url_buy = "https://buy.itunes.apple.com/verifyReceipt";
$url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";
$url = $sandbox ? $url_sandbox : $url_buy;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $POSTFIELDS);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); //这两行一定要加,不加会报SSL 错误
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
$data = json_decode($response,true);
return $data;
}
以上代码有几个需要注意的地方
1.注意:php安装curl扩展,否则curl无法使用
2.注意:若已经上线,可以去掉沙盒测试地址
3.注意:在验证支付成功时更改订单的购买状态
4.注意:注意验证凭证时,我写的重点状态(切记,不然会验证失败的)