1. 程式人生 > >ios 內購 伺服器二次驗證元寶處理

ios 內購 伺服器二次驗證元寶處理

以前都是在本地處理內購  也沒有做驗證。這次手機網遊 為了避免作弊 網路遊戲都是在伺服器端實現元寶的加減。

內購程式碼 還是以前寫的 直接用了 。這次主要做了伺服器二次驗證。

NSString *roleId = [[NSString alloc] initWithUTF8String:name];
[[PlatformHandler sharedHandler]doBuyByRoleId:roleId money:money];
//內部函式
-(void)doBuyByRoleId:(NSString *)paramRoleId money:(int)money
{
 NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
    //是否越獄
    if ([[UIApplication sharedApplication] canOpenURL:url])
    {
        NSString *sMes = NSLocalizedString(@"SHOP_ERROR_STOREBUY_INFO", nil);
        UIAlertView *alertV = [[UIAlertView alloc]initWithTitle:nil message:sMes delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertV show];
        [alertV release];
        return;
    }
    CGSize mWinSize=  [UIScreen mainScreen].bounds.size;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0)
    {
        std::swap(mWinSize.width, mWinSize.height);
    }
    LoadingView *lv = [[LoadingView alloc] initWithFrame:CGRectMake(0, 0, mWinSize.width, mWinSize.height)];
    lv.tag = TAG_VIEW_LOADING;
    [[EAGLView sharedEGLView] addSubview:lv];
    [lv release];
    
    if ([SKPaymentQueue canMakePayments])
    {
        NSLog(@"addObserver:receiveAppStoreInfo");
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(receiveAppStoreInfo:) name:NOTIFICATION_APPSTORE_BUY_FOLDER object:nil];
        [[CBiOSStoreManager sharedInstance] initialStore];
        [[CBiOSStoreManager sharedInstance] buy:[NSString stringWithFormat:@"%@%d",BUY_ID,index] paramRoleId:paramRoleId];
    }
    else
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"STR_BUY_ERROR", nil) message:NSLocalizedString(@"STR_BUY_ERROR_INFO", nil) delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        if([[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING])
            [[[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING] removeFromSuperview];
    }
}
//購買成功函式回撥
-(void)receiveAppStoreInfo:(id)sender
{
    NSLog(@"receive info");
    if([[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING])
    {
        [[[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING] removeFromSuperview];
    }
    
    NSNotification *notification = (NSNotification *)sender;
    NSString *action = [notification object];
    if ([action isEqualToString:MSG_ACTION_FINISH])
    {
        NSLog(@"------------MSG_ACTION_FINISH==============購買成功");
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIFICATION_APPSTORE_BUY_FOLDER object:nil];
}
/*
 *  CBiOSStoreManager.mm
 *  CloudBox Cross-Platform Framework Project
 *
 *  Created by xxhh on 2012/10/30.
 *
 */

#import "CBiOSStoreManager.h"
#define SERVER_DOMAIN @"http://192.168.0.177"
#define TEST_SANDBOX  1
@implementation CBiOSStoreManager

//自身例項
static CBiOSStoreManager* _sharedInstance = nil;

//付費單例獲取
+(CBiOSStoreManager*)sharedInstance
{
    @synchronized([CBiOSStoreManager class])
    {
        if (!_sharedInstance)
            [[self alloc] init];
        
        return _sharedInstance;
    }
    return nil;
}

//
+(id)alloc
{
    @synchronized([CBiOSStoreManager class])
    {
        NSAssert(_sharedInstance == nil, @"Attempted to allocate a second instance of a singleton.\n");
        _sharedInstance = [super alloc];
        return _sharedInstance;
    }
    return nil;
}

-(id)init {
    self = [super init];
    if (self != nil) {
    }
    return self;
}

-(void)initialStore
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
-(void)releaseStore
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

-(void)buy:(NSString*)buyProductIDTag paramRoleId:(NSString *)paramRoleId
{
    _paramRoleId=paramRoleId;
    [self requestProductData:buyProductIDTag];
}

//查詢付費列表。
-(bool)CanMakePay
{
    NSLog(@"----------CanMakePay--------------\n");
    return [SKPaymentQueue canMakePayments];
}

-(void)requestProductData:(NSString*)buyProductIDTag
{
    NSLog(@"----------Request--------------\n");
    _buyProductIDTag = [buyProductIDTag retain];
    NSArray *product = [[NSArray alloc] initWithObjects:buyProductIDTag,nil];
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];
    [product release];
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"----------didReceiveResponse--------------\n");
    SKPayment *payment = nil;
    if (response == NULL || response.products == NULL || response.products.count == 0) {
        [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR];
        [request autorelease];
        return;
    }
    payment = [SKPayment paymentWithProduct:[response.products objectAtIndex:0]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    [request autorelease];
    
}
- (void)requestProUpgradeProductData:(NSString*)buyProductIDTag
{
    NSLog(@"----------requestProUpgradeProductData--------------\n");
    NSSet *productIdentifiers = [NSSet setWithObject:buyProductIDTag];
    SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
    
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"----------Request Failed--------------\n");
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR];
    
}

