2013-11-25 17:57:19 -08:00

465 lines
12 KiB
PHP
Executable File

<?php
/**
* @file
* ApnsPHP_Message class definition.
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://code.google.com/p/apns-php/wiki/License
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to aldo.armiento@gmail.com so we can send you a copy immediately.
*
* @author (C) 2010 Aldo Armiento (aldo.armiento@gmail.com)
* @version $Id$
*/
/**
* @defgroup ApnsPHP_Message Message
* @ingroup ApplePushNotificationService
*/
/**
* The Push Notification Message.
*
* The class represents a message to be delivered to an end user device.
* Notification Service.
*
* @ingroup ApnsPHP_Message
* @see http://tinyurl.com/ApplePushNotificationPayload
*/
class ApnsPHP_Message
{
const PAYLOAD_MAXIMUM_SIZE = 256; /**< @type integer The maximum size allowed for a notification payload. */
const APPLE_RESERVED_NAMESPACE = 'aps'; /**< @type string The Apple-reserved aps namespace. */
protected $_bAutoAdjustLongPayload = true; /**< @type boolean If the JSON payload is longer than maximum allowed size, shorts message text. */
protected $_aDeviceTokens = array(); /**< @type array Recipients device tokens. */
protected $_sText; /**< @type string Alert message to display to the user. */
protected $_nBadge; /**< @type integer Number to badge the application icon with. */
protected $_sSound; /**< @type string Sound to play. */
protected $_bContentAvailable; /**< @type boolean True to initiates the Newsstand background download. @see http://tinyurl.com/ApplePushNotificationNewsstand */
protected $_aCustomProperties; /**< @type mixed Custom properties container. */
protected $_nExpiryValue = 604800; /**< @type integer That message will expire in 604800 seconds (86400 * 7, 7 days) if not successful delivered. */
protected $_mCustomIdentifier; /**< @type mixed Custom message identifier. */
/**
* Constructor.
*
* @param $sDeviceToken @type string @optional Recipients device token.
*/
public function __construct($sDeviceToken = null)
{
if (isset($sDeviceToken)) {
$this->addRecipient($sDeviceToken);
}
}
/**
* Add a recipient device token.
*
* @param $sDeviceToken @type string Recipients device token.
* @throws ApnsPHP_Message_Exception if the device token
* is not well formed.
*/
public function addRecipient($sDeviceToken)
{
if (!preg_match('~^[a-f0-9]{64}$~i', $sDeviceToken)) {
throw new ApnsPHP_Message_Exception(
"Invalid device token '{$sDeviceToken}'"
);
}
$this->_aDeviceTokens[] = $sDeviceToken;
}
/**
* Get a recipient.
*
* @param $nRecipient @type integer @optional Recipient number to return.
* @throws ApnsPHP_Message_Exception if no recipient number
* exists.
* @return @type string The recipient token at index $nRecipient.
*/
public function getRecipient($nRecipient = 0)
{
if (!isset($this->_aDeviceTokens[$nRecipient])) {
throw new ApnsPHP_Message_Exception(
"No recipient at index '{$nRecipient}'"
);
}
return $this->_aDeviceTokens[$nRecipient];
}
/**
* Get the number of recipients.
*
* @return @type integer Recipient's number.
*/
public function getRecipientsNumber()
{
return count($this->_aDeviceTokens);
}
/**
* Get all recipients.
*
* @return @type array Array of all recipients device token.
*/
public function getRecipients()
{
return $this->_aDeviceTokens;
}
/**
* Set the alert message to display to the user.
*
* @param $sText @type string An alert message to display to the user.
*/
public function setText($sText)
{
$this->_sText = $sText;
}
/**
* Get the alert message to display to the user.
*
* @return @type string The alert message to display to the user.
*/
public function getText()
{
return $this->_sText;
}
/**
* Set the number to badge the application icon with.
*
* @param $nBadge @type integer A number to badge the application icon with.
* @throws ApnsPHP_Message_Exception if badge is not an
* integer.
*/
public function setBadge($nBadge)
{
if (!is_int($nBadge)) {
throw new ApnsPHP_Message_Exception(
"Invalid badge number '{$nBadge}'"
);
}
$this->_nBadge = $nBadge;
}
/**
* Get the number to badge the application icon with.
*
* @return @type integer The number to badge the application icon with.
*/
public function getBadge()
{
return $this->_nBadge;
}
/**
* Set the sound to play.
*
* @param $sSound @type string @optional A sound to play ('default sound' is
* the default sound).
*/
public function setSound($sSound = 'default')
{
$this->_sSound = $sSound;
}
/**
* Get the sound to play.
*
* @return @type string The sound to play.
*/
public function getSound()
{
return $this->_sSound;
}
/**
* Initiates the Newsstand background download.
* @see http://tinyurl.com/ApplePushNotificationNewsstand
*
* @param $bContentAvailable @type boolean True to initiates the Newsstand background download.
* @throws ApnsPHP_Message_Exception if ContentAvailable is not a
* boolean.
*/
public function setContentAvailable($bContentAvailable = true)
{
if (!is_bool($bContentAvailable)) {
throw new ApnsPHP_Message_Exception(
"Invalid content-available value '{$bContentAvailable}'"
);
}
$this->_bContentAvailable = $bContentAvailable ? true : null;
}
/**
* Get if should initiates the Newsstand background download.
*
* @return @type boolean Initiates the Newsstand background download property.
*/
public function getContentAvailable()
{
return $this->_bContentAvailable;
}
/**
* Set a custom property.
*
* @param $sName @type string Custom property name.
* @param $mValue @type mixed Custom property value.
* @throws ApnsPHP_Message_Exception if custom property name is not outside
* the Apple-reserved 'aps' namespace.
*/
public function setCustomProperty($sName, $mValue)
{
if ($sName == self::APPLE_RESERVED_NAMESPACE) {
throw new ApnsPHP_Message_Exception(
"Property name '" . self::APPLE_RESERVED_NAMESPACE . "' can not be used for custom property."
);
}
$this->_aCustomProperties[trim($sName)] = $mValue;
}
/**
* Get the first custom property name.
*
* @deprecated Use getCustomPropertyNames() instead.
*
* @return @type string The first custom property name.
*/
public function getCustomPropertyName()
{
if (!is_array($this->_aCustomProperties)) {
return;
}
$aKeys = array_keys($this->_aCustomProperties);
return $aKeys[0];
}
/**
* Get the first custom property value.
*
* @deprecated Use getCustomProperty() instead.
*
* @return @type mixed The first custom property value.
*/
public function getCustomPropertyValue()
{
if (!is_array($this->_aCustomProperties)) {
return;
}
$aKeys = array_keys($this->_aCustomProperties);
return $this->_aCustomProperties[$aKeys[0]];
}
/**
* Get all custom properties names.
*
* @return @type array All properties names.
*/
public function getCustomPropertyNames()
{
if (!is_array($this->_aCustomProperties)) {
return array();
}
return array_keys($this->_aCustomProperties);
}
/**
* Get the custom property value.
*
* @param $sName @type string Custom property name.
* @throws ApnsPHP_Message_Exception if no property exists with the specified
* name.
* @return @type string The custom property value.
*/
public function getCustomProperty($sName)
{
if (!array_key_exists($sName, $this->_aCustomProperties)) {
throw new ApnsPHP_Message_Exception(
"No property exists with the specified name '{$sName}'."
);
}
return $this->_aCustomProperties[$sName];
}
/**
* Set the auto-adjust long payload value.
*
* @param $bAutoAdjust @type boolean If true a long payload is shorted cutting
* long text value.
*/
public function setAutoAdjustLongPayload($bAutoAdjust)
{
$this->_bAutoAdjustLongPayload = (boolean)$bAutoAdjust;
}
/**
* Get the auto-adjust long payload value.
*
* @return @type boolean The auto-adjust long payload value.
*/
public function getAutoAdjustLongPayload()
{
return $this->_bAutoAdjustLongPayload;
}
/**
* PHP Magic Method. When an object is "converted" to a string, JSON-encoded
* payload is returned.
*
* @return @type string JSON-encoded payload.
*/
public function __toString()
{
try {
$sJSONPayload = $this->getPayload();
} catch (ApnsPHP_Message_Exception $e) {
$sJSONPayload = '';
}
return $sJSONPayload;
}
/**
* Get the payload dictionary.
*
* @return @type array The payload dictionary.
*/
protected function _getPayload()
{
$aPayload[self::APPLE_RESERVED_NAMESPACE] = array();
if (isset($this->_sText)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['alert'] = (string)$this->_sText;
}
if (isset($this->_nBadge) && $this->_nBadge >= 0) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['badge'] = (int)$this->_nBadge;
}
if (isset($this->_sSound)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['sound'] = (string)$this->_sSound;
}
if (isset($this->_bContentAvailable)) {
$aPayload[self::APPLE_RESERVED_NAMESPACE]['content-available'] = (int)$this->_bContentAvailable;
}
if (is_array($this->_aCustomProperties)) {
foreach($this->_aCustomProperties as $sPropertyName => $mPropertyValue) {
$aPayload[$sPropertyName] = $mPropertyValue;
}
}
return $aPayload;
}
/**
* Convert the message in a JSON-encoded payload.
*
* @throws ApnsPHP_Message_Exception if payload is longer than maximum allowed
* size and AutoAdjustLongPayload is disabled.
* @return @type string JSON-encoded payload.
*/
public function getPayload()
{
$sJSON = json_encode($this->_getPayload(), defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0);
if (!defined('JSON_UNESCAPED_UNICODE') && function_exists('mb_convert_encoding')) {
$sJSON = preg_replace_callback(
'~\\\\u([0-9a-f]{4})~i',
create_function('$aMatches', 'return mb_convert_encoding(pack("H*", $aMatches[1]), "UTF-8", "UTF-16");'),
$sJSON);
}
$sJSONPayload = str_replace(
'"' . self::APPLE_RESERVED_NAMESPACE . '":[]',
'"' . self::APPLE_RESERVED_NAMESPACE . '":{}',
$sJSON
);
$nJSONPayloadLen = strlen($sJSONPayload);
if ($nJSONPayloadLen > self::PAYLOAD_MAXIMUM_SIZE) {
if ($this->_bAutoAdjustLongPayload) {
$nMaxTextLen = $nTextLen = strlen($this->_sText) - ($nJSONPayloadLen - self::PAYLOAD_MAXIMUM_SIZE);
if ($nMaxTextLen > 0) {
while (strlen($this->_sText = mb_substr($this->_sText, 0, --$nTextLen, 'UTF-8')) > $nMaxTextLen);
return $this->getPayload();
} else {
throw new ApnsPHP_Message_Exception(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes. The message text can not be auto-adjusted."
);
}
} else {
throw new ApnsPHP_Message_Exception(
"JSON Payload is too long: {$nJSONPayloadLen} bytes. Maximum size is " .
self::PAYLOAD_MAXIMUM_SIZE . " bytes"
);
}
}
return $sJSONPayload;
}
/**
* Set the expiry value.
*
* @param $nExpiryValue @type integer This message will expire in N seconds
* if not successful delivered.
*/
public function setExpiry($nExpiryValue)
{
if (!is_int($nExpiryValue)) {
throw new ApnsPHP_Message_Exception(
"Invalid seconds number '{$nExpiryValue}'"
);
}
$this->_nExpiryValue = $nExpiryValue;
}
/**
* Get the expiry value.
*
* @return @type integer The expire message value (in seconds).
*/
public function getExpiry()
{
return $this->_nExpiryValue;
}
/**
* Set the custom message identifier.
*
* The custom message identifier is useful to associate a push notification
* to a DB record or an User entry for example. The custom message identifier
* can be retrieved in case of error using the getCustomIdentifier()
* method of an entry retrieved by the getErrors() method.
* This custom identifier, if present, is also used in all status message by
* the ApnsPHP_Push class.
*
* @param $mCustomIdentifier @type mixed The custom message identifier.
*/
public function setCustomIdentifier($mCustomIdentifier)
{
$this->_mCustomIdentifier = $mCustomIdentifier;
}
/**
* Get the custom message identifier.
*
* @return @type mixed The custom message identifier.
*/
public function getCustomIdentifier()
{
return $this->_mCustomIdentifier;
}
}