mirror of
https://github.com/cwinfo/envayasms.git
synced 2025-07-03 21:57:43 +00:00
version 3.0 - real-time AMQP connections; change server API format from XML to JSON, update PHP server library; persistent storage of pending messages
This commit is contained in:
@ -1,24 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* PHP server library for EnvayaSMS
|
||||
* PHP server library for EnvayaSMS 3.0
|
||||
*
|
||||
* For example usage see example/www/index.php
|
||||
* For example usage see example/www/gateway.php
|
||||
*/
|
||||
|
||||
class EnvayaSMS
|
||||
class EnvayaSMS
|
||||
{
|
||||
const ACTION_INCOMING = 'incoming';
|
||||
const ACTION_OUTGOING = 'outgoing';
|
||||
const ACTION_FORWARD_SENT = 'forward_sent';
|
||||
const ACTION_SEND_STATUS = 'send_status';
|
||||
const ACTION_DEVICE_STATUS = 'device_status';
|
||||
const ACTION_TEST = 'test';
|
||||
const ACTION_OUTGOING = 'outgoing';
|
||||
const ACTION_AMQP_STARTED = 'amqp_started';
|
||||
// ACTION_OUTGOING should probably be const ACTION_POLL = 'poll',
|
||||
// but 'outgoing' maintains backwards compatibility between new phone versions with old servers
|
||||
|
||||
const STATUS_QUEUED = 'queued';
|
||||
const STATUS_FAILED = 'failed';
|
||||
const STATUS_SENT = 'sent';
|
||||
const STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
const EVENT_SEND = 'send';
|
||||
const EVENT_CANCEL = 'cancel';
|
||||
const EVENT_CANCEL_ALL = 'cancel_all';
|
||||
const EVENT_LOG = 'log';
|
||||
const EVENT_SETTINGS = 'settings';
|
||||
|
||||
const DEVICE_STATUS_POWER_CONNECTED = "power_connected";
|
||||
const DEVICE_STATUS_POWER_DISCONNECTED = "power_disconnected";
|
||||
const DEVICE_STATUS_BATTERY_LOW = "battery_low";
|
||||
@ -29,8 +38,10 @@ class EnvayaSMS
|
||||
const MESSAGE_TYPE_MMS = 'mms';
|
||||
const MESSAGE_TYPE_CALL = 'call';
|
||||
|
||||
const NETWORK_MOBILE = "MOBILE";
|
||||
const NETWORK_WIFI = "WIFI";
|
||||
// power source constants same as from Android's BatteryManager.EXTRA_PLUGGED
|
||||
const POWER_SOURCE_BATTERY = 0;
|
||||
const POWER_SOURCE_AC = 1;
|
||||
const POWER_SOURCE_USB = 2;
|
||||
|
||||
static function escape($val)
|
||||
{
|
||||
@ -41,60 +52,36 @@ class EnvayaSMS
|
||||
|
||||
static function get_request()
|
||||
{
|
||||
if (!isset(static::$request))
|
||||
if (!isset(self::$request))
|
||||
{
|
||||
$version = @$_POST['version'];
|
||||
|
||||
// If API version changes, could return
|
||||
// different EnvayaSMS_Request instance
|
||||
// to support multiple phone versions
|
||||
|
||||
static::$request = new EnvayaSMS_Request();
|
||||
if (isset($_POST['action']))
|
||||
{
|
||||
self::$request = new EnvayaSMS_ActionRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$request = new EnvayaSMS_Request();
|
||||
}
|
||||
|
||||
}
|
||||
return static::$request;
|
||||
}
|
||||
|
||||
static function get_error_xml($message)
|
||||
{
|
||||
ob_start();
|
||||
echo "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
echo "<response>";
|
||||
echo "<error>";
|
||||
echo EnvayaSMS::escape($message);
|
||||
echo "</error>";
|
||||
echo "</response>";
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
static function get_success_xml()
|
||||
{
|
||||
ob_start();
|
||||
echo "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
echo "<response></response>";
|
||||
return ob_get_clean();
|
||||
}
|
||||
return self::$request;
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Request
|
||||
{
|
||||
private $request_action;
|
||||
|
||||
{
|
||||
public $version;
|
||||
public $phone_number;
|
||||
public $log;
|
||||
|
||||
public $version_name;
|
||||
public $sdk_int;
|
||||
public $manufacturer;
|
||||
public $model;
|
||||
public $network;
|
||||
|
||||
public $model;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->version = $_POST['version'];
|
||||
$this->phone_number = $_POST['phone_number'];
|
||||
$this->log = $_POST['log'];
|
||||
$this->network = @$_POST['network'];
|
||||
$this->version = (int)@$_POST['version'];
|
||||
|
||||
if (preg_match('#/(?P<version_name>[\w\.\-]+) \(Android; SDK (?P<sdk_int>\d+); (?P<manufacturer>[^;]*); (?P<model>[^\)]*)\)#',
|
||||
@$_SERVER['HTTP_USER_AGENT'], $matches))
|
||||
@ -103,9 +90,115 @@ class EnvayaSMS_Request
|
||||
$this->sdk_int = $matches['sdk_int'];
|
||||
$this->manufacturer = $matches['manufacturer'];
|
||||
$this->model = $matches['model'];
|
||||
}
|
||||
}
|
||||
|
||||
function supports_json()
|
||||
{
|
||||
return $this->version >= 28;
|
||||
}
|
||||
|
||||
function supports_update_settings()
|
||||
{
|
||||
return $this->version >= 29;
|
||||
}
|
||||
|
||||
function get_response_type()
|
||||
{
|
||||
if ($this->supports_json())
|
||||
{
|
||||
return 'application/json';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'text/xml';
|
||||
}
|
||||
}
|
||||
|
||||
function render_response($events = null /* optional array of EnvayaSMS_Event objects */)
|
||||
{
|
||||
if ($this->supports_json())
|
||||
{
|
||||
return json_encode(array('events' => $events));
|
||||
}
|
||||
else
|
||||
{
|
||||
ob_start();
|
||||
echo "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
echo "<response>";
|
||||
|
||||
if ($events)
|
||||
{
|
||||
foreach ($events as $event)
|
||||
{
|
||||
echo "<messages>";
|
||||
if ($event instanceof EnvayaSMS_Event_Send)
|
||||
{
|
||||
if ($event->messages)
|
||||
{
|
||||
foreach ($event->messages as $message)
|
||||
{
|
||||
$type = isset($message->type) ? $message->type : EnvayaSMS::MESSAGE_TYPE_SMS;
|
||||
$id = isset($message->id) ? " id=\"".EnvayaSMS::escape($message->id)."\"" : "";
|
||||
$to = isset($message->to) ? " to=\"".EnvayaSMS::escape($message->to)."\"" : "";
|
||||
$priority = isset($message->priority) ? " priority=\"".$message->priority."\"" : "";
|
||||
echo "<$type$id$to$priority>".EnvayaSMS::escape($message->message)."</$type>";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "</messages>";
|
||||
}
|
||||
}
|
||||
echo "</response>";
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
function render_error_response($message)
|
||||
{
|
||||
if ($this->supports_json())
|
||||
{
|
||||
return json_encode(array('error' => array('message' => $message)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ob_start();
|
||||
echo "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
echo "<response>";
|
||||
echo "<error>";
|
||||
echo EnvayaSMS::escape($message);
|
||||
echo "</error>";
|
||||
echo "</response>";
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_ActionRequest extends EnvayaSMS_Request
|
||||
{
|
||||
private $request_action;
|
||||
|
||||
public $settings_version; // integer version of current settings (as provided by server)
|
||||
public $phone_number; // phone number of Android phone
|
||||
public $log; // app log messages since last successful request
|
||||
public $now; // current time (ms since Unix epoch) according to Android clock
|
||||
public $network; // name of network, like WIFI or MOBILE (may vary depending on phone)
|
||||
public $battery; // battery level as percentage
|
||||
public $power; // power source integer, see EnvayaSMS::POWER_SOURCE_*
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->phone_number = $_POST['phone_number'];
|
||||
$this->log = $_POST['log'];
|
||||
$this->network = @$_POST['network'];
|
||||
$this->now = @$_POST['now'];
|
||||
$this->settings_version = @$_POST['settings_version'];
|
||||
$this->battery = @$_POST['battery'];
|
||||
$this->power = @$_POST['power'];
|
||||
}
|
||||
|
||||
function get_action()
|
||||
{
|
||||
if (!$this->request_action)
|
||||
@ -121,7 +214,9 @@ class EnvayaSMS_Request
|
||||
{
|
||||
case EnvayaSMS::ACTION_INCOMING:
|
||||
return new EnvayaSMS_Action_Incoming($this);
|
||||
case EnvayaSMS::ACTION_OUTGOING:
|
||||
case EnvayaSMS::ACTION_FORWARD_SENT:
|
||||
return new EnvayaSMS_Action_ForwardSent($this);
|
||||
case EnvayaSMS::ACTION_OUTGOING:
|
||||
return new EnvayaSMS_Action_Outgoing($this);
|
||||
case EnvayaSMS::ACTION_SEND_STATUS:
|
||||
return new EnvayaSMS_Action_SendStatus($this);
|
||||
@ -129,6 +224,8 @@ class EnvayaSMS_Request
|
||||
return new EnvayaSMS_Action_Test($this);
|
||||
case EnvayaSMS::ACTION_DEVICE_STATUS:
|
||||
return new EnvayaSMS_Action_DeviceStatus($this);
|
||||
case EnvayaSMS::ACTION_AMQP_STARTED:
|
||||
return new EnvayaSMS_Action_AmqpStarted($this);
|
||||
default:
|
||||
return new EnvayaSMS_Action($this);
|
||||
}
|
||||
@ -163,29 +260,8 @@ class EnvayaSMS_Request
|
||||
|
||||
$input .= ",$password";
|
||||
|
||||
//error_log("Signed data: '$input'");
|
||||
|
||||
return base64_encode(sha1($input, true));
|
||||
}
|
||||
|
||||
static function get_messages_xml($messages)
|
||||
{
|
||||
ob_start();
|
||||
echo "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
echo "<response>";
|
||||
echo "<messages>";
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
$type = isset($message->type) ? $message->type : EnvayaSMS::MESSAGE_TYPE_SMS;
|
||||
$id = isset($message->id) ? " id=\"".EnvayaSMS::escape($message->id)."\"" : "";
|
||||
$to = isset($message->to) ? " to=\"".EnvayaSMS::escape($message->to)."\"" : "";
|
||||
$priority = isset($message->priority) ? " priority=\"".$message->priority."\"" : "";
|
||||
echo "<$type$id$to$priority>".EnvayaSMS::escape($message->message)."</$type>";
|
||||
}
|
||||
echo "</messages>";
|
||||
echo "</response>";
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_OutgoingMessage
|
||||
@ -197,6 +273,10 @@ class EnvayaSMS_OutgoingMessage
|
||||
public $type; // EnvayaSMS::MESSAGE_TYPE_* value (default sms)
|
||||
}
|
||||
|
||||
/*
|
||||
* An 'action' is the term for a HTTP request that app sends to the server.
|
||||
*/
|
||||
|
||||
class EnvayaSMS_Action
|
||||
{
|
||||
public $type;
|
||||
@ -233,24 +313,19 @@ class EnvayaSMS_MMS_Part
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_Incoming extends EnvayaSMS_Action
|
||||
abstract class EnvayaSMS_Action_Forward extends EnvayaSMS_Action
|
||||
{
|
||||
public $from; // Sender phone number
|
||||
public $message; // The message body of the SMS, or the content of the text/plain part of the MMS.
|
||||
public $message_type; // EnvayaSMS::MESSAGE_TYPE_MMS or EnvayaSMS::MESSAGE_TYPE_SMS
|
||||
public $mms_parts; // array of EnvayaSMS_MMS_Part instances
|
||||
public $timestamp; // timestamp of incoming message (added in version 12)
|
||||
public $age; // delay in ms between time when message originally received and when forwarded to server (added in version 18)
|
||||
|
||||
function __construct($request)
|
||||
{
|
||||
parent::__construct($request);
|
||||
$this->type = EnvayaSMS::ACTION_INCOMING;
|
||||
$this->from = $_POST['from'];
|
||||
$this->message = @$_POST['message'];
|
||||
$this->message_type = $_POST['message_type'];
|
||||
$this->timestamp = @$_POST['timestamp'];
|
||||
$this->age = @$_POST['age'];
|
||||
|
||||
if ($this->message_type == EnvayaSMS::MESSAGE_TYPE_MMS)
|
||||
{
|
||||
@ -260,26 +335,52 @@ class EnvayaSMS_Action_Incoming extends EnvayaSMS_Action
|
||||
$this->mms_parts[] = new EnvayaSMS_MMS_Part($mms_part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_response_xml($messages)
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_Incoming extends EnvayaSMS_Action_Forward
|
||||
{
|
||||
public $from; // Sender phone number
|
||||
|
||||
function __construct($request)
|
||||
{
|
||||
return $this->request->get_messages_xml($messages);
|
||||
parent::__construct($request);
|
||||
$this->type = EnvayaSMS::ACTION_INCOMING;
|
||||
$this->from = $_POST['from'];
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_ForwardSent extends EnvayaSMS_Action_Forward
|
||||
{
|
||||
public $to; // Recipient phone number
|
||||
|
||||
function __construct($request)
|
||||
{
|
||||
parent::__construct($request);
|
||||
$this->type = EnvayaSMS::ACTION_FORWARD_SENT;
|
||||
$this->to = $_POST['to'];
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_AmqpStarted extends EnvayaSMS_Action
|
||||
{
|
||||
public $consumer_tag;
|
||||
|
||||
function __construct($request)
|
||||
{
|
||||
parent::__construct($request);
|
||||
$this->type = EnvayaSMS::ACTION_AMQP_STARTED;
|
||||
$this->consumer_tag = $_POST['consumer_tag'];
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_Outgoing extends EnvayaSMS_Action
|
||||
{
|
||||
function __construct($request)
|
||||
{
|
||||
parent::__construct($request);
|
||||
$this->type = EnvayaSMS::ACTION_OUTGOING;
|
||||
}
|
||||
|
||||
function get_response_xml($messages)
|
||||
{
|
||||
return $this->request->get_messages_xml($messages);
|
||||
}
|
||||
$this->type = EnvayaSMS::ACTION_OUTGOING;
|
||||
}
|
||||
}
|
||||
|
||||
class EnvayaSMS_Action_Test extends EnvayaSMS_Action
|
||||
@ -318,3 +419,89 @@ class EnvayaSMS_Action_DeviceStatus extends EnvayaSMS_Action
|
||||
$this->status = $_POST['status'];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An 'event' is the term for something the server sends to the app,
|
||||
* either via a response to an 'action', or directly via AMQP.
|
||||
*/
|
||||
|
||||
class EnvayaSMS_Event
|
||||
{
|
||||
public $event;
|
||||
|
||||
/*
|
||||
* Formats this event as the body of an AMQP message.
|
||||
*/
|
||||
function render()
|
||||
{
|
||||
return json_encode($this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Instruct the phone to send one or more outgoing messages (SMS or USSD)
|
||||
*/
|
||||
class EnvayaSMS_Event_Send extends EnvayaSMS_Event
|
||||
{
|
||||
public $messages;
|
||||
|
||||
function __construct($messages /* array of EnvayaSMS_OutgoingMessage objects */)
|
||||
{
|
||||
$this->event = EnvayaSMS::EVENT_SEND;
|
||||
$this->messages = $messages;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update some of the app's settings.
|
||||
*/
|
||||
class EnvayaSMS_Event_Settings extends EnvayaSMS_Event
|
||||
{
|
||||
public $settings;
|
||||
|
||||
function __construct($settings /* associative array of key => value pairs (values can be int, bool, or string) */)
|
||||
{
|
||||
$this->event = EnvayaSMS::EVENT_SETTINGS;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel sending a message that was previously queued in the app via a 'send' event.
|
||||
* Has no effect if the message has already been sent.
|
||||
*/
|
||||
class EnvayaSMS_Event_Cancel extends EnvayaSMS_Event
|
||||
{
|
||||
public $id;
|
||||
|
||||
function __construct($id /* id of previously created EnvayaSMS_OutgoingMessage object (string) */)
|
||||
{
|
||||
$this->event = EnvayaSMS::EVENT_CANCEL;
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancels all outgoing messages that are currently queued in the app. Incoming mesages are not affected.
|
||||
*/
|
||||
class EnvayaSMS_Event_CancelAll extends EnvayaSMS_Event
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
$this->event = EnvayaSMS::EVENT_CANCEL_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a message to the app log.
|
||||
*/
|
||||
class EnvayaSMS_Event_Log extends EnvayaSMS_Event
|
||||
{
|
||||
public $message;
|
||||
|
||||
function __construct($message)
|
||||
{
|
||||
$this->event = EnvayaSMS::EVENT_LOG;
|
||||
$this->message = $message;
|
||||
}
|
||||
}
|
||||
|
@ -10,19 +10,21 @@ PHP web server, by running the following commands:
|
||||
git submodule init
|
||||
php server.php
|
||||
|
||||
example/config.php contains the list of phone numbers and passwords for phones running EnvayaSMS.
|
||||
example/config.php contains the password for a phone running EnvayaSMS. The password
|
||||
This password must match the password in the EnvayaSMS app settings,
|
||||
otherwise example/gateway.php will return an "Invalid password" error.
|
||||
|
||||
On a phone running EnvayaSMS, go to Menu -> Settings and enter:
|
||||
* Server URL: The URL to example/www/index.php.
|
||||
If you're using server.php, this will be http://<your_ip_address>:8002/
|
||||
* Your phone number: One of the phone numbers listed in example/config.php
|
||||
* Password: The corresponding password in example/config.php
|
||||
* Server URL: The URL to example/www/gateway.php.
|
||||
If you're using server.php, this will be http://<your_ip_address>:8002/gateway.php
|
||||
* Your phone number: The phone number of your Android phone
|
||||
* Password: The password in example/config.php
|
||||
|
||||
To send an outgoing SMS, use
|
||||
php example/send_sms.php
|
||||
|
||||
php example/send_sms.php
|
||||
|
||||
example/www/test.html allows you to simulate the HTTP requests made by EnvayaSMS
|
||||
in your browser without actually using the EnvayaSMS app.
|
||||
If you're using server.php, just go to http://<your_ip_address>:8002/test.html
|
||||
|
||||
See EnvayaSMS.php and example/www/index.php
|
||||
See EnvayaSMS.php and example/www/gateway.php
|
||||
|
@ -1,9 +1,33 @@
|
||||
<?php
|
||||
|
||||
$PASSWORDS = array(
|
||||
'16505551212' => 'rosebud',
|
||||
'16505551213' => 's3krit',
|
||||
);
|
||||
$PHONE_NUMBERS = array_keys($PASSWORDS);
|
||||
ini_set('display_errors','0');
|
||||
|
||||
$OUTGOING_DIR_NAME = __DIR__."/outgoing_sms";
|
||||
/*
|
||||
* This password must match the password in the EnvayaSMS app settings,
|
||||
* otherwise example/www/gateway.php will return an "Invalid request signature" error.
|
||||
*/
|
||||
|
||||
$PASSWORD = 'rosebud';
|
||||
|
||||
/*
|
||||
* example/send_sms.php uses the local file system to queue outgoing messages
|
||||
* in this directory.
|
||||
*/
|
||||
|
||||
$OUTGOING_DIR_NAME = __DIR__."/outgoing_sms";
|
||||
|
||||
/*
|
||||
* AMQP allows you to send outgoing messages in real-time (i.e. 'push' instead of polling).
|
||||
* In order to use AMQP, you would need to install an AMQP server such as RabbitMQ, and
|
||||
* also enter the AMQP connection settings in the app. (The settings in the EnvayaSMS app
|
||||
* should use the same vhost and queue name, but may use a different host/port/user/password.)
|
||||
*/
|
||||
|
||||
$AMQP_SETTINGS = array(
|
||||
'host' => 'localhost',
|
||||
'port' => 5672,
|
||||
'user' => 'guest',
|
||||
'password' => 'guest',
|
||||
'vhost' => '/',
|
||||
'queue_name' => "envayasms"
|
||||
);
|
||||
|
1
server/php/example/php-amqplib
Submodule
1
server/php/example/php-amqplib
Submodule
Submodule server/php/example/php-amqplib added at 056e94d28d
@ -1,46 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Command line script to simulate sending an outgoing SMS from the server.
|
||||
* Command line script to send an outgoing SMS from the server.
|
||||
*
|
||||
* The message will be queued on the server until the next time
|
||||
* EnvayaSMS checks for outgoing messages.
|
||||
* This example script queues outgoing messages using the local filesystem.
|
||||
* The messages are sent the next time EnvayaSMS sends an ACTION_OUTGOING request to www/gateway.php.
|
||||
*/
|
||||
|
||||
require_once __DIR__."/config.php";
|
||||
require_once dirname(__DIR__)."/EnvayaSMS.php";
|
||||
|
||||
$arg_len = sizeof($argv);
|
||||
|
||||
if ($arg_len == 4)
|
||||
{
|
||||
$from = $argv[1];
|
||||
$to = $argv[2];
|
||||
$message = $argv[3];
|
||||
}
|
||||
else if ($arg_len == 3)
|
||||
if (sizeof($argv) == 3)
|
||||
{
|
||||
$from = $PHONE_NUMBERS[0];
|
||||
$to = $argv[1];
|
||||
$message = $argv[2];
|
||||
$body = $argv[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log("Usage: php send_sms.php [<from>] <to> \"<message>\"");
|
||||
error_log("Examples: ");
|
||||
error_log(" php send_sms.php 16505551212 16504449876 \"hello world\"");
|
||||
error_log("Usage: php send_sms.php <to> \"<message>\"");
|
||||
error_log("Example: ");
|
||||
error_log(" php send_sms.php 16504449876 \"hello world\"");
|
||||
die;
|
||||
}
|
||||
|
||||
$id = uniqid("");
|
||||
$message = new EnvayaSMS_OutgoingMessage();
|
||||
$message->id = uniqid("");
|
||||
$message->to = $to;
|
||||
$message->message = $body;
|
||||
|
||||
$filename = "$OUTGOING_DIR_NAME/$id.json";
|
||||
|
||||
file_put_contents($filename, json_encode(array(
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'message' => $message,
|
||||
'id' => $id
|
||||
)));
|
||||
|
||||
echo "Message $id added to outgoing queue\n";
|
||||
file_put_contents("$OUTGOING_DIR_NAME/{$message->id}.json", json_encode($message));
|
||||
|
||||
echo "Message {$message->id} added to filesystem queue\n";
|
||||
|
45
server/php/example/send_sms_amqp.php
Normal file
45
server/php/example/send_sms_amqp.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Command line script to send an outgoing SMS from the server.
|
||||
*
|
||||
* Requires an AMQP server to be configured in config.php, and
|
||||
* pushes SMS to the phone immediately using the real-time connection.
|
||||
*/
|
||||
|
||||
require_once __DIR__."/config.php";
|
||||
require_once dirname(__DIR__)."/EnvayaSMS.php";
|
||||
require_once __DIR__."/php-amqplib/amqp.inc";
|
||||
|
||||
if (sizeof($argv) == 3)
|
||||
{
|
||||
$to = $argv[1];
|
||||
$body = $argv[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log("Usage: php send_sms_amqp.php <to> \"<message>\"");
|
||||
die;
|
||||
}
|
||||
|
||||
$message = new EnvayaSMS_OutgoingMessage();
|
||||
$message->id = uniqid("");
|
||||
$message->to = $to;
|
||||
$message->message = $body;
|
||||
|
||||
$conn = new AMQPConnection($AMQP_SETTINGS['host'], $AMQP_SETTINGS['port'],
|
||||
$AMQP_SETTINGS['user'], $AMQP_SETTINGS['password'], $AMQP_SETTINGS['vhost']);
|
||||
|
||||
$ch = $conn->channel();
|
||||
$ch->queue_declare($AMQP_SETTINGS['queue_name'], false, true, false, false);
|
||||
|
||||
$event = new EnvayaSMS_Event_Send(array($message));
|
||||
|
||||
$msg = new AMQPMessage($event->render(), array('content_type' => 'application/json', 'delivery-mode' => 2));
|
||||
|
||||
$ch->basic_publish($msg, '', $AMQP_SETTINGS['queue_name']);
|
||||
|
||||
$ch->close();
|
||||
$conn->close();
|
||||
|
||||
echo "Message {$message->id} added to AMQP queue\n";
|
87
server/php/example/www/index.php → server/php/example/www/gateway.php
Executable file → Normal file
87
server/php/example/www/index.php → server/php/example/www/gateway.php
Executable file → Normal file
@ -1,44 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This example script implements the EnvayaSMS API.
|
||||
*
|
||||
* It sends an auto-reply to each incoming message, and sends outgoing SMS
|
||||
* that were previously queued by example/send_sms.php .
|
||||
*
|
||||
* To use this file, set the URL to this file as as the the Server URL in the EnvayaSMS app.
|
||||
* The password in the EnvayaSMS app settings must be the same as $PASSWORD in config.php.
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__)."/config.php";
|
||||
require_once dirname(dirname(__DIR__))."/EnvayaSMS.php";
|
||||
|
||||
ini_set('display_errors','0');
|
||||
|
||||
// this example implementation uses the filesystem to store outgoing SMS messages,
|
||||
// but presumably a production implementation would use another storage method
|
||||
|
||||
$request = EnvayaSMS::get_request();
|
||||
|
||||
$phone_number = $request->phone_number;
|
||||
header("Content-Type: {$request->get_response_type()}");
|
||||
|
||||
$password = @$PASSWORDS[$phone_number];
|
||||
|
||||
header("Content-Type: text/xml");
|
||||
|
||||
if (!isset($password) || !$request->is_validated($password))
|
||||
if (!$request->is_validated($PASSWORD))
|
||||
{
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
error_log("Invalid request signature");
|
||||
echo EnvayaSMS::get_error_xml("Invalid request signature");
|
||||
error_log("Invalid password");
|
||||
echo $request->render_error_response("Invalid password");
|
||||
return;
|
||||
}
|
||||
|
||||
// append to EnvayaSMS app log
|
||||
$app_log = $request->log;
|
||||
if ($app_log)
|
||||
{
|
||||
$log_file = dirname(__DIR__)."/log/sms_".preg_replace('#[^\w]#', '', $request->phone_number).".log";
|
||||
$f = fopen($log_file, "a");
|
||||
fwrite($f, $app_log);
|
||||
fclose($f);
|
||||
}
|
||||
|
||||
$action = $request->get_action();
|
||||
|
||||
switch ($action->type)
|
||||
{
|
||||
case EnvayaSMS::ACTION_INCOMING:
|
||||
|
||||
// Send an auto-reply for each incoming message.
|
||||
|
||||
$type = strtoupper($action->message_type);
|
||||
|
||||
error_log("Received $type from {$action->from}");
|
||||
@ -62,25 +56,29 @@ switch ($action->type)
|
||||
$reply->message = "You said: {$action->message}";
|
||||
|
||||
error_log("Sending reply: {$reply->message}");
|
||||
|
||||
echo $action->get_response_xml(array($reply));
|
||||
|
||||
echo $request->render_response(array(
|
||||
new EnvayaSMS_Event_Send(array($reply))
|
||||
));
|
||||
return;
|
||||
|
||||
case EnvayaSMS::ACTION_OUTGOING:
|
||||
$messages = array();
|
||||
|
||||
// In this example implementation, outgoing SMS messages are queued
|
||||
// on the local file system by send_sms.php.
|
||||
|
||||
$dir = opendir($OUTGOING_DIR_NAME);
|
||||
while ($file = readdir($dir))
|
||||
{
|
||||
if (preg_match('#\.json$#', $file))
|
||||
{
|
||||
$data = json_decode(file_get_contents("$OUTGOING_DIR_NAME/$file"), true);
|
||||
if ($data && @$data['from'] == $phone_number)
|
||||
if ($data)
|
||||
{
|
||||
$sms = new EnvayaSMS_OutgoingMessage();
|
||||
$sms->id = $data['id'];
|
||||
$sms->to = $data['to'];
|
||||
$sms->from = $data['from'];
|
||||
$sms->message = $data['message'];
|
||||
$messages[] = $sms;
|
||||
}
|
||||
@ -88,33 +86,40 @@ switch ($action->type)
|
||||
}
|
||||
closedir($dir);
|
||||
|
||||
echo $action->get_response_xml($messages);
|
||||
$events = array();
|
||||
|
||||
if ($messages)
|
||||
{
|
||||
$events[] = new EnvayaSMS_Event_Send($messages);
|
||||
}
|
||||
|
||||
echo $request->render_response($events);
|
||||
|
||||
return;
|
||||
|
||||
case EnvayaSMS::ACTION_SEND_STATUS:
|
||||
|
||||
$id = $action->id;
|
||||
|
||||
error_log("message $id status: {$action->status}");
|
||||
|
||||
// delete file with matching id
|
||||
if (preg_match('#^\w+$#', $id) && unlink("$OUTGOING_DIR_NAME/$id.json"))
|
||||
if (preg_match('#^\w+$#', $id))
|
||||
{
|
||||
echo EnvayaSMS::get_success_xml();
|
||||
}
|
||||
else
|
||||
{
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
echo EnvayaSMS::get_error_xml("Invalid id");
|
||||
}
|
||||
unlink("$OUTGOING_DIR_NAME/$id.json");
|
||||
}
|
||||
echo $request->render_response();
|
||||
|
||||
return;
|
||||
case EnvayaSMS::ACTION_DEVICE_STATUS:
|
||||
error_log("device_status = {$action->status}");
|
||||
echo EnvayaSMS::get_success_xml();
|
||||
return;
|
||||
echo $request->render_response();
|
||||
return;
|
||||
case EnvayaSMS::ACTION_TEST:
|
||||
echo EnvayaSMS::get_success_xml();
|
||||
return;
|
||||
echo $request->render_response();
|
||||
return;
|
||||
default:
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
echo EnvayaSMS::get_error_xml("Invalid action");
|
||||
echo $request->render_error_response("The server does not support the requested action.");
|
||||
return;
|
||||
}
|
87
server/php/example/www/gateway_amqp.php
Normal file
87
server/php/example/www/gateway_amqp.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* An example implementation of the EnvayaSMS server API that uses AMQP
|
||||
* to send outgoing messages in real-time, intended to be used together with
|
||||
* example/send_sms_amqp.php.
|
||||
*
|
||||
* To use this file, set the URL to this file as as the the Server URL in the EnvayaSMS app.
|
||||
* The password in the EnvayaSMS app settings must be the same as $PASSWORD in config.php.
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__)."/config.php";
|
||||
require_once dirname(dirname(__DIR__))."/EnvayaSMS.php";
|
||||
|
||||
$request = EnvayaSMS::get_request();
|
||||
|
||||
header("Content-Type: {$request->get_response_type()}");
|
||||
|
||||
if (!$request->is_validated($PASSWORD))
|
||||
{
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
error_log("Invalid password");
|
||||
echo $request->render_error_response("Invalid password");
|
||||
return;
|
||||
}
|
||||
|
||||
$action = $request->get_action();
|
||||
|
||||
switch ($action->type)
|
||||
{
|
||||
case EnvayaSMS::ACTION_INCOMING:
|
||||
|
||||
// Doesn't do anything with incoming messages
|
||||
|
||||
error_log("Received {$action->message_type} from {$action->from}: {$action->message}");
|
||||
echo $request->render_response();
|
||||
return;
|
||||
|
||||
case EnvayaSMS::ACTION_OUTGOING:
|
||||
|
||||
// Doesn't need to do anything when polling for outgoing messages
|
||||
// since they should be sent via the AMQP connection.
|
||||
|
||||
// Optionally, you could use AMQP basic_get to retrieve any messages
|
||||
// from the AMQP queue so that it works in both polling and push modes.
|
||||
|
||||
error_log("No messages here, use AMQP instead");
|
||||
echo $request->render_response(array(
|
||||
new EnvayaSMS_Event_Log("No messages via polling, use AMQP instead")
|
||||
));
|
||||
return;
|
||||
|
||||
case EnvayaSMS::ACTION_AMQP_STARTED:
|
||||
|
||||
// The main point of this action is to allow the server to kick off old
|
||||
// AMQP connections (that weren't closed properly) before their heartbeat timeout
|
||||
// expires. This makes it possible to use long heartbeat timeouts to maximize
|
||||
// the phone's battery life.
|
||||
|
||||
// With RabbitMQ, this can be done using the management API:
|
||||
|
||||
// GET /queues/VHOST/QUEUE_NAME
|
||||
// to get the connection name for each consumer other than the current one
|
||||
|
||||
// DELETE /connections/CONNECTION_NAME
|
||||
// to close the connection for each consumer other than the current one
|
||||
|
||||
error_log("AMQP connection started with consumer tag {$action->consumer_tag}");
|
||||
echo $request->render_response();
|
||||
return;
|
||||
|
||||
case EnvayaSMS::ACTION_SEND_STATUS:
|
||||
error_log("message {$action->id} status: {$action->status}");
|
||||
echo $request->render_response();
|
||||
return;
|
||||
case EnvayaSMS::ACTION_DEVICE_STATUS:
|
||||
error_log("device_status = {$action->status}");
|
||||
echo $request->render_response();
|
||||
return;
|
||||
case EnvayaSMS::ACTION_TEST:
|
||||
echo $request->render_response();
|
||||
return;
|
||||
default:
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
echo $request->render_error_response("The server does not support the requested action.");
|
||||
return;
|
||||
}
|
@ -31,13 +31,26 @@ body
|
||||
<tr><th>Phone Number</th><td><input id='phone_number' type='text' /></td></tr>
|
||||
<tr><th>Password</th><td><input id='password' type='password' /></td></tr>
|
||||
<tr><th>Log Messages</th><td><textarea id='log' style='width:250px'></textarea></td></tr>
|
||||
<tr><th>Send Limit</th><td><input id='send_limit' value='100' type='text' /></td></tr>
|
||||
<tr><th>Settings Version</th><td><input id='settings_version' value='1' type='text' /></td></tr>
|
||||
<tr><th>Battery</th><td><input id='battery' value='100' type='text' /></td></tr>
|
||||
<tr><th>Power Source</th><td><select id='power'>
|
||||
<option value='0'>0 (battery)</option>
|
||||
<option value='1'>1 (USB)</option>
|
||||
<option value='2'>2 (AC)</option>
|
||||
</select></td></tr>
|
||||
<tr><th>Network Type</th><td><input id='network' value='WIFI' type='text' /></td></tr>
|
||||
<tr><th>Current Timestamp</th><td><input id='now' type='text' /></td></tr>
|
||||
|
||||
<tr><th>Action</th><td><select id='action' onchange='actionChanged()' onkeypress='actionChanged()'>
|
||||
<option value='incoming'>incoming</option>
|
||||
<option value='outgoing'>outgoing</option>
|
||||
<option value='send_status'>send_status</option>
|
||||
<option value='device_status'>device_status</option>
|
||||
<option value='test'>test</option>
|
||||
<option value='amqp_started'>amqp_started</option>
|
||||
</select></td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<div id='action_incoming'>
|
||||
@ -47,6 +60,7 @@ body
|
||||
<tr><th>Message Type</th><td><select id='message_type'>
|
||||
<option value='sms'>sms</option>
|
||||
<option value='mms'>mms</option>
|
||||
<option value='call'>call</option>
|
||||
</select></td></tr>
|
||||
<tr><th>Message</th><td><textarea id='message' style='width:250px'></textarea></td></tr>
|
||||
<tr><th>Timestamp</th><td><input id='timestamp' type='text' /></td></tr>
|
||||
@ -64,6 +78,7 @@ body
|
||||
<option value='sent'>sent</option>
|
||||
<option value='failed'>failed</option>
|
||||
<option value='queued'>queued</option>
|
||||
<option value='cancelled'>cancelled</option>
|
||||
</select></td></tr>
|
||||
<tr><th>Error Message</th><td><input id='error' type='text' size='50' /></td></tr>
|
||||
</table>
|
||||
@ -80,10 +95,16 @@ body
|
||||
<option value='power_disconnected'>power_disconnected</option>
|
||||
<option value='battery_low'>battery_low</option>
|
||||
<option value='battery_okay'>battery_okay</option>
|
||||
<option value='send_limit_exceeded'>send_limit_exceeded</option>
|
||||
</select></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='action_amqp_started' style='display:none'>
|
||||
<h4>Parameters for action=amqp_started:</h4>
|
||||
<table class='smsTable'>
|
||||
<tr><th>Consumer Tag</th><td><input id='consumer_tag' type='text' /></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
@ -110,11 +131,17 @@ function performAction() {
|
||||
var action = $('action').value;
|
||||
|
||||
var params = {
|
||||
version: '13',
|
||||
version: '29',
|
||||
phone_number: $('phone_number').value,
|
||||
action: action,
|
||||
log: $('log').value
|
||||
};
|
||||
log: $('log').value,
|
||||
send_limit: $('send_limit').value,
|
||||
settings_version: $('settings_version').value,
|
||||
battery: $('battery').value,
|
||||
power: $('power').value,
|
||||
network: $('network').value,
|
||||
now: $('now').value
|
||||
};
|
||||
|
||||
if (action == 'incoming')
|
||||
{
|
||||
@ -133,6 +160,10 @@ function performAction() {
|
||||
{
|
||||
params.status = $('device_status').value;
|
||||
}
|
||||
else if (action == 'amqp_started')
|
||||
{
|
||||
params.status = $('consumer_tag').value;
|
||||
}
|
||||
|
||||
var xhr = (window.ActiveXObject && !window.XMLHttpRequest) ? new ActiveXObject("Msxml2.XMLHTTP") : new XMLHttpRequest();
|
||||
|
||||
@ -189,8 +220,9 @@ function performAction() {
|
||||
xhr.send(paramStr);
|
||||
}
|
||||
|
||||
$('server_url').value = location.href.replace("test.html","");
|
||||
$('server_url').value = location.href.replace("test.html","gateway.php");
|
||||
$('timestamp').value = new Date().getTime();
|
||||
$('now').value = new Date().getTime();
|
||||
|
||||
</script>
|
||||
|
||||
|
Reference in New Issue
Block a user