-(void) requestDidFinish:(SKRequest *)request
{
    NSLog(@"----------Request finished--------------\n");
    
}

-(void) purchasedTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@"-----Purchased Transaction----\n");
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
    [transactions release];
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    NSLog(@"----------updatedTransactions--------------\n");
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                NSLog(@"-----Transaction--購買完成-----\n");
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:{
                [self failedTransaction:transaction];
                NSLog(@"-----Transaction Failed--購買失敗-----\n");
                break;
            }
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                NSLog(@"----- Already buy this product---已經購買-----\n");
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"-----Transcation puchasing---正在購買-----\n");
                break;
            default:
                break;
        }
    }
}

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
    // 驗證購買憑據
    [self verifyReceipt:transaction];
    NSString *sBuyID = transaction.payment.productIdentifier;
    NSLog(@"completeTransaction: BuyID: %@", sBuyID);
    
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_FINISH];
    // 將交易從交易佇列中刪除
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

#pragma mark 本地驗證購買憑據
- (void)verifyPruchase:(SKPaymentTransaction *)transaction
{
    //  transaction.transactionReceipt
    
    // 驗證憑據,獲取到蘋果返回的交易憑據
    // appStoreReceiptURL iOS7.0增加的,購買交易完成後,會將憑據存放在該地址
    //    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 從沙盒中獲取到購買憑據
    //    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    
    // 傳送網路POST請求,對購買憑據進行驗證
    //    NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
    // 國內訪問蘋果伺服器比較慢,timeoutInterval需要長一點
    //    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
    
    //    request.HTTPMethod = @"POST";
    
    // 在網路中傳輸資料,大多情況下是傳輸的字串而不是二進位制資料
    // 傳輸的是BASE64編碼的字串
    /**
     BASE64 常用的編碼方案,通常用於資料傳輸,以及加密演算法的基礎演算法,傳輸過程中能夠保證資料傳輸的穩定性
     BASE64是可以編碼和解碼的
     */
    
    //  NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    //    NSString *encodeStr = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    //    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    //    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    
    //    request.HTTPBody = payloadData;
    
    // 提交驗證請求,並獲得官方的驗證JSON結果
    //    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    
    // 官方驗證結果為空
    //    if (result == nil) {
    //        NSLog(@"驗證失敗");
    //    }
    
    //    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    
    //    NSLog(@"%@", dict);
    
    //    if (dict != nil) {
    // 比對字典中以下資訊基本上可以保證資料安全
    // bundle_id&application_version&product_id&transaction_id
    //        NSLog(@"驗證成功");
    //    }
    
}
#pragma mark 伺服器驗證購買憑據
- (void) verifyReceipt:(SKPaymentTransaction *)transaction
{
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/verify.php", SERVER_DOMAIN]];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
    request.HTTPMethod = @"POST";
    
    NSString *encodeStr = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    int isSandBox =0;
#ifdef TEST_SANDBOX
    isSandBox=1;
#endif
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\",\"sandbox\":%d,\"paramRoleId\":\"%@\"}", encodeStr,isSandBox,_paramRoleId];
    //把bodyString轉換為NSData資料
    NSData *bodyData = [payload dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];//把bodyString轉換為NSData資料
    [request setHTTPBody:bodyData];
    
    // 提交驗證請求,並獲得官方的驗證JSON結果
    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    
    // 官方驗證結果為空
    if (result == nil) {
        NSLog(@"驗證失敗");
    }
    else
    {
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
        if (dict != nil && [[dict objectForKey:@"status"]integerValue] ==1 && [[dict objectForKey:@"success"]integerValue] ==1) {
            // 比對字典中以下資訊基本上可以保證資料安全
            NSLog(@"驗證成功");
        }else
        {
            NSLog(@"驗證失敗");
        }
    }
}

