<?php
/*
	Class to send push notifications using Google Cloud Messaging for Android

	Example usage
	-----------------------
	$an = new GCMPushMessage($apiKey);
	$an->setDevices($devices);
	$response = $an->send($message);
	-----------------------
	
	$apiKey Your GCM api key
	$devices An array or string of registered device tokens
	$message The mesasge you want to push out

	@author YwLabs

	GCM 라이프 사이클

	1. GCM 활성화
	모바일 디바이스에서 실행되는 앱이 푸시 메시지를 수신하기 위해서 등록하는 과정에서 발생된다. 그 등록 과정은 아래와 같다.
	GCM 서버에 registration Intent를 발송한다. registration Intent(com.google.android.c2dm.intent.REGISTER)는 Sender ID와 안드로이드 애플리케이션 ID를 포함한다. 이 등록 프로세스는 라이프 사이클 메소드가 없기 때문에 미등록 된 경우만 등록을 해야하고, 등록 부분은 onCreate()함수 안에서 처리하면 된다.
	등록이 성공하면 GCM서버에서 리턴 값으로 안드로이드 애플리케이션에 대한 Registration ID를 부여 받는다. Google은 이 Registration ID를 정기적으로 갱신할 수 있어서 안드로이드 애플리켄이션에서는 이점을 잘 이해해 설계를 해야한다.
	등록을 완료하기 위해서 안드로이드 애플리케이션은 Registration ID를 애플리케이션 서버로 전송한다. 그리고 Registration ID는 일반적으로 데이터 베이스에 저장된다. 이 Registration ID는 안드로이드 애플리케이션에서 unregisters 하거나 구글이 새로 수정될때까지 애플리케이션 서버와 안드로이드 앱에서 유지된다. 나중에 이 Registration ID로 메세지를 발송할 수 있게 된다.
	주의: 사용자가 애플리케이션을 제거할 때 Registration ID는 GCM상에서 자동으로 등록이 해제되지는 않는다. 등록이 해제되는 경우는 GCM 서버가 모바일 디바이스에 메시지 전송을 시도하고 애플리케이션이 제거되었다는 응답을 받을 때 뿐이다. 이때 여러분의 서버는 등록이 해제된 것으로 모바일 디바이스에 기록해야 한다. (그 때 서버는 NotRegistered 오류를 받게 된다.)
	
	GCM 서버에서 Registration ID 삭제를 완료하는 데에는 몇 분이 걸릴 수 있다는 점에 유의하라. 즉, 3'd Party 애플리케이션 서버가 이전에 메시지를 보내면 메시지가 모바일 디바이스로 전달되지 않는 경우에도 3'd Party 애플리케이션 서버는 유효한 메시지 ID를 얻을 수도 있다.
	
	2. 메세지 전송
	메세지 전송을 위해서는 Registration ID와 API KEY가 필요하다. API 키 취득 방법은 아래 안드로이드 앱 만들기에서 참조하면 된다.
	애플리케이션 서버가 Android 앱에 메시지를 전송하기 위해 다음을 갖추고 있어야 한다.
	Android 앱은 특정 디바이스에 메시지를 받을 수 있도록 registration ID를 가지고 있어야 한다.
	3'd Party 애플리케이션 서버가 registration ID를 저장한다.
	API 키. 이것은 개발자가 Android 애플리케이션을 위한 애플리케이션 서버에서 이미 설치가 완료되지 않으면 안된다. (자세한 사항은 3'd Party 애플리케이션 서버의 역할을 참조). API 키는 모바일 디바이스에 메시지를 보내기 위해 사용된다.
	다음은 3'rd Party 애플리케이션 서버가 메세지를 보낼 때 발생하는 이벤트의 순서이다.
	애플리케이션 서버가 GCM 서버에 메시지를 보낸다.
	모바일 디바이스가 오프라인 상태인 경우에 대비해 Google이 메시지를 저장하고 대기열에도 저장한다.
	모바일 디바이스가 온라인 상태가 되면, Google이 해당 모바일 디바이스에 메시지를 보낸다.
	모바일 디바이스는 적절한 권한을 가진 안드로이드 애플리케이션의 Intent broadcast를 사용해서 메세지를 브로드캐스트함으로써 대상 애플리케이션만 메세지를 받을 수 있다. 그러면 안드로이드 애플리케이션이 깨어나게 된다. 즉, 안드로이드 애플리케이션은 메세지를 수신하기 전에 이미 실행되어 있을 필요는 없다.
	안드로이드 애플리케이션은 메세지를 처리한다. 안드로이드 애플리케이션이 중요한 작업을 수행하는 경우, PowerManager.WakeLock을 차단하고 서비스에서 모든 처리를 하는 것이 좋다.
	
	3. 메세지 수신
	다음은 모바일 디바이스에 설치된 Android 애플리케이션이 메시지를 받을 때 발생하는 이벤트의 순서이다.
	시스템은 들어온 메시지를 수신 메시지의 페이로드에서 원시 키/밸류 쌍을 추출한다.
	시스템은 키/밸류 쌍을 com.google.android.c2dm.intent.RECEIVE Intent를 엑스트라의 세트로 대상 Android 애플리케이션에 전달한다.
	Android 애플리케이션은 com.google.android.c2dm.intent.RECEIVE Intent에서 키의 원시 데이터를 추출하고 데이터를 처리한다.
	 * 
*/
class GCMPushMessage {

	var $url = 'https://android.googleapis.com/gcm/send';
	var $serverApiKey = "";
	var $devices = array();
	
	/*
		Constructor
		@param $apiKeyIn the server API key
	*/
	function GCMPushMessage($apiKeyIn){
		$this->serverApiKey = $apiKeyIn;
	}

	/*
		Set the devices to send to
		@param $deviceIds array of device tokens to send to
	*/
	function setDevices($deviceIds){
	
		if(is_array($deviceIds)){
			$this->devices = $deviceIds;
		} else {
			$this->devices = array($deviceIds);
		}
	
	}

	/*
		Send the message to the device
		@param $message The message to send
		@param $data Array of data to accompany the message
	*/
	function send($message, $data = false){
		
		if(!is_array($this->devices) || count($this->devices) == 0){
			$this->error("No devices set");
		}
		
		if(strlen($this->serverApiKey) < 8){
			$this->error("Server API Key not set");
		}
		
		$fields = array(
			'registration_ids'  => $this->devices,
			'data'              => array( "message" => $message ),
		);
		
		if(is_array($data)){
			foreach ($data as $key => $value) {
				$fields['data'][$key] = $value;
			}
		}

		$headers = array( 
			'Authorization: key=' . $this->serverApiKey,
			'Content-Type: application/json'
		);

		// Open connection
		$ch = curl_init();
		
		// Set the url, number of POST vars, POST data
		curl_setopt( $ch, CURLOPT_URL, $this->url );
		
		curl_setopt( $ch, CURLOPT_POST, true );
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
		
		curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $fields ) );
		
		// Execute post
		$result = curl_exec($ch);
		
		// Close connection
		curl_close($ch);
		
		return $result;
	}
	
	function error($msg){
		echo "Android send notification failed with error:";
		echo "\t" . $msg;
		exit(1);
	}
}