├── .github └── workflows │ └── run-tests.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── resources └── config.php ├── src ├── BulkSmsException.php ├── BulkSmsService.php ├── Laravel │ ├── BulkSms.php │ ├── BulkSmsService.php │ └── BulkSmsServiceProvider.php ├── Message.php └── Sender │ ├── AbstractSender.php │ ├── Bulk.php │ ├── Single.php │ └── Status.php └── tests ├── MessageConcatTest.php ├── ParseRecipientTest.php └── Sender ├── BulkSmsServiceGetStatusTest.php ├── BulkSmsServiceSendBatchMessageTest.php └── BulkSmsServiceSendSingleMessageTest.php /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | 'on': 4 | push: 5 | branches: 6 | - master 7 | - develop 8 | tags: 9 | - '**' 10 | pull_request: 11 | branches: 12 | - '**' 13 | schedule: 14 | - cron: '0 8 1 * *' 15 | 16 | jobs: 17 | phpunit: 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | php-version: 22 | - '5.6' 23 | - '7.0' 24 | - '7.1' 25 | - '7.2' 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: shivammathur/setup-php@v2 29 | with: 30 | php-version: ${{ matrix.php-version }} 31 | tools: composer 32 | - run: composer install --dev 33 | - run: ./vendor/bin/phpunit 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2015 Andreas Lutro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BulkSMS API - PHP implementation 2 | A simple implementation of BulkSMS for PHP. 3 | 4 | Includes functionality to send single or batch messages. 5 | 6 | ## Installation 7 | 8 | This package requires PHP 5.4 because I'm too lazy to type `array()`. Sorry. 9 | 10 | Using composer: `composer require anlutro/bulk-sms` - list of versions is available through GitHub's tag list. 11 | 12 | ### Laravel 13 | 14 | The package includes files to make usage super easy in Laravel 4 and higher. 15 | 16 | 1. Add `anlutro\BulkSms\Laravel\BulkSmsServiceProvider` to the list of providers in `app/config/app.php`. 17 | 2. Run `php artisan config:publish anlutro/bulk-sms`. Edit the config file in `app/config/packages/anlutro/bulk-sms` and fill in your username and password. 18 | 3. (optional) Add an alias for the facade by adding `'BulkSms' => 'anlutro\BulkSms\Laravel\BulkSms'` to aliases in `app/config/app.php`. 19 | 20 | ## Credentials 21 | 22 | To use this library you need create an account with Bulksms. They support several sub-sites for specific regions. 23 | 24 | 1. Username : Bulksms login 25 | 2. Password : Bulksms login password 26 | 3. Baseurl : Bulksms sub-site to connect to (e.g. 'http://bulksms.com' or 'http://bulksms.de') 27 | 28 | ## Usage 29 | 30 | Send a single message: 31 | 32 | ```php 33 | $bulkSms = new anlutro\BulkSms\BulkSmsService('username', 'password', 'baseurl'); 34 | $bulkSms->sendMessage('12345678', 'Hello there!'); 35 | ``` 36 | 37 | Send more than one message at the same time by providing an array of messages: 38 | 39 | ```php 40 | $message1 = new \anlutro\BulkSms\Message('12345678', 'Hi there'); 41 | $message2 = new \anlutro\BulkSms\Message('12345678', 'Hello again'); 42 | $bulkSms = new anlutro\BulkSms\BulkSmsService('username', 'password', 'baseurl'); 43 | $bulkSms->sendMessage(array($message1,$message2)); 44 | ``` 45 | 46 | Get the status of a batch of messages: 47 | 48 | ```php 49 | $bulkSms = new anlutro\BulkSms\BulkSmsService('username', 'password', 'baseurl'); 50 | $bulkSms->getStatusForBatchId(693099785); 51 | ``` 52 | 53 | ## Sending unicode messages 54 | 55 | In order to send unicode messages, make sure your message is UTF-16, convert 56 | them to hexadecimal, and specify the 'dca' parameter: 57 | 58 | ```php 59 | $text = 'السلام عليكم'; 60 | $encodedMessage = bin2hex(mb_convert_encoding($text, 'utf-16', 'utf-8')) ; 61 | $bulkSms->sendMessage('12345678', $encodedMessage, ['dca' => '16bit']); 62 | ``` 63 | 64 | ## Send test messages 65 | 66 | BulkSms suports test modes (SUCCESS and FAIL) that validate the message and return defined responses without really sending out SMS. In order to send messages in test mode, run the following: 67 | 68 | Send message that will return a success: 69 | 70 | ```php 71 | $bulkSms = new anlutro\BulkSms\BulkSmsService('username', 'password', 'baseurl'); 72 | $bulkSms->setTestMode(\anlutro\BulkSms\BulkSmsService::TEST_ALWAYS_SUCCEED); 73 | $bulkSms->getStatusForBatchId(693099785); 74 | ``` 75 | 76 | Send message that will return a failure response - and thus trigger a BulkSmsException : 77 | 78 | ```php 79 | $bulkSms = new anlutro\BulkSms\BulkSmsService('username', 'password', 'baseurl'); 80 | $bulkSms->setTestMode(\anlutro\BulkSms\BulkSmsService::TEST_ALWAYS_FAIL); 81 | $bulkSms->getStatusForBatchId(693099785); 82 | ``` 83 | 84 | In Laravel, you don't need to construct `$bulkSms`, and you can replace `$bulkSms->` with `BulkSms::` provided you followed the installation steps above. 85 | 86 | # Contact 87 | Open an issue on GitHub if you have any problems or suggestions. 88 | 89 | # License 90 | The contents of this repository is released under the [MIT license](http://opensource.org/licenses/MIT). -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anlutro/bulk-sms", 3 | "description": "BulkSMS API implementation in PHP.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Andreas Lutro", 8 | "email": "anlutro@gmail.com" 9 | }, 10 | { 11 | "name": "Michael Nowag", 12 | "email": "michaelnowag@gmail.com" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.4.0", 17 | "anlutro/curl": "~1.4.6", 18 | "respect/validation": "~1.0" 19 | }, 20 | "require-dev": { 21 | "mockery/mockery": "0.9.*", 22 | "phpunit/phpunit": "<6" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "anlutro\\BulkSms\\": "src/" 27 | } 28 | }, 29 | "minimum-stability": "dev" 30 | } 31 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /resources/config.php: -------------------------------------------------------------------------------- 1 | 'REPLACEME', 4 | 'password' => 'REPLACEME', 5 | 6 | 'baseurl' => 'http://bulksms.vsms.net:5567', 7 | // 'baseurl' => 'http://bulksms.com', 8 | // 'baseurl' => 'http://bulksms.de', 9 | ); 10 | -------------------------------------------------------------------------------- /src/BulkSmsException.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms; 11 | 12 | class BulkSmsException extends \Exception 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/BulkSmsService.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms; 11 | 12 | use anlutro\cURL\cURL; 13 | use Respect\Validation\Validator as v; 14 | 15 | /** 16 | * The main API class. 17 | */ 18 | class BulkSmsService 19 | { 20 | const TEST_ALWAYS_SUCCEED = 1; 21 | const TEST_ALWAYS_FAIL = 2; 22 | 23 | /** 24 | * Meaning of response status codes. 25 | * 26 | * @var array 27 | */ 28 | protected static $statusMessages = array( 29 | 0 => 'In progress', 30 | 10 => 'Delivered upstream', 31 | 11 => 'Delivered mobile', 32 | 12 => 'Delivered upstream unacknowledged (presume in progress)', 33 | 1 => 'Scheduled', 34 | 22 => 'Internal fatal error', 35 | 23 => 'Authentication error', 36 | 24 => 'Data validation failed', 37 | 25 => 'Insufficient credits', 38 | 26 => 'Upstream credits not available', 39 | 27 => 'Daily quota exceeded', 40 | 28 => 'Upstream quota exceeded', 41 | 40 => 'Temporarily unavailable', 42 | 201 => 'Maximum batch size exceeded', 43 | ); 44 | 45 | /** 46 | * Whether test mode is enabled. 47 | * 48 | * @var boolean 49 | */ 50 | protected $testMode = false; 51 | 52 | /** 53 | * BulkSMS username 54 | * 55 | * @var string 56 | */ 57 | protected $username; 58 | 59 | /** 60 | * BulkSMS password 61 | * 62 | * @var string 63 | */ 64 | protected $password; 65 | 66 | /** 67 | * @var string 68 | */ 69 | protected $baseUrl; 70 | 71 | /** 72 | * @param string $username BulkSMS username 73 | * @param string $password BulkSMS password 74 | * @param string $baseUrl Optional - defaults to "http://bulksms.vsms.net:5567" 75 | * @param cURL $curl Optional - a new instance will be constructed if null is passed. 76 | */ 77 | public function __construct($username, $password, $baseUrl = "http://bulksms.vsms.net:5567", $curl = null) 78 | { 79 | v::url()->setName("Base Bulksms URL")->check($baseUrl); 80 | $this->baseUrl = $baseUrl; 81 | $this->username = $username; 82 | $this->password = $password; 83 | $this->curl = $curl ?: new cURL(); 84 | } 85 | 86 | /** 87 | * Set test mode 88 | * 89 | * @param $mode 90 | */ 91 | public function setTestMode($mode) 92 | { 93 | if (BulkSmsService::TEST_ALWAYS_SUCCEED == $mode) { 94 | $this->testMode = BulkSmsService::TEST_ALWAYS_SUCCEED; 95 | } elseif (BulkSmsService::TEST_ALWAYS_FAIL == $mode) { 96 | $this->testMode = BulkSmsService::TEST_ALWAYS_FAIL; 97 | } else { 98 | throw new \InvalidArgumentException("Invalid test mode: " . $mode); 99 | } 100 | } 101 | 102 | /** 103 | * Send a single message. 104 | * 105 | * @param string $recipient 106 | * @param string $message 107 | * @param array $params 108 | * 109 | * @return mixed 110 | */ 111 | public function sendMessage($recipient, $message, array $params = null) 112 | { 113 | $sender = $this->createMessageSender(); 114 | 115 | $msg = $this->createMessage($recipient, $message); 116 | 117 | $sender->setMessage($msg); 118 | if ($params) { 119 | $sender->setParams($params); 120 | } 121 | $response = $sender->send($this->testMode); 122 | $this->validateResponse($response); 123 | 124 | return $sender->extractResponse($response); 125 | } 126 | 127 | /** 128 | * Create a message sender instance. 129 | * 130 | * @return anlutro\BulkSms\Sender\Single 131 | */ 132 | protected function createMessageSender() 133 | { 134 | return new Sender\Single($this->username, $this->password, $this->baseUrl, $this->curl); 135 | } 136 | 137 | /** 138 | * Create a message instance. 139 | * 140 | * @param string $recipient 141 | * @param string $message 142 | * 143 | * @return anlutro\BulkSms\Message 144 | */ 145 | protected function createMessage($recipient, $message) 146 | { 147 | return new Message($recipient, $message); 148 | } 149 | 150 | /** 151 | * Validate a response from the API to check for errors 152 | * 153 | * @param anlutro\cURL\Response $response 154 | * 155 | * @return bool 156 | * @throws BulkSmsException 157 | */ 158 | public function validateResponse($response) 159 | { 160 | if ($response->statusCode !== 200) { 161 | throw new BulkSmsException('BulkSMS API responded with HTTP status code ' . $response->statusCode); 162 | } 163 | 164 | $parts = explode('|', $response->body); 165 | 166 | if (!is_numeric($parts[ 0 ])) { 167 | throw new \UnexpectedValueException( 168 | 'Unknown response code: ' . $parts[ 0 ] . ' - full response: ' . $response->body 169 | ); 170 | } 171 | 172 | $code = (int) $parts[ 0 ]; 173 | 174 | if ($code === 0 || $code === 1) { 175 | return true; 176 | } 177 | 178 | $message = array_key_exists($code, static::$statusMessages) 179 | ? static::$statusMessages[ $code ] 180 | : $parts[ 1 ]; 181 | throw new BulkSmsException('BulkSMS API responded with code: ' . $code . ' - ' . $message); 182 | } 183 | 184 | /** 185 | * Send messages in bulk. 186 | * 187 | * @param Message[] $messages 188 | * @param array $params 189 | * 190 | * @return mixed 191 | */ 192 | public function sendBulkMessages(array $messages, array $params = null) 193 | { 194 | $sender = $this->createBulkSender(); 195 | v::notEmpty()->setName("BulkSms Array")->check($messages); 196 | 197 | foreach ($messages as $message) { 198 | // make sure messages are proper objects 199 | v::instance('anlutro\BulkSms\Message')->check($message); 200 | $sender->addMessage($message); 201 | } 202 | 203 | if ($params) { 204 | $sender->setParams($params); 205 | } 206 | $response = $sender->send($this->testMode); 207 | $this->validateResponse($response); 208 | 209 | return $sender->extractResponse($response); 210 | } 211 | 212 | /** 213 | * Create a message sender instance. 214 | * 215 | * @return anlutro\BulkSms\Sender\Bulk 216 | */ 217 | protected function createBulkSender() 218 | { 219 | return new Sender\Bulk($this->username, $this->password, $this->baseUrl, $this->curl); 220 | } 221 | 222 | /** 223 | * Check status for single id 224 | * 225 | * @param string $bulksmsid 226 | * 227 | * @return mixed 228 | */ 229 | public function getStatusForBatchId($bulksmsid) 230 | { 231 | $sender = $this->createBulkStatusSender(); 232 | $response = $sender->getStatusForBatchId($bulksmsid, $this->testMode); 233 | $this->validateResponse($response); 234 | 235 | return $sender->extractResponse($response); 236 | } 237 | 238 | /** 239 | * Create a message sender instance. 240 | * 241 | * @return anlutro\BulkSms\Sender\Status 242 | */ 243 | protected function createBulkStatusSender() 244 | { 245 | return new Sender\Status($this->username, $this->password, $this->baseUrl, $this->curl); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/Laravel/BulkSms.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Laravel; 11 | 12 | use Illuminate\Support\Facades\Facade; 13 | 14 | /** 15 | * Facade for easy access to a BulkSmsService instance. 16 | */ 17 | class BulkSms extends Facade 18 | { 19 | /** 20 | * The facade accessor. 21 | * 22 | * @return string 23 | */ 24 | protected static function getFacadeAccessor() 25 | { 26 | return 'bulksms'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Laravel/BulkSmsService.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Laravel; 11 | 12 | use Illuminate\Support\Facades\View; 13 | 14 | /** 15 | * The main API class. 16 | */ 17 | class BulkSmsService extends \anlutro\BulkSms\BulkSmsService 18 | { 19 | /** 20 | * Send a view with data to a recipient. Made to imitate Laravel's 21 | * Mail::send syntax. 22 | * 23 | * @param string $view 24 | * @param array $data 25 | * @param string $recipient Phone number 26 | * 27 | * @return mixed 28 | */ 29 | public function send($view, $data, $recipient) 30 | { 31 | $message = View::make($view, $data)->render(); 32 | 33 | return $this->sendMessage($recipient, $message); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Laravel/BulkSmsServiceProvider.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Laravel; 11 | 12 | use Illuminate\Foundation\Application; 13 | use Illuminate\Support\ServiceProvider; 14 | 15 | /** 16 | * Bootstrap an instance of BulkSmsService so that it can be accessed through 17 | * a facade and register the config. 18 | */ 19 | class BulkSmsServiceProvider extends ServiceProvider 20 | { 21 | /** 22 | * Whether the service provider should be deferred or not. 23 | * 24 | * @var boolean 25 | */ 26 | protected $defer = false; 27 | 28 | /** 29 | * Whether the Laravel version is 5.x or not. 30 | * 31 | * @var boolean 32 | */ 33 | protected $l5; 34 | 35 | /** 36 | * Register the service on the IoC container. 37 | * 38 | * @return void 39 | */ 40 | public function register() 41 | { 42 | $l5 = $this->l5 = version_compare(Application::VERSION, '5.0', '>='); 43 | 44 | $factory = function ($app) use($l5) { 45 | $delim = $l5 ? '.' : '::'; 46 | $config = $app['config']; 47 | $username = $config->get("bulk-sms{$delim}username"); 48 | $password = $config->get("bulk-sms{$delim}password"); 49 | $baseurl = $config->get("bulk-sms{$delim}baseurl"); 50 | 51 | $curl = isset($app['curl']) ? $app['curl'] : null; 52 | 53 | return new BulkSmsService($username, $password, $baseurl, $curl); 54 | }; 55 | 56 | if (version_compare(Application::VERSION, '5.4', '>=')) { 57 | $this->app->singleton('bulksms', $factory); 58 | } else { 59 | $this->app['bulksms'] = $this->app->share($factory); 60 | } 61 | 62 | 63 | if ($l5) { 64 | $dir = dirname(dirname(__DIR__)).'/resources'; 65 | $this->mergeConfigFrom($dir.'/config.php', 'bulk-sms'); 66 | } 67 | } 68 | 69 | /** 70 | * Load the package config files. 71 | * 72 | * @return void 73 | */ 74 | public function boot() 75 | { 76 | $dir = dirname(dirname(__DIR__)).'/resources'; 77 | 78 | if ($this->l5) { 79 | $this->publishes([ 80 | $dir.'/config.php' => config_path('bulk-sms.php') 81 | ], 'config'); 82 | } else { 83 | $this->app['config']->package('bulk-sms', $dir, 'bulk-sms'); 84 | } 85 | } 86 | 87 | /** 88 | * The services provided. 89 | * 90 | * @return array 91 | */ 92 | public function provides() 93 | { 94 | return ['bulksms']; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Message.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms; 11 | 12 | /** 13 | * Container class for a single SMS message. 14 | */ 15 | class Message 16 | { 17 | /** 18 | * Phone number of the recipient. 19 | * 20 | * @var string 21 | */ 22 | protected $recipient; 23 | 24 | /** 25 | * The text message to be sent. 26 | * 27 | * @var string 28 | */ 29 | protected $message; 30 | 31 | /** 32 | * Whether or not the message needs to be concatenated. 33 | * 34 | * @var bool 35 | */ 36 | protected $concat = false; 37 | 38 | /** 39 | * Where to start concatenating SMSes. 40 | * 41 | * @var integer 42 | */ 43 | protected $concatLimit = 140; 44 | 45 | /** 46 | * @param $recipient 47 | * @param $text 48 | */ 49 | public function __construct($recipient, $text) 50 | { 51 | $this->setRecipient($recipient); 52 | $this->setMessage($text); 53 | } 54 | 55 | /** 56 | * Get the recipient. 57 | * 58 | * @return string 59 | */ 60 | public function getRecipient() 61 | { 62 | return $this->recipient; 63 | } 64 | 65 | /** 66 | * Set the recipient. 67 | * 68 | * @param string|int $recipient 69 | * 70 | * @return $this 71 | */ 72 | protected function setRecipient($recipient) 73 | { 74 | $this->recipient = $this->parseNumber($recipient); 75 | 76 | return $this; 77 | } 78 | 79 | /** 80 | * Get the message. 81 | * 82 | * @return string 83 | */ 84 | public function getMessage() 85 | { 86 | return $this->message; 87 | } 88 | 89 | /** 90 | * Set the message. 91 | * 92 | * @param string $message 93 | * 94 | * @return $this 95 | */ 96 | protected function setMessage($message) 97 | { 98 | $this->message = $this->encodeMessage($message); 99 | 100 | if (strlen($this->message) > $this->concatLimit) { 101 | $this->concat = true; 102 | } 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Get how many SMSes the message may have to be concatenated into. 109 | * 110 | * @return int 111 | */ 112 | public function getConcatParts() 113 | { 114 | if (!$this->concat) { 115 | return 1; 116 | } else { 117 | return $this->calculateConcat(); 118 | } 119 | } 120 | 121 | /** 122 | * Calculate from the message string how many SMSes it may have to span. 123 | * 124 | * @return int 125 | */ 126 | protected function calculateConcat() 127 | { 128 | $len = strlen($this->message); 129 | $i = $this->concatLimit; 130 | $j = 1; 131 | 132 | while ($i < $len) { 133 | $i += $this->concatLimit; 134 | $j++; 135 | } 136 | 137 | return $j; 138 | } 139 | 140 | /** 141 | * Parse a phone number. 142 | * 143 | * @param string $number 144 | * 145 | * @return string 146 | */ 147 | protected function parseNumber($number) 148 | { 149 | $number = (string) $number; 150 | 151 | // remove whitespaces 152 | $number = trim($number); 153 | $number = str_replace(' ', '', $number); 154 | 155 | // remove + in front if exists 156 | if (substr($number, 0, 1) == '+') { 157 | $number = substr($number, 1); 158 | } 159 | 160 | // remove 0s in front if exists 161 | while (substr($number, 0, 1) === '0') { 162 | $number = substr($number, 1); 163 | } 164 | 165 | // we should at this point have a normal number 166 | if (!is_numeric($number)) { 167 | throw new \InvalidArgumentException("Invalid SMS recipient: $number"); 168 | } 169 | 170 | // is phone number is less than 9 characters, assume we need to append 171 | // a country code 172 | if (strlen($number) <= 8) { 173 | throw new \InvalidArgumentException( 174 | "Recipient number is too short. Is the country code missing?: " . $number 175 | ); 176 | } 177 | 178 | return $number; 179 | } 180 | 181 | /** 182 | * Encode a message to the retarded GSM-charset. 183 | * 184 | * @param string $message 185 | * 186 | * @return string 187 | */ 188 | protected function encodeMessage($message) 189 | { 190 | $replaceCharacters = array( 191 | 'Δ' => '0xD0', 192 | 'Φ' => '0xDE', 193 | 'Γ' => '0xAC', 194 | 'Λ' => '0xC2', 195 | 'Ω' => '0xDB', 196 | 'Π' => '0xBA', 197 | 'Ψ' => '0xDD', 198 | 'Σ' => '0xCA', 199 | 'Θ' => '0xD4', 200 | 'Ξ' => '0xB1', 201 | '¡' => '0xA1', 202 | '£' => '0xA3', 203 | '¤' => '0xA4', 204 | '¥' => '0xA5', 205 | '§' => '0xA7', 206 | '¿' => '0xBF', 207 | 'Ä' => '0xC4', 208 | 'Å' => '0xC5', 209 | 'Æ' => '0xC6', 210 | 'Ç' => '0xC7', 211 | 'É' => '0xC9', 212 | 'Ñ' => '0xD1', 213 | 'Ö' => '0xD6', 214 | 'Ø' => '0xD8', 215 | 'Ü' => '0xDC', 216 | 'ß' => '0xDF', 217 | 'à' => '0xE0', 218 | 'ä' => '0xE4', 219 | 'å' => '0xE5', 220 | 'æ' => '0xE6', 221 | 'è' => '0xE8', 222 | 'é' => '0xE9', 223 | 'ì' => '0xEC', 224 | 'ñ' => '0xF1', 225 | 'ò' => '0xF2', 226 | 'ö' => '0xF6', 227 | 'ø' => '0xF8', 228 | 'ù' => '0xF9', 229 | 'ü' => '0xFC', 230 | ); 231 | 232 | $message = utf8_decode($message); 233 | $message = str_replace('"', '\"', $message); 234 | $message = strtr($message, $replaceCharacters); 235 | 236 | return $message; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/Sender/AbstractSender.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Sender; 11 | 12 | use anlutro\cURL\cURL; 13 | use anlutro\cURL\Response; 14 | use Respect\Validation\Validator as v; 15 | 16 | abstract class AbstractSender 17 | { 18 | /** 19 | * BulkSMS username 20 | * 21 | * @var string 22 | */ 23 | protected $username; 24 | 25 | /** 26 | * BulkSMS password 27 | * 28 | * @var string 29 | */ 30 | protected $password; 31 | 32 | /** 33 | * The endpoint the call should go to. 34 | * 35 | * @var string 36 | */ 37 | protected $endpoint; 38 | 39 | /** 40 | * The base URL of the API. 41 | * 42 | * @var string 43 | */ 44 | protected $baseUrl; 45 | 46 | /** 47 | * The cURL instance. 48 | * 49 | * @var cURL 50 | */ 51 | protected $curl; 52 | 53 | /** 54 | * Additional BulkSMS params 55 | * 56 | * @var array 57 | */ 58 | protected $params = array(); 59 | 60 | /** 61 | * @param string $username BulkSMS username 62 | * @param string $password BulkSMS password 63 | * @param $baseUrl 64 | * @param cURL $curl 65 | */ 66 | public function __construct($username, $password, $baseUrl, cURL $curl = null) 67 | { 68 | v::url()->setName("Base Bulksms URL")->check($baseUrl); 69 | $this->baseUrl = $baseUrl; 70 | $this->username = $username; 71 | $this->password = $password; 72 | $this->curl = $curl ?: new cURL(); 73 | } 74 | 75 | public function setParams(array $params) 76 | { 77 | $this->params = $params; 78 | } 79 | 80 | /** 81 | * Extract response from Sender - depends on sender 82 | * 83 | * @param Response $response 84 | * 85 | * @return mixed 86 | */ 87 | abstract public function extractResponse(Response $response); 88 | 89 | /** 90 | * Get the full URL for the request. 91 | * 92 | * @return string 93 | */ 94 | protected function getUrl() 95 | { 96 | return $this->baseUrl . $this->endpoint; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Sender/Bulk.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Sender; 11 | 12 | use anlutro\BulkSms\BulkSmsException; 13 | use anlutro\BulkSms\Laravel\BulkSmsService; 14 | use anlutro\BulkSms\Message; 15 | use anlutro\cURL\Response; 16 | 17 | /** 18 | * Class for sending messages in bulk. 19 | */ 20 | class Bulk extends AbstractSender 21 | { 22 | /** 23 | * The endpoint the call should go to. 24 | * 25 | * @var string 26 | */ 27 | protected $endpoint = '/eapi/submission/send_batch/1/1.0'; 28 | 29 | /** 30 | * Message container 31 | * 32 | * @var array 33 | */ 34 | protected $messages; 35 | 36 | /** 37 | * Add a message to the batch. 38 | * 39 | * @param Message $message 40 | */ 41 | public function addMessage(Message $message) 42 | { 43 | $this->messages[] = $message; 44 | } 45 | 46 | /** 47 | * Send the queued messages. 48 | * 49 | * @param bool $testmode Testmode to use 50 | * 51 | * @return mixed 52 | */ 53 | public function send($testmode = false) 54 | { 55 | if (empty($this->messages)) { 56 | return false; 57 | } 58 | 59 | $data = array_replace($this->params, [ 60 | 'username' => $this->username, 61 | 'password' => $this->password, 62 | 'batch_data' => $this->generateCSV(), 63 | ]); 64 | 65 | // add test params if required 66 | if ($testmode) { 67 | if ($testmode == BulkSmsService::TEST_ALWAYS_SUCCEED) { 68 | $data['test_always_succeed'] = 1; 69 | } elseif ($testmode == BulkSmsService::TEST_ALWAYS_FAIL) { 70 | $data['test_always_fail'] = 1; 71 | } 72 | } 73 | 74 | return $this->curl->post($this->getUrl(), $data); 75 | } 76 | 77 | /** 78 | * Generate the CSV to send. 79 | * 80 | * @return string 81 | */ 82 | protected function generateCSV() 83 | { 84 | $str = "msisdn,message"; 85 | 86 | foreach ($this->messages as $message) { 87 | $str .= "\n"; 88 | $recipient = $message->getRecipient(); 89 | $message = $message->getMessage(); 90 | $str .= '"' . $recipient . '","' . $message . '"'; 91 | } 92 | 93 | return $str; 94 | } 95 | 96 | /** 97 | * Extract response from Sender - depends on sender 98 | * 99 | * @param Response $response 100 | * 101 | * @return array('status_code', 'status_description', 'batch_id') 102 | * @throws BulkSmsException 103 | */ 104 | public function extractResponse(Response $response) 105 | { 106 | $expected = array('status_code', 'status_description', 'batch_id'); 107 | $parts = explode('|', $response->body); 108 | $it = new \ArrayIterator($parts); 109 | if (count($expected) != $it->count()) { 110 | throw new BulkSmsException( 111 | "Count of BulkSMS response does not match expectations!. Return: " . $response->body 112 | ); 113 | } 114 | 115 | $toreturn = []; 116 | foreach ($expected as $item) { 117 | $toreturn[$item] = $it->current(); 118 | $it->next(); 119 | } 120 | 121 | return $toreturn; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Sender/Single.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Sender; 11 | 12 | use anlutro\BulkSms\BulkSmsException; 13 | use anlutro\BulkSms\Laravel\BulkSmsService; 14 | use anlutro\BulkSms\Message; 15 | use anlutro\cURL\Response; 16 | 17 | /** 18 | * Class for sending single messages. 19 | */ 20 | class Single extends AbstractSender 21 | { 22 | /** 23 | * The URL the call should go to. 24 | * 25 | * @var string 26 | */ 27 | protected $endpoint = '/eapi/submission/send_sms/2/2.0'; 28 | 29 | /** 30 | * The message to send. 31 | * 32 | * @var anlutro\BulkSms\Message 33 | */ 34 | protected $message; 35 | 36 | /** 37 | * Set the message. 38 | * 39 | * @param anlutro\BulkSms\Message $message 40 | */ 41 | public function setMessage(Message $message) 42 | { 43 | $this->message = $message; 44 | } 45 | 46 | /** 47 | * Send the message. 48 | * 49 | * @param bool $testmode Testmode to use 50 | * 51 | * @return mixed 52 | */ 53 | public function send($testmode = false) 54 | { 55 | $data = array_replace($this->params, [ 56 | 'username' => $this->username, 57 | 'password' => $this->password, 58 | 'message' => $this->message->getMessage(), 59 | 'msisdn' => $this->message->getRecipient(), 60 | ]); 61 | 62 | $concat = $this->message->getConcatParts(); 63 | 64 | if ($concat > 1) { 65 | $data['allow_concat_text_sms'] = 1; 66 | $data['concat_text_sms_max_parts'] = $concat; 67 | } 68 | 69 | // add test params if required 70 | if ($testmode) { 71 | if ($testmode == BulkSmsService::TEST_ALWAYS_SUCCEED) { 72 | $data['test_always_succeed'] = 1; 73 | } elseif ($testmode == BulkSmsService::TEST_ALWAYS_FAIL) { 74 | $data['test_always_fail'] = 1; 75 | } 76 | } 77 | 78 | return $this->curl->post($this->getUrl(), $data); 79 | } 80 | 81 | /** 82 | * Extract response from Sender - depends on sender 83 | * 84 | * @param Response $response 85 | * 86 | * @return array('status_code', 'status_description', 'batch_id') 87 | * @throws BulkSmsException 88 | */ 89 | public function extractResponse(Response $response) 90 | { 91 | $expected = array('status_code', 'status_description', 'batch_id'); 92 | $parts = explode('|', $response->body); 93 | $it = new \ArrayIterator($parts); 94 | if (count($expected) != $it->count()) { 95 | throw new BulkSmsException( 96 | "Count of BulkSMS response does not match expectations!. Return: " . $response->body 97 | ); 98 | } 99 | 100 | $toreturn = []; 101 | foreach ($expected as $item) { 102 | $toreturn[$item] = $it->current(); 103 | $it->next(); 104 | } 105 | 106 | return $toreturn; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Sender/Status.php: -------------------------------------------------------------------------------- 1 | 6 | * @license http://opensource.org/licenses/MIT 7 | * @package anlutro/bulk-sms 8 | */ 9 | 10 | namespace anlutro\BulkSms\Sender; 11 | 12 | use anlutro\BulkSms\BulkSmsException; 13 | use anlutro\cURL\Response; 14 | 15 | /** 16 | * Class for getting the message status 17 | */ 18 | class Status extends AbstractSender 19 | { 20 | /** 21 | * The URL the call should go to. 22 | * 23 | * @var string 24 | */ 25 | protected $endpoint = '/eapi/status_reports/get_report/2/2.0'; 26 | 27 | /** 28 | * Get status for single batch id 29 | * 30 | * @param string $batchid 31 | * 32 | * @return \anlutro\cURL\Response|void 33 | */ 34 | public function getStatusForBatchId($batchid) 35 | { 36 | return $this->send($batchid); 37 | } 38 | 39 | /** 40 | * Send the status query 41 | * 42 | * @param $batchid 43 | * 44 | * @return \anlutro\cURL\Response|void 45 | */ 46 | public function send($batchid) 47 | { 48 | if (empty($batchid)) { 49 | throw new \InvalidArgumentException("Batch Id must not be empty"); 50 | } 51 | 52 | $data = [ 53 | 'username' => $this->username, 54 | 'password' => $this->password, 55 | 'batch_id' => $batchid, 56 | ]; 57 | 58 | return $this->curl->get($this->getUrl(), $data); 59 | } 60 | 61 | /** 62 | * Extract response from Sender - depends on sender 63 | * 64 | * @param Response $response 65 | * 66 | * @return array('msisdn', 'status_code') 67 | * @throws BulkSmsException 68 | */ 69 | public function extractResponse(Response $response) 70 | { 71 | // dump the first 2 lines indicated by the string "0|Returns to follow\n\n" 72 | $cleaned = substr($response->body, strlen("0|Returns to follow\n\n"), strlen($response->body)); 73 | $statusitems = explode("\n", $cleaned); 74 | 75 | $siit = new \ArrayIterator(array_filter($statusitems)); 76 | $toreturn = []; 77 | foreach ($siit as $item) { 78 | $expected = array('msisdn', 'status_code'); 79 | $parts = explode('|', $item); 80 | $it = new \ArrayIterator($parts); 81 | if (count($expected) != $it->count()) { 82 | throw new BulkSmsException( 83 | "Count of BulkSMS response does not match expectations!. Return: " . $response->body 84 | ); 85 | } 86 | 87 | $status = []; 88 | foreach ($expected as $statusitem) { 89 | $status[ $statusitem ] = $it->current(); 90 | $it->next(); 91 | 92 | } 93 | $toreturn[ ] = $status; 94 | } 95 | 96 | return $toreturn; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/MessageConcatTest.php: -------------------------------------------------------------------------------- 1 | msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(1)); 11 | $this->assertMsgConcat(1); 12 | 13 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(140)); 14 | $this->assertMsgConcat(1); 15 | 16 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(141)); 17 | $this->assertMsgConcat(2); 18 | } 19 | 20 | protected function generateStrlen($len) 21 | { 22 | $str = ''; 23 | 24 | for ($i = 0; $i < $len; $i++) { 25 | $str .= 'x'; 26 | } 27 | 28 | return $str; 29 | } 30 | 31 | protected function assertMsgConcat($concat) 32 | { 33 | $this->assertEquals($concat, $this->msg->getConcatParts()); 34 | } 35 | 36 | public function testDoubleMessageConcat() 37 | { 38 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(161)); 39 | $this->assertMsgConcat(2); 40 | 41 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(280)); 42 | $this->assertMsgConcat(2); 43 | 44 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(281)); 45 | $this->assertMsgConcat(3); 46 | } 47 | 48 | public function testTripleMessageConcat() 49 | { 50 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(321)); 51 | $this->assertMsgConcat(3); 52 | 53 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(420)); 54 | $this->assertMsgConcat(3); 55 | 56 | $this->msg = new \anlutro\BulkSms\Message(1111111111, $this->generateStrlen(421)); 57 | $this->assertMsgConcat(4); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/ParseRecipientTest.php: -------------------------------------------------------------------------------- 1 | message = new \anlutro\BulkSms\Message("4712345678", "text"); 11 | $this->assertRecipientEquals('4712345678'); 12 | } 13 | 14 | protected function assertRecipientEquals($expected) 15 | { 16 | $this->assertEquals($expected, $this->message->getRecipient()); 17 | } 18 | 19 | public function testParseWithCountryCodeAndPlus() 20 | { 21 | $this->message = new \anlutro\BulkSms\Message('+4712345678', "text"); 22 | $this->assertRecipientEquals('4712345678'); 23 | } 24 | 25 | public function testParseWithCountryCodeAndSpace() 26 | { 27 | $this->message = new \anlutro\BulkSms\Message('47 12345678', "text"); 28 | $this->assertRecipientEquals('4712345678'); 29 | } 30 | 31 | public function testParseWithCountryCodeAndPlusSpace() 32 | { 33 | $this->message = new \anlutro\BulkSms\Message('+47 12345678', "text"); 34 | $this->assertRecipientEquals('4712345678'); 35 | } 36 | 37 | /** 38 | * @expectedException InvalidArgumentException 39 | */ 40 | public function testParseWithoutCountryCode() 41 | { 42 | $this->message = new \anlutro\BulkSms\Message('12345678', "text"); 43 | $this->assertRecipientEquals('4712345678'); 44 | } 45 | 46 | public function testParseIntNumber() 47 | { 48 | $this->message = new \anlutro\BulkSms\Message(4712345678, "text"); 49 | $this->assertRecipientEquals('4712345678'); 50 | } 51 | 52 | /** 53 | * @expectedException InvalidArgumentException 54 | */ 55 | public function testParseTooShortNumber() 56 | { 57 | $this->message = new \anlutro\BulkSms\Message(1234567, "text"); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/Sender/BulkSmsServiceGetStatusTest.php: -------------------------------------------------------------------------------- 1 | 'foo', 15 | 'password' => 'bar', 16 | 'batch_id' => '123445566' 17 | ); 18 | $mockResponse = m::mock('anlutro\cURL\Response'); 19 | $mockResponse->statusCode = 200; 20 | $mockResponse->body = "0|Returns to follow\n\n"; 21 | $mockResponse->body .= "1212121|11\n"; 22 | $curl = $this->mockCurl(); 23 | $curl->shouldReceive('get')->once()->with( 24 | 'http://bulksms.vsms.net:5567/eapi/status_reports/get_report/2/2.0', 25 | $expectedGetData 26 | )->andReturn($mockResponse); 27 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 28 | $this->assertEquals( 29 | array(array('msisdn' => '1212121', 'status_code' => '11')), 30 | $bsms->getStatusForBatchId('123445566') 31 | ); 32 | } 33 | 34 | public function mockCurl() 35 | { 36 | return m::mock('anlutro\cURL\cURL'); 37 | } 38 | 39 | public function makeService($username, $password, $baseurl, $curl = null) 40 | { 41 | return new anlutro\BulkSms\BulkSmsService($username, $password, $baseurl, $curl); 42 | } 43 | 44 | public function testMultipleResponseSuccess() 45 | { 46 | $expectedGetData = array( 47 | 'username' => 'foo', 48 | 'password' => 'bar', 49 | 'batch_id' => '123445566' 50 | ); 51 | $mockResponse = m::mock('anlutro\cURL\Response'); 52 | $mockResponse->statusCode = 200; 53 | $mockResponse->body = "0|Returns to follow\n\n"; 54 | $mockResponse->body .= "1212121|11\n"; 55 | $mockResponse->body .= "1212122|12\n"; 56 | $curl = $this->mockCurl(); 57 | $curl->shouldReceive('get')->once()->with( 58 | 'http://bulksms.vsms.net:5567/eapi/status_reports/get_report/2/2.0', 59 | $expectedGetData 60 | )->andReturn($mockResponse); 61 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 62 | $this->assertEquals( 63 | array( 64 | array('msisdn' => '1212121', 'status_code' => '11'), 65 | array('msisdn' => '1212122', 'status_code' => '12') 66 | ), 67 | $bsms->getStatusForBatchId('123445566') 68 | ); 69 | } 70 | 71 | public function testNoResponseSuccess() 72 | { 73 | $expectedGetData = array( 74 | 'username' => 'foo', 75 | 'password' => 'bar', 76 | 'batch_id' => '123445566' 77 | ); 78 | $mockResponse = m::mock('anlutro\cURL\Response'); 79 | $mockResponse->statusCode = 200; 80 | $mockResponse->body = "0|Returns to follow\n\n"; 81 | $mockResponse->body .= "\n"; 82 | $curl = $this->mockCurl(); 83 | $curl->shouldReceive('get')->once()->with( 84 | 'http://bulksms.vsms.net:5567/eapi/status_reports/get_report/2/2.0', 85 | $expectedGetData 86 | )->andReturn($mockResponse); 87 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 88 | $this->assertEquals(array(), $bsms->getStatusForBatchId('123445566')); 89 | } 90 | 91 | /** 92 | * @expectedException anlutro\BulkSms\BulkSmsException 93 | */ 94 | public function testSendSingleHttpFail() 95 | { 96 | $expectedGetData = array( 97 | 'username' => 'foo', 98 | 'password' => 'bar', 99 | 'batch_id' => '123445566' 100 | ); 101 | $mockResponse = m::mock('anlutro\cURL\Response'); 102 | $mockResponse->code = '500'; 103 | $mockResponse->body = "0|Returns to follow\n\n"; 104 | $mockResponse->body .= "1212121|11\n"; 105 | $curl = $this->mockCurl(); 106 | $curl->shouldReceive('get')->once()->with( 107 | 'http://bulksms.vsms.net:5567/eapi/status_reports/get_report/2/2.0', 108 | $expectedGetData 109 | )->andReturn($mockResponse); 110 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 111 | $bsms->getStatusForBatchId('123445566'); 112 | } 113 | 114 | /** 115 | * @expectedException anlutro\BulkSms\BulkSmsException 116 | */ 117 | public function testSendSingleApiError() 118 | { 119 | $expectedGetData = array( 120 | 'username' => 'foo', 121 | 'password' => 'bar', 122 | 'batch_id' => '123445566' 123 | ); 124 | $mockResponse = m::mock('anlutro\cURL\Response'); 125 | $mockResponse->statusCode = 200; 126 | $mockResponse->body = "23|invalid credentials (username was: XXXXXXX)|\n"; 127 | $curl = $this->mockCurl(); 128 | $curl->shouldReceive('get')->once()->with( 129 | 'http://bulksms.vsms.net:5567/eapi/status_reports/get_report/2/2.0', 130 | $expectedGetData 131 | )->andReturn($mockResponse); 132 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 133 | $this->assertTrue($bsms->getStatusForBatchId('123445566')); 134 | } 135 | 136 | public function testSendSingleSuccessCustomURL() 137 | { 138 | $expectedGetData = array( 139 | 'username' => 'foo', 140 | 'password' => 'bar', 141 | 'batch_id' => '123445566' 142 | ); 143 | $mockResponse = m::mock('anlutro\cURL\Response'); 144 | $mockResponse->statusCode = 200; 145 | $mockResponse->body = "0|Returns to follow\n\n"; 146 | $mockResponse->body .= "1212121|11\n"; 147 | $curl = $this->mockCurl(); 148 | $curl->shouldReceive('get')->once()->with( 149 | 'http://bulksms.de/eapi/status_reports/get_report/2/2.0', 150 | $expectedGetData 151 | )->andReturn($mockResponse); 152 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.de', $curl); 153 | $this->assertEquals( 154 | array(array('msisdn' => '1212121', 'status_code' => '11')), 155 | $bsms->getStatusForBatchId('123445566') 156 | ); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /tests/Sender/BulkSmsServiceSendBatchMessageTest.php: -------------------------------------------------------------------------------- 1 | mockCurl(); 18 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 19 | $this->assertEquals( 20 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 21 | $bsms->sendBulkMessages(array()) 22 | ); 23 | } 24 | 25 | public function mockCurl() 26 | { 27 | return m::mock('anlutro\cURL\cURL'); 28 | } 29 | 30 | public function makeService($username, $password, $baseurl, $curl = null) 31 | { 32 | return new anlutro\BulkSms\BulkSmsService($username, $password, $baseurl, $curl); 33 | } 34 | 35 | /** 36 | * @expectedException Respect\Validation\Exceptions\InstanceException 37 | * @expectedExceptionMessage must be an instance of "anlutro\\BulkSms\\Message" 38 | */ 39 | public function testSendWrongMessageClassSuccess() 40 | { 41 | $curl = $this->mockCurl(); 42 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 43 | $this->assertEquals( 44 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 45 | $bsms->sendBulkMessages(array(m::mock('anlutro\cURL\Response'))) 46 | ); 47 | } 48 | 49 | public function testSendSingleMessageSuccess() 50 | { 51 | $expectedPostData = array( 52 | 'username' => 'foo', 53 | 'password' => 'bar', 54 | 'batch_data' => "msisdn,message\n\"4917610908093\",\"TestText\"", 55 | ); 56 | $mockResponse = m::mock('anlutro\cURL\Response'); 57 | $mockResponse->statusCode = 200; 58 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 59 | $curl = $this->mockCurl(); 60 | $curl->shouldReceive('post')->once()->with( 61 | "http://bulksms.vsms.net:5567/eapi/submission/send_batch/1/1.0", 62 | $expectedPostData 63 | )->andReturn($mockResponse); 64 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 65 | $message = new \anlutro\BulkSms\Message("4917610908093", "TestText"); 66 | $this->assertEquals( 67 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 68 | $bsms->sendBulkMessages(array($message)) 69 | ); 70 | } 71 | 72 | public function testSendMultipleMessageSuccess() 73 | { 74 | $expectedPostData = array( 75 | 'username' => 'foo', 76 | 'password' => 'bar', 77 | 'batch_data' => "msisdn,message\n\"4917610908093\",\"TestText\"\n\"4917610908094\",\"TestText2\"", 78 | ); 79 | $mockResponse = m::mock('anlutro\cURL\Response'); 80 | $mockResponse->statusCode = 200; 81 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 82 | $curl = $this->mockCurl(); 83 | $curl->shouldReceive('post')->once()->with( 84 | "http://bulksms.vsms.net:5567/eapi/submission/send_batch/1/1.0", 85 | $expectedPostData 86 | )->andReturn($mockResponse); 87 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 88 | $message1 = new \anlutro\BulkSms\Message("4917610908093", "TestText"); 89 | $message2 = new \anlutro\BulkSms\Message("4917610908094", "TestText2"); 90 | $this->assertEquals( 91 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 92 | $bsms->sendBulkMessages(array($message1, $message2)) 93 | ); 94 | } 95 | 96 | public function testExtraParamsAreAppended() 97 | { 98 | $expectedPostData = array( 99 | 'username' => 'foo', 100 | 'password' => 'bar', 101 | 'batch_data' => "msisdn,message\n\"4917610908093\",\"TestText\"\n\"4917610908094\",\"TestText2\"", 102 | 'routing_group' => 1, 103 | ); 104 | $mockResponse = m::mock('anlutro\cURL\Response'); 105 | $mockResponse->statusCode = 200; 106 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 107 | $curl = $this->mockCurl(); 108 | $curl->shouldReceive('post')->once()->with( 109 | "http://bulksms.vsms.net:5567/eapi/submission/send_batch/1/1.0", 110 | $expectedPostData 111 | )->andReturn($mockResponse); 112 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 113 | $message1 = new \anlutro\BulkSms\Message("4917610908093", "TestText"); 114 | $message2 = new \anlutro\BulkSms\Message("4917610908094", "TestText2"); 115 | $this->assertEquals( 116 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 117 | $bsms->sendBulkMessages(array($message1, $message2), array('routing_group' => 1)) 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/Sender/BulkSmsServiceSendSingleMessageTest.php: -------------------------------------------------------------------------------- 1 | 'foo', 15 | 'password' => 'bar', 16 | 'message' => 'hello', 17 | 'msisdn' => '4712345678', 18 | ); 19 | $mockResponse = m::mock('anlutro\cURL\Response'); 20 | $mockResponse->statusCode = 200; 21 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 22 | $curl = $this->mockCurl(); 23 | $curl->shouldReceive('post')->once()->with( 24 | 'http://bulksms.vsms.net:5567/eapi/submission/send_sms/2/2.0', 25 | $expectedPostData 26 | )->andReturn($mockResponse); 27 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 28 | 29 | $this->assertEquals( 30 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 31 | $bsms->sendMessage('4712345678', 'hello') 32 | ); 33 | } 34 | 35 | public function mockCurl() 36 | { 37 | return m::mock('anlutro\cURL\cURL'); 38 | } 39 | 40 | public function makeService($username, $password, $baseurl, $curl = null) 41 | { 42 | return new anlutro\BulkSms\BulkSmsService($username, $password, $baseurl, $curl); 43 | } 44 | 45 | /** 46 | * @expectedException anlutro\BulkSms\BulkSmsException 47 | */ 48 | public function testSendSingleHttpFail() 49 | { 50 | $expectedPostData = array( 51 | 'username' => 'foo', 52 | 'password' => 'bar', 53 | 'message' => 'hello', 54 | 'msisdn' => '4712345678', 55 | ); 56 | $mockResponse = m::mock('anlutro\cURL\Response'); 57 | $mockResponse->code = '500'; 58 | $curl = $this->mockCurl(); 59 | $curl->shouldReceive('post')->once()->andReturn($mockResponse); 60 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 61 | 62 | $bsms->sendMessage('4712345678', 'hello'); 63 | } 64 | 65 | /** 66 | * @expectedException anlutro\BulkSms\BulkSmsException 67 | */ 68 | public function testSendSingleApiError() 69 | { 70 | $expectedPostData = array( 71 | 'username' => 'foo', 72 | 'password' => 'bar', 73 | 'message' => 'hello', 74 | 'msisdn' => '4712345678', 75 | ); 76 | $mockResponse = m::mock('anlutro\cURL\Response'); 77 | $mockResponse->statusCode = 200; 78 | $mockResponse->body = '99|ERROR|12345678'; 79 | $curl = $this->mockCurl(); 80 | $curl->shouldReceive('post')->once()->andReturn($mockResponse); 81 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 82 | 83 | $bsms->sendMessage('23712345678', 'hello'); 84 | } 85 | 86 | public function testSendSingleConcat() 87 | { 88 | $message = str_repeat('x', 200); 89 | $expectedPostData = array( 90 | 'username' => 'foo', 91 | 'password' => 'bar', 92 | 'message' => $message, 93 | 'msisdn' => '4712345678', 94 | 'allow_concat_text_sms' => 1, 95 | 'concat_text_sms_max_parts' => 2, 96 | ); 97 | $mockResponse = m::mock('anlutro\cURL\Response'); 98 | $mockResponse->statusCode = 200; 99 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 100 | $curl = $this->mockCurl(); 101 | $curl->shouldReceive('post')->once()->with( 102 | 'http://bulksms.vsms.net:5567/eapi/submission/send_sms/2/2.0', 103 | $expectedPostData 104 | )->andReturn($mockResponse); 105 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.vsms.net:5567', $curl); 106 | 107 | $this->assertEquals( 108 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 109 | $bsms->sendMessage('4712345678', $message) 110 | ); 111 | } 112 | 113 | public function testSendSingleConcatCustomURL() 114 | { 115 | $message = str_repeat('x', 200); 116 | $expectedPostData = array( 117 | 'username' => 'foo', 118 | 'password' => 'bar', 119 | 'message' => $message, 120 | 'msisdn' => '4712345678', 121 | 'allow_concat_text_sms' => 1, 122 | 'concat_text_sms_max_parts' => 2, 123 | ); 124 | $mockResponse = m::mock('anlutro\cURL\Response'); 125 | $mockResponse->statusCode = 200; 126 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 127 | $curl = $this->mockCurl(); 128 | $curl->shouldReceive('post')->once()->with( 129 | 'http://bulksms.de/eapi/submission/send_sms/2/2.0', 130 | $expectedPostData 131 | )->andReturn($mockResponse); 132 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.de', $curl); 133 | $this->assertEquals( 134 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 135 | $bsms->sendMessage('4712345678', $message) 136 | ); 137 | } 138 | 139 | public function testExtraParamsAreAppended() 140 | { 141 | $message = str_repeat('x', 200); 142 | $expectedPostData = array( 143 | 'username' => 'foo', 144 | 'password' => 'bar', 145 | 'message' => $message, 146 | 'msisdn' => '4712345678', 147 | 'allow_concat_text_sms' => 1, 148 | 'concat_text_sms_max_parts' => 2, 149 | 'routing_group' => 1, 150 | ); 151 | $mockResponse = m::mock('anlutro\cURL\Response'); 152 | $mockResponse->statusCode = 200; 153 | $mockResponse->body = '0|IN_PROGRESS|4712345678'; 154 | $curl = $this->mockCurl(); 155 | $curl->shouldReceive('post')->once()->with( 156 | 'http://bulksms.de/eapi/submission/send_sms/2/2.0', 157 | $expectedPostData 158 | )->andReturn($mockResponse); 159 | $bsms = $this->makeService('foo', 'bar', 'http://bulksms.de', $curl); 160 | $this->assertEquals( 161 | array('status_code' => 0, 'status_description' => "IN_PROGRESS", 'batch_id' => 4712345678), 162 | $bsms->sendMessage('4712345678', $message, array('routing_group' => 1)) 163 | ); 164 | } 165 | } 166 | --------------------------------------------------------------------------------