Jul 312012
 

Third and final PHP script for Android GCM. This script is for device registration. After a device has registered itself for GCM, the registration id is sent to the third-party application server for storage.

Also see http://skipstechtalk.net/2012/07/20/my-google-cloud-messaging-gcm-php-script/
and
http://skipstechtalk.net/2012/07/31/my-php-script-for-storing-gcm-user-registration/

<?php
/*
saveRegId.php
 
Script for receiving GCM device registrations. The script 
  expects an HTTP GET with the following parameters:
&phone_name=my_friendly_phone_name. This is edited by the user in 
  the global settings.
&regid=my_gcm_registration_id. This is the registration id that the 
  phone receives when it calls the GCM registration intent
&device_id=my_device_id. Normally this is the IMEI number, but it can 
  be other numbers, depending on the phone and OS. It is easily
  hacked, so it isn't bulletproof. I just use it to try and prevent
  multiple device registrations.
&username=my_username. The same username used to register here
&password=my_password. The same password used to register here
$message_type=gcm or c2dm. All recent versions of PHCA send gcm
 
A working example of this is (all on one line)
https://phc-a.net/saveRegId.php?phone_name=Skips%20phone
  &regid=a1b2c3d4f51234567890abcdef
  &device_id=9ab8c7d6e5f1234567890abcdef
  &username=me
  &password=fluffypants
  &message_type=gcm
*/
$dbuser = 'mydbusername';
$dbname = 'phcadb';
$dbpasswd = 'mydbpassword';
$dbhost = 'my.dbhost.net';
 
$dbh = @mysql_connect($dbhost, $dbuser, $dbpasswd);
$verbose = "";
 
if (!$dbh) {
	echo "Could not connect to MySQL server on " . $dbhost;
	die();
} else {
	$verbose = mysql_real_escape_string($_REQUEST[verbose]);
}
 
if (!@mysql_select_db($dbname, $dbh)) {
	if ($verbose==true) echo "Could not connect to database " . $dbname;
	die();
}
 
 
// store the url, just for debugging purposes.
//$incomingurl = curPageURL();
//$sql = "INSERT INTO incomingsql (sqlx) VALUES ('$incomingurl')";
//$result = query($sql);
 
$salt = GetSalt();
$storedEncryptedPassword = GetStoredEncryptedPassword();
 
$encryptedPassword=hash('sha512', $salt.$_REQUEST[password]);
for($i=0; $i<5000; $i++){
   $encryptedPassword=hash('sha512', $salt.$encryptedPassword);
}
 
if ($storedEncryptedPassword == $encryptedPassword) {
	StoreRegistrationId($verbose);
}
else
{
	header('HTTP/1.0 401 Unauthorized', true, 401);
	die("Bad Username/Password");
}
 
 
function StoreRegistrationId($verbose) {
	$phone_name = mysql_real_escape_string($_REQUEST[phone_name]);
	$regid = mysql_real_escape_string($_REQUEST[regid]);
	$device_id = mysql_real_escape_string($_REQUEST[device_id]);
	$username = mysql_real_escape_string($_REQUEST[username]);
	$password= mysql_real_escape_string($_REQUEST[password]);
	$message_type = mysql_real_escape_string($_REQUEST[message_type]);
 
	// first check to see if we already have this device registered
	if ($verbose==true) echo "Checking if we have seen this device before<br />";
	$sql = "SELECT * FROM userdevices WHERE device_id='$_REQUEST[device_id]'";
	if ($verbose==true) echo "$sql <br />";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // it's a new device, so INSERT it
	{
		$sql = "INSERT INTO userdevices (
			registration_id, 
			device_id, 
			username, 
			is_sending, 
			message_type, 
			phone_name
			) VALUES (
			'$regid', 
			'$device_id', 
			'$username', 
			1, 
			'$message_type', 
			'$phone_name'
			)";
	}
	else
	{
		// we do have this phone registered already. Check to see if it is with the same user.
		// We don't want people signing up with multiple accounts.
		$row = mysql_fetch_array($result);
		if ($_REQUEST[username] == $row[username])
		{
			$sql = "UPDATE userdevices SET 
			registration_id='$regid', 
			is_sending=1, 
			message_type='$message_type', 
			phone_name='$phone_name' 
			WHERE username = '$username' AND device_id='$device_id'";
		}
		else
		{
			header('HTTP/1.0 550 Unauthorized', true, 550);
			die("This phone is already registered with username '" . $row[username] . "'");
		}
	}
 
	if ($verbose==true) echo "$sql <br />";
	$result = query($sql);
	if (!$result) {
		header('HTTP/1.0 500 Internal Server Error');
		die("Internal Error");
	} else {
		//header("Status: 200");
		//echo "OK<br />";
		// send a test message to the phone to be sure everything is working.
		$url = "https://phc-a.net/send.php?username=".$username."&password=".$password."&varname=".$device_id."&varvalue=".$device_id;
		if ($verbose==true) echo "Sending test message to GCM server. The url is $url<br />";
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, '10');
		$data = curl_exec($ch);
		if(curl_errno($ch) && $verbose==true){
		    echo 'Curl error: ' . curl_error($ch);
		}
		if ($verose==true) print_r(curl_getinfo($ch));
		if ($verbose==true) echo "Execute complete. Here's the data: $data";
		curl_close($ch);
		//exit;
	}
}
 