-(void)recordTransaction:(NSString *)product
{
    NSLog(@"-----Record transcation--------\n");
    
}

-(void)provideContent:(NSString *)product
{
    NSLog(@"-----Download product content--------\n");
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@"-----failedTransaction--------\n");
    NSNotification *notification= [NSNotification notificationWithName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    if (center == nil  && notification == nil) {
        NSLog(@"null");
    }
    [center postNotification:notification];
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR];
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        if(transaction.error.code == SKErrorUnknown)
        {
            NSLog(@"Unknown Error (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier);
            UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:"
                                                                    message: @"There was an error purchasing this item please try again."
                                                                  delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil];
            [failureAlert show];
            [failureAlert release];
        }
        
        if(transaction.error.code == SKErrorClientInvalid)
        {
            NSLog(@"Client invalid (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier);
            UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:"
                                                                    message: @"There was an error purchasing this item please try again."
                                                                  delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil];
            [failureAlert show];
            [failureAlert release];
        }
        
        if(transaction.error.code == SKErrorPaymentInvalid)
        {
            NSLog(@"Payment invalid (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier);
            UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:"
                                                                    message: @"There was an error purchasing this item please try again."
                                                                  delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil];
            [failureAlert show];
            [failureAlert release];
        }
        
        if(transaction.error.code == SKErrorPaymentNotAllowed)
        {
            NSLog(@"Payment not allowed (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier);
            UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:"
                                                                    message: @"There was an error purchasing this item please try again."
                                                                  delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil];
            [failureAlert show];
            [failureAlert release];
        }
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction
{
    NSLog(@"-----paymentQueueRestoreCompletedTransactionsFinished-------\n");
    
}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@"-----Restore transaction--------\n");
}

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
    NSLog(@"-------Payment Queue----\n");
}


-(void)dealloc
{
    [super dealloc];
}

@end
/*
 *  CBiOSStoreManager.h
 *  CloudBox Cross-Platform Framework Project
 *
 *  Created by xxhh on 2012/10/30.
 *
 */

#import 
#import 

#define NOTIFICATION_APPSTORE_BUY_FOLDER @"buy_folder"
#define MSG_ACTION_ERROR    @"msg_action_error"
#define MSG_ACTION_FINISH   @"msg_action_finish"
#define MSG_ACTION_RESTORE  @"msg_action_restore"


@interface CBiOSStoreManager : NSObject
{
    int buyType;
    NSString* _buyProductIDTag;
    NSString* _paramRoleId;
}

+ (CBiOSStoreManager*) sharedInstance;

- (void) buy:(NSString*)buyProductIDTag paramRoleId:(NSString *)paramRoleId;
- (bool) CanMakePay;
- (void) initialStore;
- (void) releaseStore;
- (void) requestProductData:(NSString*)buyProductIDTag;
- (void) provideContent:(NSString *)product;
- (void) recordTransaction:(NSString *)product;

- (void) requestProUpgradeProductData:(NSString*)buyProductIDTag;

