diff --git a/NexmoAccount.php b/NexmoAccount.php index bc11e12..95ea719 100644 --- a/NexmoAccount.php +++ b/NexmoAccount.php @@ -1,244 +1,297 @@ array('method' => 'GET', 'url' => '/account/get-balance/{k}/{s}'), + 'get_pricing' => array('method' => 'GET', 'url' => '/account/get-pricing/outbound/{k}/{s}/{country_code}'), + 'get_own_numbers' => array('method' => 'GET', 'url' => '/account/numbers/{k}/{s}'), + 'search_numbers' => array('method' => 'GET', 'url' => '/number/search/{k}/{s}/{country_code}?pattern={pattern}'), + 'buy_number' => array('method' => 'POST', 'url' => '/number/buy/{k}/{s}/{country_code}/{msisdn}'), + 'cancel_number' => array('method' => 'POST', 'url' => '/number/cancel/{k}/{s}/{country_code}/{msisdn}'), + 'search_message' => array('method' => 'GET', 'url' => '/search/message/{k}/{s}/{message_id}'), + 'search_messages' => array('method' => 'GET', 'url' => '/search/messages/{k}/{s}'), + ); + + /** + * Cache results of API calls + * @var array + */ + private $cache = array(); + + /** + * @param $nx_key Your Nexmo account key + * @param $nx_secret Your Nexmo secret + */ + public function __construct($api_key, $api_secret) { + $this->nx_key = $api_key; + $this->nx_secret = $api_secret; + } - class NexmoAccount { - private $nx_key = ''; - private $nx_secret = ''; - - public $rest_base_url = 'https://rest.nexmo.com/'; - private $rest_commands = array ( - 'get_balance' => array('method' => 'GET', 'url' => '/account/get-balance/{k}/{s}'), - 'get_pricing' => array('method' => 'GET', 'url' => '/account/get-pricing/outbound/{k}/{s}/{country_code}'), - 'get_own_numbers' => array('method' => 'GET', 'url' => '/account/numbers/{k}/{s}'), - 'search_numbers' => array('method' => 'GET', 'url' => '/number/search/{k}/{s}/{country_code}?pattern={pattern}'), - 'buy_number' => array('method' => 'POST', 'url' => '/number/buy/{k}/{s}/{country_code}/{msisdn}'), - 'cancel_number' => array('method' => 'POST', 'url' => '/number/cancel/{k}/{s}/{country_code}/{msisdn}') - ); - - - private $cache = array(); - - /** - * @param $nx_key Your Nexmo account key - * @param $nx_secret Your Nexmo secret - */ - public function __construct ($api_key, $api_secret) { - $this->nx_key = $api_key; - $this->nx_secret = $api_secret; - } - - - /** - * Return your account balance in Euros - * @return float|bool - */ - public function balance () { - if (!isset($this->cache['balance'])) { - $tmp = $this->apiCall('get_balance'); - if (!$tmp['data']) return false; - - $this->cache['balance'] = $tmp['data']['value']; + /** + * Return your account balance in Euros + * @return float|bool + */ + public function balance() { + if (!isset($this->cache['balance'])) { + $tmp = $this->apiCall('get_balance'); + if (!$tmp['data']) { + return false; } - - return (float)$this->cache['balance']; + $this->cache['balance'] = $tmp['data']['value']; } + return (float)$this->cache['balance']; + } - - /** - * Find out the price to send a message to a country - * @param $country_code Country code to return the SMS price for - * @return float|bool - */ - public function smsPricing ($country_code) { - $country_code = strtoupper($country_code); - - if (!isset($this->cache['country_codes'])) - $this->cache['country_codes'] = array(); - - if (!isset($this->cache['country_codes'][$country_code])) { - $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code)); - if (!$tmp['data']) return false; - - $this->cache['country_codes'][$country_code] = $tmp['data']; - } - - return (float)$this->cache['country_codes'][$country_code]['mt']; + /** + * Find out the price to send a message to a country + * @param $country_code Country code to return the SMS price for + * @return float|bool + */ + public function smsPricing($country_code) { + $country_code = strtoupper($country_code); + if (!isset($this->cache['country_codes'])) { + $this->cache['country_codes'] = array(); } - - - /** - * Return a countries international dialing code - * @param $country_code Country code to return the dialing code for - * @return string|bool - */ - public function getCountryDialingCode ($country_code) { - $country_code = strtoupper($country_code); - - if (!isset($this->cache['country_codes'])) - $this->cache['country_codes'] = array(); - - if (!isset($this->cache['country_codes'][$country_code])) { - $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code)); - if (!$tmp['data']) return false; - - $this->cache['country_codes'][$country_code] = $tmp['data']; + if (!isset($this->cache['country_codes'][$country_code])) { + $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code)); + if (!$tmp['data']) { + return false; } - - return (string)$this->cache['country_codes'][$country_code]['prefix']; + $this->cache['country_codes'][$country_code] = $tmp['data']; } + return (float)$this->cache['country_codes'][$country_code]['mt']; + } - - /** - * Get an array of all purchased numbers for your account - * @return array|bool - */ - public function numbersList () { - if (!isset($this->cache['own_numbers'])) { - $tmp = $this->apiCall('get_own_numbers'); - if (!$tmp['data']) return false; - - $this->cache['own_numbers'] = $tmp['data']; + /** + * Return a countries international dialing code + * @param $country_code Country code to return the dialing code for + * @return string|bool + */ + public function getCountryDialingCode($country_code) { + $country_code = strtoupper($country_code); + if (!isset($this->cache['country_codes'])) { + $this->cache['country_codes'] = array(); + } + if (!isset($this->cache['country_codes'][$country_code])) { + $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code)); + if (!$tmp['data']) { + return false; } + $this->cache['country_codes'][$country_code] = $tmp['data']; + } + return (string)$this->cache['country_codes'][$country_code]['prefix']; + } - if (!$this->cache['own_numbers']['numbers']) { - return array(); + /** + * Get an array of all purchased numbers for your account + * @return array|bool + */ + public function numbersList() { + if (!isset($this->cache['own_numbers'])) { + $tmp = $this->apiCall('get_own_numbers'); + if (!$tmp['data']) { + return false; } - - return $this->cache['own_numbers']['numbers']; + $this->cache['own_numbers'] = $tmp['data']; } - - - /** - * Search available numbers to purchase for your account - * @param $country_code Country code to search available numbers in - * @param $pattern Number pattern to search for - * @return bool - */ - public function numbersSearch ($country_code, $pattern) { - $country_code = strtoupper($country_code); - - $tmp = $this->apiCall('search_numbers', array('country_code'=>$country_code, 'pattern'=>$pattern)); - if (!$tmp['data'] || !isset($tmp['data']['numbers'])) return false; - return $tmp['data']['numbers']; + if (!$this->cache['own_numbers']['numbers']) { + return array(); } + return $this->cache['own_numbers']['numbers']; + } - - /** - * Purchase an available number to your account - * @param $country_code Country code for your desired number - * @param $msisdn Full number which you wish to purchase - * @return bool - */ - public function numbersBuy ($country_code, $msisdn) { - $country_code = strtoupper($country_code); - - $tmp = $this->apiCall('buy_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn)); - return ($tmp['http_code'] === 200); + /** + * Search available numbers to purchase for your account + * @param $country_code Country code to search available numbers in + * @param $pattern Number pattern to search for + * @return bool + */ + public function numbersSearch($country_code, $pattern) { + $country_code = strtoupper($country_code); + $tmp = $this->apiCall('search_numbers', array('country_code'=>$country_code, 'pattern'=>$pattern)); + if (!$tmp['data'] || !isset($tmp['data']['numbers'])) { + return false; } + return $tmp['data']['numbers']; + } + /** + * Purchase an available number to your account + * @param $country_code Country code for your desired number + * @param $msisdn Full number which you wish to purchase + * @return bool + */ + public function numbersBuy($country_code, $msisdn) { + $country_code = strtoupper($country_code); + $tmp = $this->apiCall('buy_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn)); + return ($tmp['http_code'] === 200); + } - /** - * Cancel an existing number on your account - * @param $country_code Country code for which the number is for - * @param $msisdn The number to cancel - * @return bool - */ - public function numbersCancel ($country_code, $msisdn) { - $country_code = strtoupper($country_code); + /** + * Cancel an existing number on your account + * @param $country_code Country code for which the number is for + * @param $msisdn The number to cancel + * @return bool + */ + public function numbersCancel($country_code, $msisdn) { + $country_code = strtoupper($country_code); + $tmp = $this->apiCall('cancel_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn)); + return ($tmp['http_code'] === 200); + } - $tmp = $this->apiCall('cancel_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn)); - return ($tmp['http_code'] === 200); + /** + * Search message by id + * @param $message_id Message id to retrieve + * @return boolean|array + */ + public function searchMessage($message_id) { + if (!isset($this->cache['message'][$message_id])) { + $tmp = $this->apiCall('search_message', array('message_id'=>$message_id)); + $message = ($tmp['http_code'] === 200) ? $tmp['data'] : false; + $this->cache['message'][$message_id] = $message; } + return $this->cache['message'][$message_id]; + } + /** + * Search message multiple ids + * @param $ids Array of message ids + * @return boolean|array + */ + public function searchMessages($ids) { + $tmp = $this->apiCall('search_messages', null, compact('ids')); + return ($tmp['http_code'] === 200) ? $tmp['data'] : false; + } - /** - * Run a REST command on Nexmo SMS services - * @param $command - * @param array $data - * @return array|bool - */ - private function apiCall($command, $data=array()) { - if (!isset($this->rest_commands[$command])) { - return false; - } - - $cmd = $this->rest_commands[$command]; - - $url = $cmd['url']; - $url = str_replace(array('{k}', '{s}') ,array($this->nx_key, $this->nx_secret), $url); - - $parsed_data = array(); - foreach ($data as $k => $v) $parsed_data['{'.$k.'}'] = $v; - $url = str_replace(array_keys($parsed_data) ,array_values($parsed_data), $url); - - $url = trim($this->rest_base_url, '/') . $url; - $post_data = ''; - - // If available, use CURL - if (function_exists('curl_version')) { + /** + * Search message by recipient and date + * @param $to Recipent's phone number + * @param $date Date when sms was sent in YYYY-MM-DD format + * @return boolean|array + */ + public function searchMessagesByRecipient($to, $date) { + $tmp = $this->apiCall('search_messages', null, compact('to', 'date')); + return ($tmp['http_code'] === 200) ? $tmp['data'] : false; + } - $to_nexmo = curl_init( $url ); - curl_setopt( $to_nexmo, CURLOPT_RETURNTRANSFER, true ); - curl_setopt( $to_nexmo, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($to_nexmo, CURLOPT_HTTPHEADER, array('Accept: application/json')); + /** + * Run a REST command on Nexmo SMS services + * @param string $command REST command to call + * @param array $data POST data to send + * @param array $query GET paramaters + * @return array|bool + */ + private function apiCall($command, $data=array(), $query=array()) { + if (!isset($this->rest_commands[$command])) { + return false; + } - if ($cmd['method'] == 'POST') { - curl_setopt( $to_nexmo, CURLOPT_POST, true ); - curl_setopt( $to_nexmo, CURLOPT_POSTFIELDS, $post_data ); - } + $cmd = $this->rest_commands[$command]; + $url = $cmd['url']; + $url = str_replace(array('{k}', '{s}'), array($this->nx_key, $this->nx_secret), $url); - $from_nexmo = curl_exec( $to_nexmo ); - $curl_info = curl_getinfo($to_nexmo); - $http_response_code = $curl_info['http_code']; - curl_close ( $to_nexmo ); - - } elseif (ini_get('allow_url_fopen')) { - // No CURL available so try the awesome file_get_contents - - $opts = array('http' => - array( - 'method' => 'GET', - 'header' => 'Accept: application/json' - ) - ); - - if ($cmd['method'] == 'POST') { - $opts['http']['method'] = 'POST'; - $opts['http']['header'] .= "\r\nContent-type: application/x-www-form-urlencoded"; - $opts['http']['content'] = $post_data; + $parsed_data = array(); + foreach ((array)$data as $k => $v) { + $parsed_data['{'.$k.'}'] = $v; + } + $url = str_replace(array_keys($parsed_data), array_values($parsed_data), $url); + + $url = trim($this->rest_base_url, '/') . $url; + $queryString = ''; + foreach($query as $k => $v) { + if (is_array($v)) { + foreach($v as $i) { + $queryString .= "$k=$i&"; } - - $context = stream_context_create($opts); - $from_nexmo = file_get_contents($url, false, $context); - - // et the response code - preg_match('/HTTP\/[^ ]+ ([0-9]+)/i', $http_response_header[0], $m); - $http_response_code = $m[1]; - } else { - // No way of sending a HTTP post :( - return false; + $queryString .= "$k=$v&"; } - - $data = json_decode($from_nexmo, true); - return array( - 'data' => $data, - 'http_code' => (int)$http_response_code + } + if ($queryString) { + $url .= '?' . substr($queryString, 0, -1); + } + $post_data = ''; + + // If available, use CURL + if (function_exists('curl_version')) { + $to_nexmo = curl_init( $url ); + curl_setopt($to_nexmo, CURLOPT_RETURNTRANSFER, true); + curl_setopt($to_nexmo, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($to_nexmo, CURLOPT_HTTPHEADER, array('Accept: application/json')); + if ($cmd['method'] == 'POST') { + curl_setopt($to_nexmo, CURLOPT_POST, true); + curl_setopt($to_nexmo, CURLOPT_POSTFIELDS, $post_data); + } + $from_nexmo = curl_exec($to_nexmo); + $curl_info = curl_getinfo($to_nexmo); + $http_response_code = $curl_info['http_code']; + curl_close ($to_nexmo); + } elseif (ini_get('allow_url_fopen')) { + // No CURL available so try the awesome file_get_contents + $opts = array('http' => + array( + 'method' => 'GET', + 'header' => 'Accept: application/json' + ) ); - + if ($cmd['method'] == 'POST') { + $opts['http']['method'] = 'POST'; + $opts['http']['header'] .= "\r\nContent-type: application/x-www-form-urlencoded"; + $opts['http']['content'] = $post_data; + } + $context = stream_context_create($opts); + $from_nexmo = file_get_contents($url, false, $context); + // get the response code + preg_match('/HTTP\/[^ ]+ ([0-9]+)/i', $http_response_header[0], $m); + $http_response_code = $m[1]; + } else { + // No way of sending a HTTP post :`( + return false; } + $data = json_decode($from_nexmo, true); + return array( + 'data' => $data, + 'http_code' => (int)$http_response_code + ); } + +} \ No newline at end of file diff --git a/NexmoMessage.php b/NexmoMessage.php index aa63d56..2762e0e 100644 --- a/NexmoMessage.php +++ b/NexmoMessage.php @@ -1,21 +1,18 @@ nx_key = $api_key; $this->nx_secret = $api_secret; } - - /** * Prepare new text message. * @@ -70,8 +61,7 @@ function NexmoMessage ($api_key, $api_secret) { * message type. Otherwise set to TRUE if you require * unicode characters. */ - function sendText ( $to, $from, $message, $unicode=null ) { - + function sendText($to, $from, $message, $unicode=null) { // Making sure strings are UTF-8 encoded if ( !is_numeric($from) && !mb_check_encoding($from, 'UTF-8') ) { trigger_error('$from needs to be a valid UTF-8 encoded string'); @@ -93,8 +83,8 @@ function sendText ( $to, $from, $message, $unicode=null ) { $from = $this->validateOriginator($from); // URL Encode - $from = urlencode( $from ); - $message = urlencode( $message ); + $from = urlencode($from); + $message = urlencode($message); // Send away! $post = array( @@ -103,19 +93,16 @@ function sendText ( $to, $from, $message, $unicode=null ) { 'text' => $message, 'type' => $containsUnicode ? 'unicode' : 'text' ); - return $this->sendRequest ( $post ); - + return $this->sendRequest($post); } - /** * Prepare new WAP message. */ - function sendBinary ( $to, $from, $body, $udh ) { - + function sendBinary($to, $from, $body, $udh) { //Binary messages must be hex encoded - $body = bin2hex ( $body ); - $udh = bin2hex ( $udh ); + $body = bin2hex($body); + $udh = bin2hex($udh); // Make sure $from is valid $from = $this->validateOriginator($from); @@ -128,18 +115,15 @@ function sendBinary ( $to, $from, $body, $udh ) { 'body' => $body, 'udh' => $udh ); - return $this->sendRequest ( $post ); - + return $this->sendRequest($post); } - - + /** * Prepare new binary message. */ - function pushWap ( $to, $from, $title, $url, $validity = 172800000 ) { - + function pushWap($to, $from, $title, $url, $validity=172800000) { // Making sure $title and $url are UTF-8 encoded - if ( !mb_check_encoding($title, 'UTF-8') || !mb_check_encoding($url, 'UTF-8') ) { + if (!mb_check_encoding($title, 'UTF-8') || !mb_check_encoding($url, 'UTF-8')) { trigger_error('$title and $udh need to be valid UTF-8 encoded strings'); return false; } @@ -156,15 +140,13 @@ function pushWap ( $to, $from, $title, $url, $validity = 172800000 ) { 'title' => $title, 'validity' => $validity ); - return $this->sendRequest ( $post ); - + return $this->sendRequest($post); } - /** * Prepare and send a new message. */ - private function sendRequest ( $data ) { + private function sendRequest($data) { // Build the post data $data = array_merge($data, array('username' => $this->nx_key, 'password' => $this->nx_secret)); $post = ''; @@ -174,22 +156,17 @@ private function sendRequest ( $data ) { // If available, use CURL if (function_exists('curl_version')) { - - $to_nexmo = curl_init( $this->nx_uri ); - curl_setopt( $to_nexmo, CURLOPT_POST, true ); - curl_setopt( $to_nexmo, CURLOPT_RETURNTRANSFER, true ); - curl_setopt( $to_nexmo, CURLOPT_POSTFIELDS, $post ); - + $to_nexmo = curl_init($this->nx_uri); + curl_setopt($to_nexmo, CURLOPT_POST, true); + curl_setopt($to_nexmo, CURLOPT_RETURNTRANSFER, true); + curl_setopt($to_nexmo, CURLOPT_POSTFIELDS, $post); if (!$this->ssl_verify) { - curl_setopt( $to_nexmo, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($to_nexmo, CURLOPT_SSL_VERIFYPEER, false); } - - $from_nexmo = curl_exec( $to_nexmo ); - curl_close ( $to_nexmo ); - + $from_nexmo = curl_exec($to_nexmo); + curl_close ($to_nexmo); } elseif (ini_get('allow_url_fopen')) { // No CURL available so try the awesome file_get_contents - $opts = array('http' => array( 'method' => 'POST', @@ -199,50 +176,37 @@ private function sendRequest ( $data ) { ); $context = stream_context_create($opts); $from_nexmo = file_get_contents($this->nx_uri, false, $context); - } else { // No way of sending a HTTP post :( return false; } - $from_nexmo = str_replace('-', '', $from_nexmo); - - return $this->nexmoParse( $from_nexmo ); - + return $this->nexmoParse($from_nexmo); } - /** * Parse server response. */ - private function nexmoParse ( $from_nexmo ) { - - $response_obj = json_decode( $from_nexmo ); - + private function nexmoParse($from_nexmo) { + $response_obj = json_decode($from_nexmo); if ($response_obj) { $this->nexmo_response = $response_obj; - // Find the total cost of this message $response_obj->cost = $total_cost = 0; if (is_array($response_obj->messages)) { - foreach ($response_obj->messages as $msg) { + foreach($response_obj->messages as $msg) { $total_cost = $total_cost + (float)$msg->messageprice; } - $response_obj->cost = $total_cost; } - return $response_obj; - } else { // A malformed response $this->nexmo_response = array(); return false; } - } - /** * Validate an originator string * @@ -253,81 +217,65 @@ private function nexmoParse ( $from_nexmo ) { private function validateOriginator($inp){ // Remove any invalid characters $ret = preg_replace('/[^a-zA-Z0-9]/', '', (string)$inp); - if(preg_match('/[a-zA-Z]/', $inp)){ - // Alphanumeric format so make sure it's < 11 chars $ret = substr($ret, 0, 11); - } else { - // Numerical, remove any prepending '00' if(substr($ret, 0, 2) == '00'){ $ret = substr($ret, 2); $ret = substr($ret, 0, 15); } } - return (string)$ret; } - - - - public function displayOverview( $nexmo_response=null ){ + public function displayOverview($nexmo_response=null){ $info = (!$nexmo_response) ? $this->nexmo_response : $nexmo_response; - - if (!$nexmo_response ) return 'Cannot display an overview of this response'; - + if (!$nexmo_response ) { + return 'Cannot display an overview of this response'; + } // How many messages were sent? - if ( $info->messagecount > 1 ) { - + if ($info->messagecount > 1) { $status = 'Your message was sent in ' . $info->messagecount . ' parts'; - - } elseif ( $info->messagecount == 1) { - + } elseif ($info->messagecount == 1) { $status = 'Your message was sent'; - } else { - return 'There was an error sending your message'; } // Build an array of each message status and ID - if (!is_array($info->messages)) $info->messages = array(); + if (!is_array($info->messages)) { + $info->messages = array(); + } $message_status = array(); - foreach ( $info->messages as $message ) { + foreach($info->messages as $message) { $tmp = array('id'=>'', 'status'=>0); - if ( $message->status != 0) { $tmp['status'] = $message->errortex; } else { $tmp['status'] = 'OK'; $tmp['id'] = $message->messageid; } - $message_status[] = $tmp; } - // Build the output if (isset($_SERVER['HTTP_HOST'])) { // HTML output $ret = ''; $ret .= ''; - foreach ($message_status as $mstat) { + foreach($message_status as $mstat) { $ret .= ''; } $ret .= '
'.$status.'
StatusMessage ID
'.$mstat['status'].''.$mstat['id'].'
'; - } else { - // CLI output $ret = "$status:\n"; // Get the sizes for the table $out_sizes = array('id'=>strlen('Message ID'), 'status'=>strlen('Status')); - foreach ($message_status as $mstat) { + foreach($message_status as $mstat) { if ($out_sizes['id'] < strlen($mstat['id'])) { $out_sizes['id'] = strlen($mstat['id']); } @@ -335,63 +283,52 @@ public function displayOverview( $nexmo_response=null ){ $out_sizes['status'] = strlen($mstat['status']); } } - $ret .= ' '.str_pad('Status', $out_sizes['status'], ' ').' '; $ret .= str_pad('Message ID', $out_sizes['id'], ' ')."\n"; - foreach ($message_status as $mstat) { + foreach($message_status as $mstat) { $ret .= ' '.str_pad($mstat['status'], $out_sizes['status'], ' ').' '; $ret .= str_pad($mstat['id'], $out_sizes['id'], ' ')."\n"; } } - return $ret; } - - - - - - /** * Inbound text methods */ - /** * Check for any inbound messages, using $_GET by default. * * This will set the current message to the inbound * message allowing for a future reply() call. */ - public function inboundText( $data=null ){ - if(!$data) $data = $_GET; - - if(!isset($data['text'], $data['msisdn'], $data['to'])) return false; - + public function inboundText($data=null){ + if(!$data) { + $data = $_GET; + } + if(!isset($data['text'], $data['msisdn'], $data['to'])) { + return false; + } // Get the relevant data $this->to = $data['to']; $this->from = $data['msisdn']; $this->text = $data['text']; $this->network = (isset($data['network-code'])) ? $data['network-code'] : ''; $this->message_id = $data['messageId']; - // Flag that we have an inbound message $this->inbound_message = true; - return true; } - /** * Reply the current message if one is set. */ - public function reply ($message) { + public function reply($message) { // Make sure we actually have a text to reply to if (!$this->inbound_message) { return false; } - return $this->sendText($this->from, $this->to, $message); } diff --git a/NexmoReceipt.php b/NexmoReceipt.php index b4277f6..27634c5 100644 --- a/NexmoReceipt.php +++ b/NexmoReceipt.php @@ -1,15 +1,13 @@ found = true; @@ -55,4 +53,5 @@ public function __construct ($data = false) { public function exists () { return $this->found; } + } \ No newline at end of file