function curPageURL() {
 $pageURL = 'http';
 if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
 $pageURL .= "://";
 if ($_SERVER["SERVER_PORT"] != "80") {
  $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
 } else {
  $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
 }
 return $pageURL;
}
 
 
function GetSalt() {
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // bad username
	{
		header('HTTP/1.0 401 Unauthorized');
		die("Bad Username/Password");
	}
	while ($row = mysql_fetch_assoc($result)) {
	    return $row["salt"];
	}
}
 
function GetStoredEncryptedPassword() {
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // bad username, should not happen here
	{
		header('HTTP/1.0 401 Unauthorized');
		die("Bad Username/Password");
	}
	while ($row = mysql_fetch_assoc($result)) {
	    return $row["passwordHash"];
	}
}
 
function query($query) {
if(!($result = mysql_query($query)))
	{
		die ( "MySQL Reports: " . mysql_error());
	}
return $result;
}
?>
 Posted by at 2:48 pm
Jul 312012
 

Next in the series of GCM scripts that I use, here is the script that stores registration information on the server. I have this saved as my index.php file so it is served up whenever someone navigates to my server. See http://skipstechtalk.net/2012/07/20/my-google-cloud-messaging-gcm-php-script/ for the script for actually sending GCM messages. There will also be one more script for saving device registrations.

<?php
$action = $_REQUEST['action'];
 
