<?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;
}
?> |