PHP receipt verification always returns true - php

I'm attempting to verify the integrity of a consumable purchase in my app.
I've tested my in app purchase and it works fine. However, upon testing it with an "In-App-Purchase Cracker" with a jailbroken device, I realized that All of my receipts returned ok by apple's servers regardless of whether the purchase actually happened or not.
My transaction listener:
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self unlockFeature];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Transaction Failed");
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
default:
break;
}
}
unlockFeature:
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
NSString *rs = [receipt base64EncodedStringWithOptions:kNilOptions];
NSInteger amt = _cDonAmt;
_cDonAmt = 0;
if (receipt) {
NSURL *url = [NSURL URLWithString:#"http://example.com/verifyDonation.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[MasterViewController getUserId] forKey:#"userID"];
[request setPostValue:rs forKey:#"receipt"];
[request setPostValue:[NSString stringWithFormat:#"%ld",(long)amt] forKey:#"dAmt"];
[request setDelegate:self];
[request startAsynchronous];
}
I'm hoping that my error might lie in my PHP Verification script
<?php
class VerifyDonation {
function verify() {
$uid = htmlspecialchars($_POST["userID"]);
$dA = intval(htmlspecialchars($_POST["dAmt"]));
$receipti = $_POST["receipt"];
$sandbox = true;
//start getting
if ($sandbox)
$verify_host = "ssl://sandbox.itunes.apple.com";
else
$verify_host = "ssl://buy.itunes.apple.com";
$json='{"receipt-data" : "'.$receipti.'" }';
//opening socket to itunes
$fp = fsockopen ($verify_host, 443, $errno, $errstr, 30);
if (!$fp)
{
// HTTP ERROR
return false;
}
else
{
//iTune's request url is /verifyReceipt
$header = "POST /verifyReceipt HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($json) . "\r\n\r\n";
fputs ($fp, $header . $json);
$res = '';
while (!feof($fp))
{
$step_res = fgets ($fp, 1024);
$res = $res . $step_res;
}
fclose ($fp);
//taking the JSON response
$json_source = substr($res, stripos($res, "\r\n\r\n{") + 4);
//decoding
$app_store_response_map = json_decode($json_source);
$app_store_response_status = $app_store_response_map->{'status'};
//end geting
if ($app_store_response_status == 0)//eithr OK or expired and needs to synch
{
echo "validReceipt";
$link = mysql_connect("localhost", "user", "pass") or
die("Could not connect: " . mysql_error());
mysql_select_db("database");
mysql_query("UPDATE `users` SET `donarAmt`= donarAmt + $dA WHERE facebookId = $uid");
return true;
}
else
{
echo "invalidReceipt";
return false;
}
}
}
}
// This is the first thing that gets called when this page is loaded
// Creates a new instance of the RedeemAPI class and calls the redeem method
$ver = new VerifyDonation;
$ver->verify();
?>

Related

UPDATE data not getting in php file?

When i tried to UPDATE / PUT fields from iOS to PHP server and am not getting these value over there.
this is my iOS Code
NSString *url=#"http://example.com/project/php/basicinfo.php";
NSString *stringData = [NSString stringWithFormat:#"fname=%#&mname=%#&lname=%#&email=%#&country=%#&city=%#&dob=%#&role=%#",firstNameCell.fname.text ,mnameCell.mname.text,lnameCell.lname.text,emailCell.email.text,[countryCell.country currentTitle],cityCell.city.text,[dobCell.dob currentTitle],#"Model"];
NSLog(#"%#",stringData);
NSURL *aUrl = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"UPDATE"];
[request setHTTPBody:[stringData dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:request delegate:self];
When i echo in PHP its coming as empty.
Pls help me
This is the receiving response
Did Receive Response <NSHTTPURLResponse: 0x14ef17e40> { URL: http://example.com/project/php/basicinfo.php } { status code: 200, headers {
Connection = "Keep-Alive";
"Content-Length" = 1;
"Content-Type" = "text/html; charset=utf-8";
Date = "Fri, 15 Jan 2016 15:15:40 GMT";
"Keep-Alive" = "timeout=5, max=100";
Server = "Apache/2.4.7 (Ubuntu)";
"X-Powered-By" = "PHP/5.5.9-1ubuntu4.11";
} }
PHP Code
<?php
header("Content-type: text/html; charset=utf-8");
$servername = "localhost";
$username = "root";
$password = "root";
$dbname = "test";
$charset="UTF8";
$fname=$_POST['fname'];
$mname=$_POST['mname'];
$lname=$_POST['lname'];
$email=$_POST['email'];
$country=$_POST['country'];
$city=$_POST['city'];
$dob=$_POST['dob'];
$role=$_POST['role'];
echo $name;
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
/* change character set to utf8 */
if (!mysqli_set_charset($conn, "utf8")) {
exit();
} else {
mysqli_close($link);
echo $email;
$sql="UPDATE `basicinfo` SET `fname`='$fname',`mname`='$mname',`lname`='$lname',`email`='$email',`country`='$country',`city`='$city',`dob`='$dob',`role`='$role' WHERE `email`='$email'";
if ($conn->query($sql) === TRUE) {
// echo $email;
} else {
echo "fail";
}
//printf("Current character set: %s\n", mysqli_character_set_name($conn));
}
?>
if you use UPDATE HTTP method to call your script $_POST won't work.
You can do something like that:
$rest = $_SERVER['REQUEST_METHOD'];
if(isset($_SERVER['CONTENT_TYPE'])) {
$content_type = $_SERVER['CONTENT_TYPE'];
}
if ($rest=="PUT") {
$body = file_get_contents("php://input");
parse_str($body, $parsed);
switch ($content_type)
{
case "application/json":
// do stuff
break;
case "application/x-www-form-urlencoded":
// do stuff
break;
}
break;
}
}
Or use POST

PayPal IPN Listener works inside sandbox but not outside

I am running this PayPal IPN listener written by tutsplus, it's modified a bit to suit my needs. Everything worked fine until I have moved from sandbox to live mode. I have went over the code, and don't quite understand if I need to switch anything or it is checking for sandbox/live itself.
<?php
class PayPal_IPN{
function infotuts_ipn($im_debut_ipn) {
define('SSL_P_URL', 'https://www.paypal.com/cgi-bin/webscr');
define('SSL_SAND_URL', 'https://www.sandbox.paypal.com/cgi-bin/webscr');
$hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
if (!preg_match('/paypal\.com$/', $hostname)) {
$ipn_status = 'Validation post isn\'t from PayPal';
if ($im_debut_ipn == true) {
// mail test
}
return false;
}
// parse the paypal URL
$paypal_url = ($_REQUEST['test_ipn'] == 1) ? SSL_SAND_URL : SSL_P_URL;
$url_parsed = parse_url($paypal_url);
$post_string = '';
foreach ($_REQUEST as $field => $value) {
$post_string .= $field . '=' . urlencode(stripslashes($value)) . '&';
}
$post_string.="cmd=_notify-validate"; // append ipn command
// get the correct paypal url to post request to
$paypal_mode_status = $im_debut_ipn; //get_option('im_sabdbox_mode');
if ($paypal_mode_status == true)
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
else
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60);
$ipn_response = '';
if (!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$ipn_status = "fsockopen error no. $err_num: $err_str";
if ($im_debut_ipn == true) {
echo 'fsockopen fail';
}
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($post_string) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while (!feof($fp)) {
$ipn_response .= fgets($fp, 1024);
}
fclose($fp); // close connection
}
// Invalid IPN transaction. Check the $ipn_status and log for details.
if (!preg_match("/VERIFIED/s", $ipn_response)) {
$ipn_status = 'IPN Validation Failed';
if ($im_debut_ipn == true) {
echo 'Validation fail';
print_r($_REQUEST);
}
return false;
} else {
$ipn_status = "IPN VERIFIED";
if ($im_debut_ipn == true) {
echo 'SUCCESS';
}
return true;
}
}
function ipn_response($request){
mail("mssoad#gmail.com","My subject",print_r($request,true));
$im_debut_ipn=true;
if ($this->infotuts_ipn($im_debut_ipn)) {
// if paypal sends a response code back let's handle it
if ($im_debut_ipn == true) {
$sub = 'PayPal IPN Debug Email Main';
$msg = print_r($request, true);
$aname = 'infotuts';
//mail send
}
// process the membership since paypal gave us a valid +
$this->insert_data($request);
}
}
function issetCheck($post,$key){
if(isset($post[$key])){
$return=$post[$key];
}
else{
$return='';
}
return $return;
}
function insert_data($request){
require_once('dbconnect.php');
$post=$request;
$item_name=$this->issetCheck($post,'item_name');
$amount=$this->issetCheck($post,'mc_gross');
$currency=$this->issetCheck($post,'mc_currency');
$payer_email=$this->issetCheck($post,'payer_email');
$first_name=$this->issetCheck($post,'first_name');
$last_name=$this->issetCheck($post,'last_name');
$country=$this->issetCheck($post,'residence_country');
$txn_id=$this->issetCheck($post,'txn_id');
$txn_type=$this->issetCheck($post,'txn_type');
$payment_status=$this->issetCheck($post,'payment_status');
$payment_type=$this->issetCheck($post,'payment_type');
$payer_id=$this->issetCheck($post,'payer_id');
$date=$this->issetCheck($post,'custom');
$create_date=date('Y-m-d H:i:s');
$payment_date=date('Y-m-d H:i:s');
$firstLast = $first_name . $last_name;
$explode = explode('|', $item_name);
foreach($explode as $slot) {
if(strlen($slot) > 0) {
$query = "INSERT INTO bookings (date, start, name, email, phone, order_id) VALUES ('$date', '$slot', '$firstLast', '$payer_email', '$phone', '$orderid')";
$result = mysqli_query($con, $query) or die(mysqli_error($link));
} // Close if
} // Close foreach
mysqli_query($con,"INSERT INTO trans_tbl (item_name,ride_day,payer_email,first_name,last_name,amount,currency,country,txn_id,txn_type,payer_id,payment_status,payment_type,create_date,payment_date)
VALUES ('$item_name','$date','$payer_email','$first_name','$last_name','$amount','$currency','$country','$txn_id','$txn_type','$payer_id','$payment_status','$payment_type','$create_date','$payment_date')");
mysqli_close($con);
}
}
$obj = New PayPal_IPN();
$obj->ipn_response($_REQUEST);
?>
On the IPN History of the paypal website it is stuck at sent - resending.
I have setup IPN settings and notify URL in profile settings, and have a business account. My email is verified on the account as well.
Another thing to note, I have been doing simple $0.01 to test this outside sandbox mode, and the return page is working fine just not the ipn listener.
Any help is much appreciated, thanks.
$paypal_mode_status = $im_debut_ipn; //get_option('im_sabdbox_mode');
if ($paypal_mode_status == true)
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
else
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60);
Could be incorrect, you should test to confirm, but I think it's because your $im_debut_ipn variable, when set to TRUE, is not only "debugging" but for some reason is also being used to determine the paypal url. It then sets the url to be paypals sandbox url (see above).
i.e, When
$im_debut_ipn = true
then,
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
is also true.
Note that I think $im_debut_ipn is actually a typo and should be ..debug.., meaning a debug mode that lets error messages be shown.

Validating appReceiptStoreURL Returning 21002 Status

I have created a class which handles the purchases on In-App Purchases and also the validating of receipts. A while ago I used to use the transactionReceipt property on an SKPaymentTransaction, but have updated my code a fair amount and now use appStoreReceiptURL on the [NSBundle mainBundle].
Basically it seems as though my receipt is being sent to Apple's server in an acceptable manner, but I keep getting the status code of 21002. In auto-renewable subscriptions I know that this means the receipt is not in an acceptable format, however I have no idea what this status means in regard to an in-app purchase receipt.
Here is the local method validating the receipt:
/**
* 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];
}];
}
The important PHP function on the server does this:
/**
* 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);
}
The actual PHP script being executed is:
$receipt = $_POST['receipt'];
$sandbox = $_POST['sandbox'];
$returnValue = validateReceipt($receipt, $sandbox);
header('content-type: application/json; charset=utf-8');
echo json_encode($returnValue);
Comparing your PHP with mine (which I know works) is difficult because I am using HTTPRequest rather than the raw curl APIs. However, it seems to me that you are setting the "{receipt-data:..}" JSON string as merely a field in the POST data rather than as the raw POST data itself, which is what my code is doing.
curl_setopt($curlHandle, CURLOPT_POST, true);
curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $postData); // Possible problem
$encodedResponse = curl_exec($curlHandle);
Compared to:
$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();
I have changed my variable names a bit to make them match up with your example.
the code 21002 means "The data in the receipt-data property was malformed or missing."
you can find it in
https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
below code is my class for appstore in-app verifyRecepip, GuzzleHttp is required, you can install it by composer require guzzlehttp/guzzle https://github.com/guzzle/guzzle
<?php
namespace App\Libraries;
class AppStoreIAP
{
const SANDBOX_URL = 'https://sandbox.itunes.apple.com/verifyReceipt';
const PRODUCTION_URL = 'https://buy.itunes.apple.com/verifyReceipt';
protected $receipt = null;
protected $receiptData = null;
protected $endpoint = 'production';
public function __construct($receipt, $endpoint = self::PRODUCTION_URL)
{
$this->receipt = json_encode(['receipt-data' => $receipt]);
$this->endpoint = $endpoint;
}
public function setEndPoint($endpoint)
{
$this->endpoint = $endpoint;
}
public function getReceipt()
{
return $this->receipt;
}
public function getReceiptData()
{
return $this->receiptData;
}
public function getEndpoint()
{
return $this->endpoint;
}
public function validate($bundle_id, $transaction_id, $product_code)
{
$http = new \GuzzleHttp\Client([
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'timeout' => 4.0,
]);
$res = $http->request('POST', $this->endpoint, ['body' => $this->receipt]);
$receiptData = json_decode((string) $res->getBody(), true);
$this->receiptData = $receiptData;
switch ($receiptData['status']) {
case 0: // verify Ok
// check bundle_id
if (!empty($receiptData['receipt']['bundle_id'])) {
$receipt_bundle_id = $receiptData['receipt']['bundle_id'];
if ($receipt_bundle_id != $bundle_id) {
throw new \Exception('bundle_id not matched!');
}
}
// check transaction_id , product_id
if (!empty($receiptData['receipt']['in_app'])) {
$in_app = array_combine(array_column($receiptData['receipt']['in_app'], 'transaction_id'), $receiptData['receipt']['in_app']);
if (empty($in_app[$transaction_id])) {
throw new \Exception('transaction_id is empty!');
}
$data = $in_app[$transaction_id];
if ($data['product_id'] != $product_code) {
throw new \Exception('product_id not matched!');
}
} else {
$receipt_transaction_id = $receiptData['receipt']['transaction_id'];
$receipt_product_id = $receiptData['receipt']['product_id'];
if ($receipt_transaction_id != $transaction_id || $product_id != $product_code) {
throw new \Exception('tranaction_id not matched!');
}
}
break;
case 21007:// sandbox order validate in production will return 21007
if ($this->getEndpoint() != self::SANDBOX_URL) {
$this->setEndPoint(self::SANDBOX_URL);
$this->validate($bundle_id, $transaction_id, $product_code);
} else {
throw new \Exception('appstore error!');
}
break;
default:
throw new \Exception("[{$receiptData['status']}]appstore error!");
break;
}
return $receiptData;
}
}
I think Morteza M is correct. I did a test and got reply(JSON) like:
{
'status':
'environment': 'Sandbox'
'receipt':
{
'download_id':
....
'in_app":
{
'product_id':
....
}
....
}
}

iphone push notification not work

I am implementing a push notification in my application.
Server: php
Client: iphone
Sever side Coding:
function pushToIphone($deviceToken, $badge){
ini_set('display_errors','on');
error_reporting(E_ALL);
//$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsHost = 'gateway.push.apple.com';
$apnsPort = 2195;
$pem_path = dirname(__FILE__);
$pem_path = $pem_path .'\cert';
$apnsCert = $pem_path.'\apns_cer.pem';
echo $apnsCert."<br/>";
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if($apns) {
echo "Connection Established<br/>";
$payload = array();
//$payload['aps'] = array('alert' => 'BiiMe finds product for you', 'badge' => $badge, 'sound' => 'default');
//$payload = get_payload_message('BiiMe finds product for you',$badge);
//$payload['server'] = array('serverId' => $serverId, 'name' => $serverName);
//$payload = json_encode($payload);
$payload = get_payload_message('BiiMe finds product for you',$badge);
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
echo $apnsMessage."<BR/>";
$fwrite = fwrite($apns, $apnsMessage);
echo $fwrite." bytes written<BR/>";
} else {
echo "Connection fail<br/>";
}
//socket_close($apns);
fclose($apns);
}
function get_payload_message($message_text,$badge,$sound='default')
{
$PAYLOAD_MAXIMUM_SIZE = 256;
$payload['aps'] = array("alert" => "$message_text", 'badge' => $badge, 'sound' => $sound);
$payload = json_encode($payload);
$nJSONPayloadLen = strlen($payload);
if($nJSONPayloadLen > $PAYLOAD_MAXIMUM_SIZE)
{
$nTextLen = strlen($message_text);
if($nJSONPayloadLen - $nTextLen <= $PAYLOAD_MAXIMUM_SIZE)
{
$badge_count = substr($message_text, 0, $nTextLen - ($nJSONPayloadLen - $PAYLOAD_MAXIMUM_SIZE));
$payload = get_payload_message($message_text);
}
}
return $payload;
}
Iphone side i added:
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"It comes<<<<<<<<<<<<<---------------------------------------");
NSString *str = [NSString
stringWithFormat:#"Device Token=%#",deviceToken];
NSLog(str);
NSString *token = [NSString stringWithFormat:deviceToken];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:token forKey:#"deviceId"];
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"It comes with error---------------------------->>>>>>>>>>>>>>");
NSString *str = [NSString stringWithFormat: #"Error: %#", err];
NSLog(str);
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:str forKey:#"deviceId"];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
for (id key in userInfo) {
NSLog(#"key: %#, value: %#", key, [userInfo objectForKey:key]);
}
}
also i use:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIImageView *loading = [[UIImageView alloc] initWithFrame:CGRectMake(0, 20, 320, 460)];
[loading setImage:[UIImage imageNamed:#"Default.png"]];
[window addSubview:loading];
[loading release];
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound)];
}
This is my whole code that used:
iPhone Log shows while Device is Connected:
2012-02-03 19:51:32.872 BiiMe[7544:707] It comes<<<<<<<<<<<<<---------------------------------------
2012-02-03 19:51:32.873 BiiMe[7544:707] Device Token=<26d906c5 c273446d 5f40d2c1 73ddd3f6 869b2666 b1c7afd5 173d69b6 629def70>
all times server side:
Connection Established
What is missing by me..? or what should i implemented in my code:
your answer will help me.
use this code in didFinishLaunchingWithOption in AppDelegete
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert)];
gateway.push.apple.com is used for released application or AdHoc application. If you are checking with development profile you might need to change it to gateway.sandbox.push.apple.com
Hope this helps.

How do I notify my iPhone app via php that a name has been added to a database or not?

My iPhone app communicates through a php file with my mySql database. Everything works fine. But when I send the form and the username already exists, the php file should somehow backfire a notification. What should I do ?
php File
$query = "SELECT username FROM userData WHERE username = '$username'";
$result = mysql_query($query);
if (mysql_num_rows($result) > 0) {
// WHAT SHOULD BE DONE HERE TO NOTIFY iPHONE ?
}
I could think of a way, but it I think there is a better and more efficient way to do it.
[EDIT]
This is what I did to get the response:
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSDictionary *jsonDictionaryResponse =[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"json response = %#", jsonDictionaryResponse);
[/EDIT]
He does not really need a push notification. Just need a response back from the server.
$query = "SELECT username FROM userData WHERE username = '$username'";
$result = mysql_query($query);
if (mysql_num_rows($result) > 0) {
// WHAT SHOULD BE DONE HERE TO NOTIFY iPHONE ?
sendResponse(200, json_encode('SUCCESS Notification'));
}
Where sendResponse looks like this
// Helper method to send a HTTP response code/message
function sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
$status_header = 'HTTP/1.1 ' . $status . ' ' . 'OK';
header($status_header);
header('Content-type: ' . $content_type);
echo $body;
}

Categories