if ($action=='formsubmitted' || $action =='reg')
{
	$salt = getSalt();
	$encryptedPassword=hash('sha512', $salt.$_REQUEST[password]);
	for($i=0; $i<5000; $i++){
	   $encryptedPassword=hash('sha512', $salt.$encryptedPassword);
	}
 
	$dbuser = 'mydbusername';
	$dbname = 'phcadb';
	$dbpasswd = 'mydbpassword';
	$dbhost = 'my.dbhost.net';
 
	$dbh = @mysql_connect($dbhost, $dbuser, $dbpasswd);
	if (!$dbh) {
		echo "Could not connect to MySQL server on " . $dbhost;
		die();
	}
 
	if (!@mysql_select_db($dbname, $dbh)) {
		echo "Could not connect to database " . $dbname;
		die();
	}
 
	if ($_REQUEST[username] == "" | $_REQUEST[password] == "")
	{
		die ('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br />' .
		'<html>' .
		'<head>' .
		'</head>' .
		'<body>' .
		'<h1>PowerHome Connector for Android</h1><br />' .
		"Username and password may not be blank.<br /><a href='https://phc-a.net'>Click here to try again.</a>" .
		'</body>' .
		'</html>' );
	}
 
	//first see if the user already exists
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
 
	if (mysql_num_rows($result) == 0)
	{
		$sql = "INSERT INTO user (username,passwordHash,salt,registration_date,email) VALUES ('$_REQUEST[username]','$encryptedPassword','$salt', curdate(), '$_REQUEST[email]')";
		$result = query($sql);
 
		echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br />';
		echo "<html>\n";
		echo "<head>\n";
		echo "</head>\n";
		echo "<body>\n";
		echo "<h1>PowerHome Connector for Android</h1><br />\n";
		echo "username = " . $_REQUEST[username] . "<br />";
		echo "password = " . $_REQUEST[password] . "<br />";
		echo "salt = $salt<br />";
		echo "encrypted password = $encryptedPassword<br />";
		echo 'All done!<br />Now you can setup GCM notifications on your Android phone with the PowerHome Connector for Android app.<br />See <a href="http://skipstechtalk.net/powerhome-connector-for-android-usage-instructions-and-screenshots/">skipstechtalk.net</a> for a tutorial for setting up your PowerHome formulas.';
		echo '</body>\n';
		echo '</html>\n';
	}
	else
	{
		header('x', true, 401);
		echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br />';
		echo '<html>';
		echo '<head>';
		echo '</head>';
		echo '<body>';
		echo '<h1>PowerHome Connector for Android</h1><br />';
		echo "Sorry, but the username $_REQUEST[username] has already been used. Please try a different username.<br /><a href='https://phc-a.net'>Click here to try again.</a>";
		echo '</body>';
		echo '</html>';
	}
}
else
{
	echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br />';
	echo "<html>\n";
	echo "<head>\n";
	echo "</head>\n";
	echo "<body>\n";
	echo "<h1>PowerHome Connector for Android</h1><br />\n";
	echo 'Create an account so you can use the PowerHome Connector for Android app on your Android phone.<br /><br />' .
	     'Please use a username and password that you are not using anywhere else. ' .
	     'Passwords are stored in a database on this server, but are hashed 5000 times with a random salt, so it should be secure, but you never know. ' .
	     'That is why I suggest you use a username and password that you do not use anywhere else. ' .
	     'There is no personal information stored in the database. Just your login information and a registration id which routes the messages to your phone. ' .
	     'If someone does figure out how to copy the database, even though they will not have access to any personal information, you do not want them having your paypal password. ' .
	     'So, please, go the safe route and use a different password from any other website. <br/><br />' .
	     'Do remember your username and password because you will need them to send messages from PowerHome and you will need to enter it into your phone too.<br /><br />' .
	     'You may also include your email address which will be used to help you recover your username and password should you forget them. I promise I will not use it for anything else.<br /><br />' .
	     'You may register as many phones as you want with this account. This will allow you to send messages to each phone. You cannot select some messages for one phone and some messages for another. ' .
	     'It is an all or nothing deal.<br /><br />' .
	     '<b>None of the messages sent from your PowerHome application to this server are saved on this server</b>.<br /><br />' .
	     'For instructions on installing and using the PowerHome Connector for Android App, please see <a href="http://skipstechtalk.net/powerhome-connector-for-android/">http://skipstechtalk.net/powerhome-connector-for-android/</a><br /><br />';
	echo '<FORM METHOD="POST" ACTION="?action=formsubmitted">';
	echo 'Username (required): <INPUT TYPE="text" NAME="username" SIZE="30"><br />';
	echo 'Password (Required): <INPUT TYPE="text" NAME="password" SIZE="30"><br />';
	echo 'Email (optional): <INPUT TYPE="text" NAME="email" SIZE="30"><br />';
	echo '<INPUT TYPE="submit">';
	echo '</body>';
	echo '</html>';
}
 
//function md5crypt($password){
function getSalt(){
    // create a salt that ensures crypt creates an md5 hash
    $base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                    .'abcdefghijklmnopqrstuvwxyz0123456789+/';
    $salt='';
    for($i=0; $i<20; $i++){
        $salt.=$base64_alphabet[rand(0,63)];
    }
    return $salt;
}
 
function query($query) {
		if(!($result = mysql_query($query)))
        	{
            		//can't execute query
            		echo ( "Couldn't query table!<br>\n");
            		echo ( "MySQL Reports: " . mysql_error() . "<br>\n");
            		exit();
        	}
 
		return $result;
	}
?>
 Posted by at 11:51 am
Jul 202012
 

This is the script that I have on my GCM server. I am posting it here in the hopes that I can get some feedback on it, and perhaps also help some other people setting up GCM servers.

The PHP script for users to register themselves is here: http://skipstechtalk.net/2012/07/31/my-php-script-for-storing-gcm-user-registration/

The PHP script for to store device registration id’s is here: http://skipstechtalk.net/2012/07/31/my-php-script-for-gcm-device-registration/