- (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
- (void) purchasedTransaction: (SKPaymentTransaction *)transaction;

- (void) completeTransaction: (SKPaymentTransaction *)transaction;
- (void) failedTransaction: (SKPaymentTransaction *)transaction;
- (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;
- (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;

- (void) restoreTransaction: (SKPaymentTransaction *)transaction;

@end
//
//  LoadingView.m
//  pDownloader
//
//  Created by xxhh on 10/5/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "LoadingView.h"
#import 

@implementation LoadingView


- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame]))
    {
        // Initialization code
		self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.0];
		UIActivityIndicatorView *loadingview  = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0 , 0, 36, 36)];
        loadingview.center=CGPointMake(frame.size.width/2, frame.size.height/2-20);
		[loadingview startAnimating];
        UIImageView *image = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"bg_black.png"]];
        image.frame = CGRectMake(0, 0, 210, 150);
        image.center=CGPointMake(frame.size.width/2, frame.size.height/2);
        [self addSubview:image];
        
        UILabel *labLoading = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 210, 200)];
        labLoading.center=CGPointMake(frame.size.width/2, frame.size.height/2+20);
        labLoading.textAlignment = UITextAlignmentCenter;
        [labLoading setText:@"Loading..."];
        [labLoading setBackgroundColor:[UIColor clearColor]];
        [labLoading setTextColor:[UIColor whiteColor]];
        [self addSubview:labLoading];
        [self addSubview:loadingview];
		UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
        [self addSubview:btn];
        
        [btn release];
        [labLoading release];
		[loadingview release];
        [image release];
    }
    return self;
}


- (void)drawRect:(CGRect)rect {
    // Drawing code
}


- (void)dealloc {
    [super dealloc];
}


@end
//
//  LoadingView.h
//  pDownloader
//
//  Created by leefj on 10/5/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import 

#define TAG_VIEW_LOADING        1234


@interface LoadingView : UIView {

}

@end
 $receipt)   
        );   
    
        $ch = curl_init($endpoint);   
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);   
        curl_setopt($ch, CURLOPT_POST, true);   
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);   
    
        $response = curl_exec($ch);   
        $errno    = curl_errno($ch);   
        $errmsg   = curl_error($ch);   
        curl_close($ch);   
    
        if ($errno != 0) {   
            throw new Exception($errmsg, $errno);   
        }   
    
        $data = json_decode($response);   
    
        if (!is_object($data)) {   
            throw new Exception('Invalid response data');   
        }   
    
        if (!isset($data->status) || $data->status != 0) {   
            throw new Exception('Invalid receipt');   
        }   
    
        return array(   
            'quantity'       =>  $data->receipt->quantity,   
            'product_id'     =>  $data->receipt->product_id,   //產品id
            'transaction_id' =>  $data->receipt->transaction_id,   
            'purchase_date'  =>  $data->receipt->purchase_date,   
            'app_item_id'    =>  $data->receipt->app_item_id,   
            'bid'            =>  $data->receipt->bid,   
            'bvrs'           =>  $data->receipt->bvrs   
        );   
    }


    $content=file_get_contents("php://input");
    $data = json_decode($content,true);  
    $receipt = $data["receipt-data"];   
    $isSandbox = (bool) $data["sandbox"]; 
    $paramRoleId  = $data["paramRoleId"];
    $hostIp  = $data["hostIp"];  

    try {   
        $info = getReceiptData($receipt, $isSandbox);
        $infoJson=json_encode($info);
        //進行相關充值處理
        // 日誌記錄
        $fh = fopen("lshudong.txt", "a+"); 
        fwrite($fh, "userId:".$paramRoleId."==hostIp:".$hostIp."==時間:".date("Y-m-d H:i:s") ." ==驗證成功\n\r");
        fclose($fh);
        // 傳送回傳訊息
        echo json_encode(array(   
            'status'       =>  1,   
            'success'     =>  1,   
        ));
     }   
     catch (Exception $ex) {   
        echo $ex;
        //日誌記錄
        $fh = fopen("lshudong.txt", "a+"); 
        fwrite($fh, "userId:".$paramRoleId."hostIp:".$hostIp."時間:".date("Y-m-d H:i:s") ." 驗證失敗\n\r");
        fclose($fh);
        //傳送回傳訊息
        echo  json_encode(array(   
            'status'       =>  1,   
            'success'     =>  0,   
        ));
     } 
?>