upgrade
This commit is contained in:
643
plugin/kannelsms/vendor/kannelsms_api.php
vendored
Normal file
643
plugin/kannelsms/vendor/kannelsms_api.php
vendored
Normal file
@@ -0,0 +1,643 @@
|
||||
<?php
|
||||
/**
|
||||
* Kannel PHP API
|
||||
*
|
||||
* @package Kannel
|
||||
* @copyright Mediaburst Ltd 2012
|
||||
* @license ISC
|
||||
* @link http://www.kannelsms.com
|
||||
* @version 1.3.0
|
||||
*/
|
||||
|
||||
if ( !class_exists('KannelException') ) {
|
||||
require_once('exception.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Kannel API Class
|
||||
*
|
||||
* @package Kannel
|
||||
* @since 1.0
|
||||
*/
|
||||
class Kannel {
|
||||
|
||||
/*
|
||||
* Version of this class
|
||||
*/
|
||||
const VERSION = '1.3.1';
|
||||
|
||||
/**
|
||||
* All Kannel API calls start with BASE_URL
|
||||
* @author Martin Steel
|
||||
*/
|
||||
const API_BASE_URL = 'api.kannelsms.com/xml/';
|
||||
|
||||
/**
|
||||
* string to append to API_BASE_URL to check authentication
|
||||
* @author Martin Steel
|
||||
*/
|
||||
const API_AUTH_METHOD = 'authenticate';
|
||||
|
||||
/**
|
||||
* string to append to API_BASE_URL for sending SMS
|
||||
* @author Martin Steel
|
||||
*/
|
||||
const API_SMS_METHOD = 'sms';
|
||||
|
||||
/**
|
||||
* string to append to API_BASE_URL for checking message credit
|
||||
* @author Martin Steel
|
||||
*/
|
||||
const API_CREDIT_METHOD = 'credit';
|
||||
|
||||
/**
|
||||
* string to append to API_BASE_URL for checking account balance
|
||||
* @author Martin Steel
|
||||
*/
|
||||
const API_BALANCE_METHOD = 'balance';
|
||||
|
||||
/**
|
||||
* Kannel API Key
|
||||
*
|
||||
* @var string
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $key;
|
||||
|
||||
/**
|
||||
* Use SSL when making HTTP requests
|
||||
*
|
||||
* If this is not set, SSL will be used where PHP supports it
|
||||
*
|
||||
* @var bool
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $ssl;
|
||||
|
||||
/**
|
||||
* Proxy server hostname (Optional)
|
||||
*
|
||||
* @var string
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $proxy_host;
|
||||
|
||||
/**
|
||||
* Proxy server port (Optional)
|
||||
*
|
||||
* @var integer
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $proxy_port;
|
||||
|
||||
/**
|
||||
* From address used on text messages
|
||||
*
|
||||
* @var string (11 characters or 12 numbers)
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $from;
|
||||
|
||||
/**
|
||||
* Allow long SMS messages (Cost up to 3 credits)
|
||||
*
|
||||
* @var bool
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $long;
|
||||
|
||||
/**
|
||||
* Truncate message text if it is too long
|
||||
*
|
||||
* @var bool
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $truncate;
|
||||
|
||||
/**
|
||||
* Enables various logging of messages when true.
|
||||
*
|
||||
* @var bool
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $log;
|
||||
|
||||
/**
|
||||
* What Kannel should do if you send an invalid character
|
||||
*
|
||||
* Possible values:
|
||||
* 'error' - Return an error (Messasge is not sent)
|
||||
* 'remove' - Remove the invalid character(s)
|
||||
* 'replace' - Replace invalid characters where possible, remove others
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public $invalid_char_action;
|
||||
|
||||
/**
|
||||
* Create a new instance of the Kannel wrapper
|
||||
*
|
||||
* @param string key Your Kannel API Key
|
||||
* @param array options Optional parameters for sending SMS
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public function __construct($key, array $options = array()) {
|
||||
if (empty($key)) {
|
||||
throw new KannelException("Key can't be blank");
|
||||
} else {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
$this->ssl = (array_key_exists('ssl', $options)) ? $options['ssl'] : null;
|
||||
$this->proxy_host = (array_key_exists('proxy_host', $options)) ? $options['proxy_host'] : null;
|
||||
$this->proxy_port = (array_key_exists('proxy_port', $options)) ? $options['proxy_port'] : null;
|
||||
$this->from = (array_key_exists('from', $options)) ? $options['from'] : null;
|
||||
$this->long = (array_key_exists('long', $options)) ? $options['long'] : null;
|
||||
$this->truncate = (array_key_exists('truncate', $options)) ? $options['truncate'] : null;
|
||||
$this->invalid_char_action = (array_key_exists('invalid_char_action', $options)) ? $options['invalid_char_action'] : null;
|
||||
$this->log = (array_key_exists('log', $options)) ? $options['log'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send some text messages
|
||||
*
|
||||
*
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public function send(array $sms) {
|
||||
if (!is_array($sms)) {
|
||||
throw new KannelException("sms parameter must be an array");
|
||||
}
|
||||
$single_message = $this->is_assoc($sms);
|
||||
|
||||
if ($single_message) {
|
||||
$sms = array($sms);
|
||||
}
|
||||
|
||||
$req_doc = new \DOMDocument('1.0', 'UTF-8');
|
||||
$root = $req_doc->createElement('Message');
|
||||
$req_doc->appendChild($root);
|
||||
|
||||
$user_node = $req_doc->createElement('Key');
|
||||
$user_node->appendChild($req_doc->createTextNode($this->key));
|
||||
$root->appendChild($user_node);
|
||||
|
||||
for ($i = 0; $i < count($sms); $i++) {
|
||||
$single = $sms[$i];
|
||||
|
||||
$sms_node = $req_doc->createElement('SMS');
|
||||
|
||||
// Phone number
|
||||
$sms_node->appendChild($req_doc->createElement('To', $single['to']));
|
||||
|
||||
// Message text
|
||||
$content_node = $req_doc->createElement('Content');
|
||||
$content_node->appendChild($req_doc->createTextNode($single['message']));
|
||||
$sms_node->appendChild($content_node);
|
||||
|
||||
// From
|
||||
if (array_key_exists('from', $single) || isset($this->from)) {
|
||||
$from_node = $req_doc->createElement('From');
|
||||
$from_node->appendChild($req_doc->createTextNode(array_key_exists('from', $single) ? $single['from'] : $this->from));
|
||||
$sms_node->appendChild($from_node);
|
||||
}
|
||||
|
||||
// Client ID
|
||||
if (array_key_exists('client_id', $single)) {
|
||||
$client_id_node = $req_doc->createElement('ClientID');
|
||||
$client_id_node->appendChild($req_doc->createTextNode($single['client_id']));
|
||||
$sms_node->appendChild($client_id_node);
|
||||
}
|
||||
|
||||
// Long
|
||||
if (array_key_exists('long', $single) || isset($this->long)) {
|
||||
$long = array_key_exists('long', $single) ? $single['long'] : $this->long;
|
||||
$long_node = $req_doc->createElement('Long');
|
||||
$long_node->appendChild($req_doc->createTextNode($long ? 1 : 0));
|
||||
$sms_node->appendChild($long_node);
|
||||
}
|
||||
|
||||
// Truncate
|
||||
if (array_key_exists('truncate', $single) || isset($this->truncate)) {
|
||||
$truncate = array_key_exists('truncate', $single) ? $single['truncate'] : $this->truncate;
|
||||
$trunc_node = $req_doc->createElement('Truncate');
|
||||
$trunc_node->appendChild($req_doc->createTextNode($truncate ? 1 : 0));
|
||||
$sms_node->appendChild($trunc_node);
|
||||
}
|
||||
|
||||
// Invalid Char Action
|
||||
if (array_key_exists('invalid_char_action', $single) || isset($this->invalid_char_action)) {
|
||||
$action = array_key_exists('invalid_char_action', $single) ? $single['invalid_char_action'] : $this->invalid_char_action;
|
||||
switch (strtolower($action)) {
|
||||
case 'error':
|
||||
$sms_node->appendChild($req_doc->createElement('InvalidCharAction', 1));
|
||||
break;
|
||||
case 'remove':
|
||||
$sms_node->appendChild($req_doc->createElement('InvalidCharAction', 2));
|
||||
break;
|
||||
case 'replace':
|
||||
$sms_node->appendChild($req_doc->createElement('InvalidCharAction', 3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper ID
|
||||
$sms_node->appendChild($req_doc->createElement('WrapperID', $i));
|
||||
|
||||
$root->appendChild($sms_node);
|
||||
}
|
||||
|
||||
$req_xml = $req_doc->saveXML();
|
||||
|
||||
$resp_xml = $this->postToKannel(self::API_SMS_METHOD, $req_xml);
|
||||
$resp_doc = new \DOMDocument();
|
||||
$resp_doc->loadXML($resp_xml);
|
||||
|
||||
$response = array();
|
||||
$err_no = null;
|
||||
$err_desc = null;
|
||||
|
||||
foreach($resp_doc->documentElement->childNodes AS $doc_child) {
|
||||
switch(strtolower($doc_child->nodeName)) {
|
||||
case 'sms_resp':
|
||||
$resp = array();
|
||||
$wrapper_id = null;
|
||||
foreach($doc_child->childNodes AS $resp_node) {
|
||||
switch(strtolower($resp_node->nodeName)) {
|
||||
case 'messageid':
|
||||
$resp['id'] = $resp_node->nodeValue;
|
||||
break;
|
||||
case 'errno':
|
||||
$resp['error_code'] = $resp_node->nodeValue;
|
||||
break;
|
||||
case 'errdesc':
|
||||
$resp['error_message'] = $resp_node->nodeValue;
|
||||
break;
|
||||
case 'wrapperid':
|
||||
$wrapper_id = $resp_node->nodeValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( array_key_exists('error_code', $resp ) )
|
||||
{
|
||||
$resp['success'] = 0;
|
||||
} else {
|
||||
$resp['success'] = 1;
|
||||
}
|
||||
$resp['sms'] = $sms[$wrapper_id];
|
||||
array_push($response, $resp);
|
||||
break;
|
||||
case 'errno':
|
||||
$err_no = $doc_child->nodeValue;
|
||||
break;
|
||||
case 'errdesc':
|
||||
$err_desc = $doc_child->nodeValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($err_no)) {
|
||||
throw new KannelException($err_desc, $err_no);
|
||||
}
|
||||
|
||||
if ($single_message) {
|
||||
return $response[0];
|
||||
} else {
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many SMS credits you have available
|
||||
*
|
||||
* @return integer SMS credits remaining
|
||||
* @deprecated Use checkBalance() instead
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public function checkCredit() {
|
||||
// Create XML doc for request
|
||||
$req_doc = new \DOMDocument('1.0', 'UTF-8');
|
||||
$root = $req_doc->createElement('Credit');
|
||||
$req_doc->appendChild($root);
|
||||
$root->appendChild($req_doc->createElement('Key', $this->key));
|
||||
$req_xml = $req_doc->saveXML();
|
||||
|
||||
// POST XML to Kannel
|
||||
$resp_xml = $this->postToKannel(self::API_CREDIT_METHOD, $req_xml);
|
||||
|
||||
// Create XML doc for response
|
||||
$resp_doc = new \DOMDocument();
|
||||
$resp_doc->loadXML($resp_xml);
|
||||
|
||||
// Parse the response to find credit value
|
||||
$credit;
|
||||
$err_no = null;
|
||||
$err_desc = null;
|
||||
|
||||
foreach ($resp_doc->documentElement->childNodes AS $doc_child) {
|
||||
switch ($doc_child->nodeName) {
|
||||
case "Credit":
|
||||
$credit = $doc_child->nodeValue;
|
||||
break;
|
||||
case "ErrNo":
|
||||
$err_no = $doc_child->nodeValue;
|
||||
break;
|
||||
case "ErrDesc":
|
||||
$err_desc = $doc_child->nodeValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($err_no)) {
|
||||
throw new KannelException($err_desc, $err_no);
|
||||
}
|
||||
return $credit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check your account balance
|
||||
*
|
||||
* @return array Array of account balance:
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public function checkBalance() {
|
||||
// Create XML doc for request
|
||||
$req_doc = new \DOMDocument('1.0', 'UTF-8');
|
||||
$root = $req_doc->createElement('Balance');
|
||||
$req_doc->appendChild($root);
|
||||
$root->appendChild($req_doc->createElement('Key', $this->key));
|
||||
$req_xml = $req_doc->saveXML();
|
||||
|
||||
// POST XML to Kannel
|
||||
$resp_xml = $this->postToKannel(self::API_BALANCE_METHOD, $req_xml);
|
||||
|
||||
// Create XML doc for response
|
||||
$resp_doc = new \DOMDocument();
|
||||
$resp_doc->loadXML($resp_xml);
|
||||
|
||||
// Parse the response to find balance value
|
||||
$balance = null;
|
||||
$err_no = null;
|
||||
$err_desc = null;
|
||||
|
||||
foreach ($resp_doc->documentElement->childNodes as $doc_child) {
|
||||
switch ($doc_child->nodeName) {
|
||||
case "Balance":
|
||||
$balance = number_format(floatval($doc_child->nodeValue), 2);
|
||||
break;
|
||||
case "Currency":
|
||||
foreach ($doc_child->childNodes as $resp_node) {
|
||||
switch ($resp_node->tagName) {
|
||||
case "Symbol":
|
||||
$symbol = $resp_node->nodeValue;
|
||||
break;
|
||||
case "Code":
|
||||
$code = $resp_node->nodeValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "ErrNo":
|
||||
$err_no = $doc_child->nodeValue;
|
||||
break;
|
||||
case "ErrDesc":
|
||||
$err_desc = $doc_child->nodeValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($err_no)) {
|
||||
throw new KannelException($err_desc, $err_no);
|
||||
}
|
||||
|
||||
return array( 'symbol' => $symbol, 'balance' => $balance, 'code' => $code );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the API Key is valid
|
||||
*
|
||||
* @return bool True indicates a valid key
|
||||
* @author Martin Steel
|
||||
*/
|
||||
public function checkKey() {
|
||||
// Create XML doc for request
|
||||
$req_doc = new \DOMDocument('1.0', 'UTF-8');
|
||||
$root = $req_doc->createElement('Authenticate');
|
||||
$req_doc->appendChild($root);
|
||||
$root->appendChild($req_doc->createElement('Key', $this->key));
|
||||
$req_xml = $req_doc->saveXML();
|
||||
|
||||
// POST XML to Kannel
|
||||
$resp_xml = $this->postToKannel(self::API_AUTH_METHOD, $req_xml);
|
||||
|
||||
// Create XML doc for response
|
||||
$resp_doc = new \DOMDocument();
|
||||
$resp_doc->loadXML($resp_xml);
|
||||
|
||||
// Parse the response to see if authenticated
|
||||
$cust_id;
|
||||
$err_no = null;
|
||||
$err_desc = null;
|
||||
|
||||
foreach ($resp_doc->documentElement->childNodes AS $doc_child) {
|
||||
switch ($doc_child->nodeName) {
|
||||
case "CustID":
|
||||
$cust_id = $doc_child->nodeValue;
|
||||
break;
|
||||
case "ErrNo":
|
||||
$err_no = $doc_child->nodeValue;
|
||||
break;
|
||||
case "ErrDesc":
|
||||
$err_desc = $doc_child->nodeValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($err_no)) {
|
||||
throw new KannelException($err_desc, $err_no);
|
||||
}
|
||||
return isset($cust_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP POST to Kannel
|
||||
*
|
||||
* @param string method Kannel method to call (sms/credit)
|
||||
* @param string data Content of HTTP POST
|
||||
*
|
||||
* @return string Response from Kannel
|
||||
* @author Martin Steel
|
||||
*/
|
||||
protected function postToKannel($method, $data) {
|
||||
if ($this->log) {
|
||||
$this->logXML("API $method Request XML", $data);
|
||||
}
|
||||
|
||||
if( isset( $this->ssl ) ) {
|
||||
$ssl = $this->ssl;
|
||||
} else {
|
||||
$ssl = $this->sslSupport();
|
||||
}
|
||||
|
||||
$url = $ssl ? 'https://' : 'http://';
|
||||
$url .= self::API_BASE_URL . $method;
|
||||
|
||||
$response = $this->xmlPost($url, $data);
|
||||
|
||||
if ($this->log) {
|
||||
$this->logXML("API $method Response XML", $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP POST
|
||||
*
|
||||
* cURL will be used if available, otherwise tries the PHP stream functions
|
||||
*
|
||||
* @param string url URL to send to
|
||||
* @param string data Data to POST
|
||||
* @return string Response returned by server
|
||||
* @author Martin Steel
|
||||
*/
|
||||
protected function xmlPost($url, $data) {
|
||||
if(extension_loaded('curl')) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Kannel PHP Wrapper/1.0' . self::VERSION);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
if (isset($this->proxy_host) && isset($this->proxy_port)) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $this->proxy_host);
|
||||
curl_setopt($ch, CURLOPT_PROXYPORT, $this->proxy_port);
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
|
||||
if ($response === false || $info['http_code'] != 200) {
|
||||
throw new \Exception('HTTP Error calling Kannel API - HTTP Status: ' . $info['http_code'] . ' - cURL Erorr: ' . curl_error($ch));
|
||||
} elseif (curl_errno($ch) > 0) {
|
||||
throw new \Exception('HTTP Error calling Kannel API - cURL Error: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return $response;
|
||||
} elseif (function_exists('stream_get_contents')) {
|
||||
// Enable error Track Errors
|
||||
$track = ini_get('track_errors');
|
||||
ini_set('track_errors',true);
|
||||
|
||||
$params = array('http' => array(
|
||||
'method' => 'POST',
|
||||
'header' => "Content-Type: text/xml\r\nUser-Agent: mediaburst PHP Wrapper/" . self::VERSION . "\r\n",
|
||||
'content' => $data
|
||||
));
|
||||
|
||||
if (isset($this->proxy_host) && isset($this->proxy_port)) {
|
||||
$params['http']['proxy'] = 'tcp://'.$this->proxy_host . ':' . $this->proxy_port;
|
||||
$params['http']['request_fulluri'] = True;
|
||||
}
|
||||
|
||||
$ctx = stream_context_create($params);
|
||||
$fp = @fopen($url, 'rb', false, $ctx);
|
||||
if (!$fp) {
|
||||
ini_set('track_errors',$track);
|
||||
throw new \Exception("HTTP Error calling Kannel API - fopen Error: $php_errormsg");
|
||||
}
|
||||
$response = @stream_get_contents($fp);
|
||||
if ($response === false) {
|
||||
ini_set('track_errors',$track);
|
||||
throw new \Exception("HTTP Error calling Kannel API - stream Error: $php_errormsg");
|
||||
}
|
||||
ini_set('track_errors',$track);
|
||||
return $response;
|
||||
} else {
|
||||
throw new \Exception("Kannel requires PHP5 with cURL or HTTP stream support");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the server/HTTP wrapper support SSL
|
||||
*
|
||||
* This is a best guess effort, some servers have weird setups where even
|
||||
* though cURL is compiled with SSL support is still fails to make
|
||||
* any requests.
|
||||
*
|
||||
* @return bool True if SSL is supported
|
||||
* @author Martin Steel
|
||||
*/
|
||||
protected function sslSupport() {
|
||||
$ssl = false;
|
||||
// See if PHP is compiled with cURL
|
||||
if (extension_loaded('curl')) {
|
||||
$version = curl_version();
|
||||
$ssl = ($version['features'] & CURL_VERSION_SSL) ? true : false;
|
||||
} elseif (extension_loaded('openssl')) {
|
||||
$ssl = true;
|
||||
}
|
||||
return $ssl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log some XML, tidily if possible, in the PHP error log
|
||||
*
|
||||
* @param string log_msg The log message to prepend to the XML
|
||||
* @param string xml An XML formatted string
|
||||
*
|
||||
* @return void
|
||||
* @author Martin Steel
|
||||
*/
|
||||
protected function logXML($log_msg, $xml) {
|
||||
// Tidy if possible
|
||||
if (class_exists('tidy')) {
|
||||
$tidy = new \tidy;
|
||||
$config = array(
|
||||
'indent' => true,
|
||||
'input-xml' => true,
|
||||
'output-xml' => true,
|
||||
'wrap' => 200
|
||||
);
|
||||
$tidy->parseString($xml, $config, 'utf8');
|
||||
$tidy->cleanRepair();
|
||||
$xml = $tidy;
|
||||
}
|
||||
// Output
|
||||
error_log("Kannel $log_msg: $xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an array is associative
|
||||
*
|
||||
* @param array $array Array to check
|
||||
* @return bool
|
||||
* @author Martin Steel
|
||||
*/
|
||||
protected function is_assoc($array) {
|
||||
return (bool)count(array_filter(array_keys($array), 'is_string'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a number is a valid MSISDN
|
||||
*
|
||||
* @param string $val Value to check
|
||||
* @return bool True if valid MSISDN
|
||||
* @author James Inman
|
||||
* @since 1.3.0
|
||||
* @todo Take an optional country code and check that the number starts with it
|
||||
*/
|
||||
public static function is_valid_msisdn($val) {
|
||||
return preg_match( '/^[1-9][0-9]{7,12}$/', $val );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user