<?php
/*
Third-party Application server for the PowerHome Connector for Android
C2DM and GCM applications. Takes an incoming HTTP GET request and
sends the correctly encoded message to the Google server, for ultimate
passing to the registered devices.
 
The requests should be sent as (all on one line, of course)
https://phc-a.net/send.php?username=myusername
	&password=mypass&var1=var1value&var2=var2value
 
additionally, requests may be sent as
https://phc-a.net/send.php?username=myusername
	&password=mypass&varname=myvar&varvalue=myvarvalue
but this format only supports a single variable/value pair.
 
The app looks at the returned message from the google server to determine if 
any changes need to be made, such as deleting registration id's
*/
 
$dbuser = 'mydbusername';
$dbname = 'phcadb';
$dbpasswd = 'mydbpassword';
$dbhost = 'my.dbhost.net';
 
// hold the data for the JSON object sent to the google server
$devices = array();
$data = array();
 
// php keeps track of the db connection. Each sql query here uses this 
// connection
$dbh = @mysql_connect($dbhost, $dbuser, $dbpasswd);
if (!$dbh) {
	echo "Could not connect to MySQL server on " . $dbhost;
	die();
}
 
if (!@mysql_select_db($dbname, $dbh)) {
	echo "Could not connect to database " . $dbname;
	die();
}
 
// used to determine whether to print debugging information
$verbose = $_REQUEST[verbose];
 
if ($verbose==true) {
	echo "<a href='help.html'>See this page for help</a><br />\n";
}
 
// for debugging, store each url in a database
//	$sql = "LOCK TABLE incomingsql WRITE";
//	query($sql);
//	$url = curPageURL();
//	$sql = "INSERT INTO incomingsql (sqlx) VALUES ('$url')";
//	$result = query($sql);
//	$sql = "UNLOCK TABLES";
//	query($sql);
 
if ($verbose==true) echo "The url was: $url<br />";
 
// check the password
$salt = GetSalt();
 
// get the stored password for the username passed in
$storedEncryptedPassword = GetStoredEncryptedPassword();
 
// hash the password that was passed in
$encryptedPassword=hash('sha512', $salt.$_REQUEST[password]);
for($i=0; $i<5000; $i++){
   $encryptedPassword=hash('sha512', $salt.$encryptedPassword);
}
 
// If the passwords match, then check for variable names and values 
// to be sent
if ($storedEncryptedPassword == $encryptedPassword) {
	if ($verbose==true) {
		echo "Username/Password match. Continue to send C2DM message.<br />";
	}
 
	// load up the $data array with the variable names and values
	foreach($_REQUEST as $key => $value) {
		switch ($key) {
			case "verbose":
			case "password":
			case "varvalue":
			case "username":
				break;
			case "varname":
				if ($verbose==true) {
					echo "Using varname/varvalue syntax<br />";
				}
				$varname = mysql_real_escape_string($value);
				$varvalue = $_REQUEST[varvalue];
 
				// prevent sql injection
				$varvalue = addslashes($varvalue);
				$varvalue = strip_tags($varvalue);
				if ($verbose==true) echo "Varname: " . $varname 
					. "; VarValue: " . $varvalue . "<br />";
				$data[$varname]=$varvalue;
				UpdateLastMessageSentTime($verbose);
				break;
			default:
				if ($verbose==true) {
					echo "Using direct variable syntax<br />";
				}
				$value = mysql_real_escape_string( $value );
 
				// prevent sql injection
				$value = addslashes($value);
				$value = strip_tags($value);
				if ($verbose==true) {
					echo "Varname: " . $key . "; VarValue: " . $value 
						. "<br />";
				}
				$data[$key]=$value;
				UpdateLastMessageSentTime($verbose);
				break;
		}
	}
}
else
{
	header('x', true, 401);
	die("Bad Username/Password");
}
 
if ($verbose==true) {
	echo "The data array is:<br />";
	print_r($data);
	echo "<br />";
}
 
// get all of the user's GCM devices
$sql = "SELECT * FROM userdevices WHERE username = "
           . "'$_REQUEST[username]' AND message_type='GCM'";
