最近项目中用到了苹果支付,当客户段进行支付后,服务端要进行二次验证,防止篡改。这时IOS只需要把支付凭证传递给服务端,服务端进行验证。如果验证通过,将支付记录保存之数据库,给用户返回支付成功的消息即可。
首先,通过curl发送请求,获取苹果端的响应。代码如下:
//去苹果服务器二次验证代码
function getReceiptData($receipt, $isSandbox = false) {
if ($isSandbox) {
$endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';//沙箱地址
} else {
$endpoint = 'https://buy.itunes.apple.com/verifyReceipt';//真实运营地址
}
$postData = json_encode(
array('receipt-data' => $receipt)
);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //这两行一定要加,不加会报SSL 错误
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$errno = curl_errno($ch);
curl_close($ch);
if ($errno != 0) {//curl请求有错误
$order['errNo'] = 1;
return $order;
}else{
$data = json_decode($response, true);
if (!is_array($data)) {
$order['errNo'] = 2;
return $order;
}
//判断购买时候成功
if (!isset($data['status']) || $data['status'] != 0) {
$order['errNo'] = 3;
return $order;
}
//返回产品的信息
$order = $data['receipt']['in_app'][0];
$order['errNo'] = 0;
return $order;
}
}
$endpoint代表请求地址,沙箱模式和正式运营时的地址是不一样的,是否是沙箱模式在配置文件里面定义下就行了。次函数主要返回的苹果验证的结果。errNo位1时:请求超时。errNo位2时:苹果返回数据有误。errNo位3时:购买失败。errNo位0时:支付成功。
接下来就是接口的编写了,具体代码如下:
ApiError('001', '用户ID不能为空');
if ($receipt == '') $api->ApiError('002', '充值凭证不能为空');
if ($vcode == '') $api->ApiError('004', '校验码不能为空');
if ($source == '') $api->ApiError('005', '来源不能为空');
$vcode_raw = md5(md5($userid) . md5($source));
if ($vcode_raw != $vcode) {
$api->ApiError('006', '校验码不正确');
}
if (!in_array($source, array_keys($Array_API_Source)))
$api->ApiError('007', '来源错误');
//设置API来源
$api->setsource($source);
$userInfo = User::getInfoById($userid);
if (!$userInfo)
$api->ApiError('008', '用户不存在');
$chargeInfo=Chargelog::getInfoByReceipt($userid,$receipt);
if (!empty($chargeInfo))
$api->ApiError('009', '该凭证已经充值');
$isSandbox = true;//沙箱是测试环境,正式环境改为false
$info =getReceiptData($receipt, $isSandbox);//去苹果进行二次验证,防止收到的是伪造的数据
if(is_array($info) && $info['errNo'] == 0){//没有错误就进行业务逻辑的处理,订单设置成已支付,给用户加钱
$priceArr=split(".", $info['product_id']);
//$money=0;
// $api->ApiError('010', $info['product_id']);
if($info['product_id']=="cn.shushubuyue.product6")
$money=6;
elseif ($info['product_id']=="cn.shushubuyue.product30")
$money=30;
elseif ($info['product_id']=="cn.shushubuyue.product98")
$money=98;
$rs=Chargelog::add($userid, $money, $receipt,1);
if($rs>0){
User::chargeMoney($userid,$money);
echo json_encode_cn(array('status' => 'ok'));
$api->apicount();
}else{
$api->ApiError('010', '操作失败');
}
}else{
if($info['errNo'] == 1)
$api->ApiError('011', '请求超时,请稍后重试');
if($info['errNo'] == 2)
$api->ApiError('012', '苹果返回数据有误,请稍后重试');
if($info['errNo'] == 3)
$api->ApiError('013', '购买失败');
}
?>
代码中有好多公司自己封装的函数在这里就不贴出来了。其中:strCheck主要用于参数检查。ApiError 主要是用于接口调用的统计。到此,苹果支付接口就开发完毕了。