<?php


	// apress.php
	// quick and dirty apns "self-contained" example server for apress chapter
	// reflects messages from known users to the entire user base

	// AUTHOR INFO
	// Copyright Joe Pezzillo, 2009, All Rights Reserved
	
	// 
	// NO WARRANTY, USE AT OWN RISK
	// USE OF CODE IS AGREEMENT TO HOLD AUTHOR HARMLESS AGAINST ANY CLAIMS
	// AUTHOR MAKES NO WARRANTIES OR REPRESENTATIONS OF ANY KIND WHATSOEVER
	
	
	// REQUIRES: BASIC PHP SITE HOSTING EXPERIENCE
	

	// YOUR CERTIFICATE	
	$certificate = '';
	$certificate_password = ''; // passphrase for the certificate file, we left it blank
	$APPLE_SERVER = 'ssl://gateway.sandbox.push.apple.com:2195';
	
	
	// YOUR MYSQL DATABASE CONNECTION
	$hostname = 'HOST';
	$username = 'USERNAME';
	$password = 'PASSWORD';

	
	// bogus token, if you use it, remember to remove it from your DB!
	$example_token = '1dfc17527407d39bcd1d69defa7ab3e7ae5f9d7a87b0cc69bd3020b369c0b8d9'; 
	

	//	STEP ONE:
	// SETUP THIS DATABASE:
	/*
	CREATE TABLE  `apresschapter`.`apressdevices` (
		`device_token` VARCHAR( 64 ) NOT NULL ,
		`username` VARCHAR( 32 ) NOT NULL
		) ENGINE = MYISAM COMMENT =  'Simple database to hold Apress Push Chapter Sample Server Registrations'

			
	*/

	$database = 'apresschapter';
	$table = 'apressdevices';
		
	$db_link = mysql_connect($hostname, $username, $password);

	mysql_select_db( $database ) or die('ConnectToMySQL: Could not select database: ' . $database );

	$result = ini_set ( 'mysql.connect_timeout' , '60' );
	
		
	// take in either a registration, or a message and respond apropriately
	
	// registration: incoming: devicetoken + (arbitrary, username?)
	
	// message: incoming: devicetoken + message
	
	
	// ?token=TOKEN&cmd=(REG|MSG)&(name|msg)=(NAME|MSGBODY)
	
	if( ! isset( $_GET['token'] ) ) {

		// all commands require a device token
		
		$q = "SELECT DISTINCT(device_token),username FROM $database.$table";

		$result = mysql_query($q);
		$count = mysql_num_rows($result);
		if( $count > 0 ) {
			$rec = mysql_fetch_assoc($result);
			$example_token = $rec['device_token']; // the first device registered, presumably the developer's
		}
				
		$infotext = <<<INFOTEXT
			<font face="monospace">
			<br/>
			<blockquote>
			Apress.php<br/>
			Sample server program for use with Apress Push Notification Chapter<br/>
			<br/>
			Usage:<br/>
			?token=DEVICE_TOKEN&cmd=(reg|msg)&(name|msg)=(USERNAME OR MESSAGE)<br/>
			<br/>
			e.g.<br/>
			<br/>
			Register a token:<br/>
			?token=$example_token&cmd=reg&name=test<br/>
			<br/>
			Send a message:<br/>
			?token=$example_token&cmd=msg&msg=Hello,%20World!<br/>
			<br/>
			<br/>
			<br/>
			You have $count devices in your database.
			</blockquote>
			</font>			
INFOTEXT;
		
		print( $infotext );

	} else {
		
		if( isset( $_GET['cmd'] ) && ( $_GET['cmd'] == 'reg' || $_GET['cmd'] == 'msg' ) ) {
		
			if( $_GET['cmd'] == 'reg' ) {
				
				if( isset($_GET['name']) ) {
				
					// GOOD: write token + name to persistent registered devices list
					print( "Write token to registrations<br/>" );
					
					$token = mysql_escape_string($_GET['token']);
					$name = mysql_escape_string($_GET['name']);
					
						$q = "INSERT INTO $database.$table (`device_token`,`username`) VALUES ('$token','$name' )";
						
						$result = mysql_query($q);
						
						if( mysql_affected_rows() > 0 ) {
							print( "success registering" );
						} else {
							print( "error while registering" );
						}


				} else {
					
					// registration requires a name to be passed it to go with token
					
				}
			
			} else if( $_GET['cmd'] == 'msg' ) {
				
				if( isset($_GET['msg']) ) {
					
					// GOOD: we now have the message body
					// is token in registered devices list?
					// is message compliant (length, characters)
					// send it

					print( "Send message<br/>" );
					
					$q = "SELECT DISTINCT(device_token),username FROM $database.$table";
					
					$result = mysql_query($q);
					$devices = array();
					$validated_sender = FALSE;
					$sender_name = 'Unknown';

					while( $rec = mysql_fetch_assoc($result) ) {
						
						if( $_GET['token'] == $rec['device_token'] ) {
							$validated_sender = TRUE;
							$sender_name = $rec['username'];
						}
						print( "user+device:" . $rec['username'] . '+' . $rec['device_token'] . "<br/>" );
						
						// build the device list to be sent to here
						array_push($devices,$rec['device_token']);
						
					}
					
					if( $validated_sender ) {
						// send them in one batch here
						
						// check the name here? - future development: is the submitted name the same as the registered name?
						if( isset( $_GET['name'] ) && strlen($_GET['name']) ) {
							$sender_name = $_GET['name'];
						}
						$alert = $sender_name . ' says ' . $_GET['msg'];
						$sound = '';
						$badge = '';
						
						$custom = $sender_name;
						
						send_apns_to_devices($devices,$alert,$sound,$badge,$custom);
						
					} else {
						// we don't know the sender token
					}			
					
				} else {
					
					// message command requires a message
				
				}
				
				
			} else {
				
				// unknown command - shouldn't get here, but for future expansion
				
			}
		
		
		} else {
			
			// invalid command, either command not present, or not valid command
			
		}
	
	}

	function send_apns_to_devices($device_list,$alert,$sound,$badge,$custom)
	{
		
		global $APPLE_SERVER;
		global $certificate;
		global $certificate_password;
		
		// The actual notification payload
		$notification = array();
		if( strlen($alert) > 0 ) {
			$notification['alert'] = $alert;
		}
		
		if( strlen($sound) > 0 ) {
			$notification['sound'] = $sound;
		}
		
		if( is_numeric($badge) ) {
			$notification['badge'] = $badge;
		}
				
		$body['aps'] = $notification;

		// presumes $custom is string only
		if( strlen($custom) != 0 ) {
			$body['custom'] = $custom;
		}


		// CONNECT		
		$ctx = stream_context_create();

		stream_context_set_option($ctx, 'ssl', 'local_cert', $certificate );
		stream_context_set_option($ctx, 'ssl', 'passphrase', $certificate_password );

		$fp = stream_socket_client( $APPLE_SERVER, $err, $errstr, 15, STREAM_CLIENT_CONNECT, $ctx);

		if (!$fp) {
			print "Failed to connect $err $errstr\n";
			return;
		}

		// SEND
		foreach( $device_list as $device ) {
			$payload = json_encode($body);
			// format the message
			$msg = chr(0) . chr(0) . chr(32) . pack('H*', $device) . chr(0) . chr(strlen($payload)) . $payload;
			
			fwrite($fp, $msg);
		}
		
		
		// CLOSE CONNECTION
		fclose($fp);
		
		
	}
	
?>