$result = query($sql);
if ($verbose==true) echo "Sending to the following GCM devices:<br />";
$devicecount = mysql_num_rows($result);
if ($devicecount==0) {
	if ($verbose==true) echo "--none--<br />";
}
while ($row = mysql_fetch_array($result)) {
	array_push($devices, $row[registration_id]);
	if ($verbose==true) echo $row[phone_name] . "<br />";
}
 
$devicecount = mysql_num_rows($result);
if ($devicecount>0) {
	if ($verbose==true) echo "There are $devicecount GCM devices<br />";
	SendGCM($verbose, $devices, $data);
}
 
// reset devices for C2DM
$devices = array();
 
// get all of the user's C2DM devices
$sql = "SELECT * FROM userdevices WHERE username = "
     . "'$_REQUEST[username]' AND message_type='C2DM'";
$result = query($sql);
$devicecount = mysql_num_rows($result);
if ($verbose==true) echo "There are $devicecount C2DM devices<br />";
if ($verbose==true) echo "Sending to the following C2DM devices:<br />";
if ($devicecount==0) {
	if ($verbose==true) echo "--none--<br />";
}
while ($row = mysql_fetch_array($result)) {
	array_push($devices, $row[registration_id]);
	if ($verbose==true) echo $row[phone_name] . "<br />";
}
 
foreach ($devices as $device) {
	SendC2DM($verbose, $device, $data);
}
 
// All done!
 
//
//
// FUNCTIONS go below here
//
//
function SendGCM ($verbose, $devices, $data) {
	if ($verbose==true) {
		echo "The data array is:<br />";
		print_r($data);
		echo "<br />";
		echo "The GCM devices array is:<br />";
		print_r($devices);
		echo "<br />";
	}
	$message = json_encode(array("registration_ids"=>$devices, 
		"data"=>$data));
	if ($verbose==true) echo "JSON message:<br />";
	if ($verbose==true) echo "$message" . "<br />";
	if ($verbose==true) echo "Sending over GCM<br />";
 
	// My GCM API key. KEEP SECRET!!!!!
	$phcaApiKey = "AIzaSAbCdEfGhIjKlnjkyXp-DCUMnOpQra8"; // SECRET!!!
 
	$url = "https://android.googleapis.com/gcm/send";
 
	$headers = array('Authorization: key=' . $phcaApiKey, 
		"Content-Type: application/json");
 
	if ($verbose==true) echo "Sending POST to GCM server. <br />";
 
	$x = curl_init($url); 
	curl_setopt($x, CURLOPT_HTTPHEADER, $headers);
	curl_setopt($x, CURLOPT_HEADER, 1); 
	curl_setopt($x, CURLOPT_POST, 1); 
	curl_setopt($x, CURLOPT_POSTFIELDS, $message); 
	curl_setopt($x, CURLOPT_RETURNTRANSFER, 1); 
	curl_setopt($x, CURLOPT_SSL_VERIFYPEER, false);
	$response = curl_exec($x); 
	$http_code = curl_getinfo($x, CURLINFO_HTTP_CODE);
 
	// request has been sent. Now get the response. The response 
	// is in the form of a JSON object, formatted as
	/*
		{ "multicast_id": 216,
		  "success": 3,
		  "failure": 3,
		  "canonical_ids": 1,
		  "results": [
		    { "message_id": "1:0408" },
		    { "error": "Unavailable" },
		    { "error": "InvalidRegistration" },
		    { "message_id": "1:1516" },
		    { "message_id": "1:2342", "registration_id": "32" },
		    { "error": "NotRegistered"}
		  ]
		}
	*/
 
	$header_size = curl_getinfo($x,CURLINFO_HEADER_SIZE);
	$body = substr( $response, $header_size );
 
	$json_response = json_decode($body);
	$results = $json_response->results;
 
	// first, print some debugging information
	if ($verbose==true) {
		echo "The response from the C2DM server was:<br />";
		print_r ($response);
		echo "<br />";
		$header = substr($response, 0, $header_size);
		echo "Header: $header<br />\n";
		echo "Body: $body<br />\n";
		echo "JSON decoded response:<br />";
		print_r($json_response);
		echo "<br />";
		echo "Results:<br />";
		print_r($results);
		echo "<br />";
	}
 
	$device_number = 0;
	foreach ($results as $device_response) {
		if (is_array($device_response)) {
			// only happens when a registration id needs to be updated.
			$old_id = $devices->$device_number;
			$new_id = $device_response->registration_id;
			if ($verbose==true) {
				echo "Updating the registration id from "
				   . "$old_id to $new_id.<br />\n";
			}
			$sql = "userdevices SET registration_id = "
			     . "'$new_id' WHERE registration_id='$old_id'";
			if ($verbose==true) echo $sql . "<br />";
			$result2 = query($sql);
		} else {
			if ($device_response->error == "NotRegistered") {
				// delete the device from the userdevices table
				if ($verbose==true) {
					echo "Deleting this entry from the devices table. "
					. "It has been unregistered.<br />\n";
				}
				$sql = "LOCK TABLE userdevices WRITE";
				query($sql);
				$sql = "DELETE FROM userdevices WHERE registration_id='"
 				   . $devices[$device_number] . "'";
				if ($verbose==true) echo $sql . "<br />";
				$result2 = query($sql);
				if ($verbose==true) echo "The result was: ";
				if ($verbose==true) print_r ($result2);
				$sql = "UNLOCK TABLES";
				query($sql);
			}
			if ($device_response->error == "InvalidRegistration") {
				// Not very likely. Possible corruption in the database???
				if ($verbose==true) {
					echo "ERROR!! Invalid Registration should never "
					. "happen. Please inform the developer and perhaps "
					. "try unregistering and re-registering your device.";
				}
			}
			if ($device_response->error == "Unavailable") {
				// GCM Service is temporarily down. Try again later
				if ($verbose==true) {
					echo "Google GCM dervice is temporarily down. Try "
					. "sending again later.";
				}
			}
		}
		$device_number++;
	}
 
	// close the curl object
	curl_close($x); 
 
	if ($verbose==true) {
		echo "You should not see any errors in the response. If there "
		. "are no errors, you should see an updated variable in the "
		. "status text on your phone.<br />";
	}
}
 
function SendC2DM($verbose, $device, $data) {
 
	if ($verbose==true) echo "Sending over C2DM<br />";
	/*
	Ultimately, this is how the request should be formatted:
	curl --header "Authorization: GoogleLogin auth=your_authenticationid" \
	"https://android.apis.google.com/c2dm/send" \
	-d registration_id=your_registration \
	-d "data.payload=This data will be send to your application as payload" \
	-d collapse_key=0
	*/
	$googleAuth = "A-VERY-LONG-STRING-WITH-A-BUNCH-OF-LETTERS-AND-NUMBERS";
	/*
	$google Auth can be obtained using curl like this:
	(all on one line, begin below this line)
	C:\>curl https://www.google.com/accounts/ClientLogin 
		-d Email=skip.morrow.mobile@gmail.com 
		-d "Passwd=kklirctpnucvnelf" 
		-d accountType=GOOGLE 
		-d source=Google-cURL-Example -d service=ac2dm -k
	(end of command)
 
	Note that the password is a one-time use, application specific password.
 
	*/
 
	$url = "https://android.apis.google.com/c2dm/send";
	//$regid = GetRegId();
	$data_msg .= urlencode($key) ."=". urlencode($value); 
	$size=strlen($data_msg);
 
	$data_msg = "";
 
	if ($verbose==true) echo "<br />Registration_id = " 
		. $device . "<br />";
 
	// add "data." to all of the keys in the $data array
 
	foreach($data as $key => $value) {
		$data["data." . $key] = $value;
		unset($data[$key]);
	}
	// $data has all of the variables. Just add the registration_id 
	// and collapse_key and it will be ready to send
	$data["registration_id"]=$device;
	$collapse_key = date("Hi");
 
	$data["collapse_key"]=$collapse_key;
 
	if ($verbose==true) print_r ($data);
	if ($verbose==true) echo "<br />";
	//echo "Headers: ";
	$headers = array('Authorization: GoogleLogin auth=' . $googleAuth);
	//print_r($headers);
	if ($verbose==true) echo "Sending POST to C2DM server. <br />";
 
	$x = curl_init("https://android.apis.google.com/c2dm/send"); 
	if ($headers) curl_setopt($x, CURLOPT_HTTPHEADER, $headers);
	curl_setopt($x, CURLOPT_HEADER, 1); 
	curl_setopt($x, CURLOPT_POST, 1); 
	curl_setopt($x, CURLOPT_POSTFIELDS, $data); 
	curl_setopt($x, CURLOPT_RETURNTRANSFER, 1); 
	curl_setopt($x, CURLOPT_SSL_VERIFYPEER, false);
	$data = curl_exec($x); 
	curl_close($x); 
	$response = $data;
	if ($verbose==true) {
		echo "The response from the C2DM server was:<br />";
		print_r ($data);
		echo "<br />";
		echo "<br />";
		echo "<br />\n";
		echo "You should not see any errors in the response. "
			. "If there are no errors, you should see an updated "
			. "variable in the status text on your phone.<br />";
	}
}
 
function curPageURL() {
 $pageURL = 'http';
 if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
 $pageURL .= "://";
 if ($_SERVER["SERVER_PORT"] != "80") {
  $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"]
	.$_SERVER["REQUEST_URI"];
 } else {
  $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
 }
 return $pageURL;
}
 
function GetRegId() {
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // bad username
	{
		header('x', true, 401);
		die("Bad Username");
	}
	while ($row = mysql_fetch_assoc($result)) {
	    return $row["regId"];
	}
}
 
 
function GetSalt() {
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // bad username
	{
		header('x', true, 401);
		die("Bad Username");
	}
	while ($row = mysql_fetch_assoc($result)) {
	    return $row["salt"];
	}
}
 
function GetStoredEncryptedPassword() {
	$sql = "SELECT * FROM user WHERE username = '$_REQUEST[username]'";
	$result = query($sql);
	if (mysql_num_rows($result) == 0) // bad username, should not happen
	{
		header('x', true, 401);
		die("Bad Username");
	}
	while ($row = mysql_fetch_assoc($result)) {
	    return $row["passwordHash"];
	}
}
 
function UpdateLastMessageSentTime() {
	$sql = "LOCK TABLE user WRITE";
	query($sql);
	$sql = "UPDATE user SET last_msg_timestamp=now() WHERE username = "
	. "'$_REQUEST[username]'";
	$result = query($sql);
	$sql = "UNLOCK TABLES";
	query($sql);
}
 
function query($query) {
if(!($result = mysql_query($query)))
	{
		//can't execute query
		if ($verbose==true) echo ( "Couldn't query table!<br>\n");
		if ($verbose==true) {
			echo ( "MySQL Reports: " . mysql_error() . "<br>\n");
		}
		exit();
	}
return $result;
}
?>

Here’s the SQL scripts to create the database tables that I am using:

 
-- phpMyAdmin SQL Dump
-- version 3.3.10.4
-- http://www.phpmyadmin.net
--
-- Host: my.dbhost.net
-- Generation Time: Jul 20, 2012 at 11:07 AM
-- Server version: 5.1.39
-- PHP Version: 5.2.17
 
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
 
--
-- Database: `phcadb`
--
 
-- --------------------------------------------------------
 
--
-- Table structure for table `incomingsql`
--
 
CREATE TABLE IF NOT EXISTS `incomingsql` (
  `index` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `sqlx` VARCHAR(1024) NOT NULL,
  PRIMARY KEY (`index`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
-- --------------------------------------------------------
 
--
-- Table structure for table `user`
--
 
CREATE TABLE IF NOT EXISTS `user` (
  `username` VARCHAR(64) NOT NULL,
  `passwordHash` VARCHAR(1024) NOT NULL,
  `salt` VARCHAR(26) NOT NULL,
  `registration_date` DATE NOT NULL,
  `email` VARCHAR(60) DEFAULT NULL,
  `last_msg_timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
-- --------------------------------------------------------
 
--
-- Table structure for table `userdevices`
--
 
CREATE TABLE IF NOT EXISTS `userdevices` (
  `registration_id` VARCHAR(256) NOT NULL,
  `username` VARCHAR(64) NOT NULL,
  `device_id` VARCHAR(128) NOT NULL,
  `is_sending` tinyint(1) NOT NULL,
  `message_type` enum('C2DM','GCM') DEFAULT NULL COMMENT 'Either C2DM or GCM',
  `phone_name` VARCHAR(64) DEFAULT NULL,
  PRIMARY KEY (`registration_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 Posted by at 5:54 pm