Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clickatell #21

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
57bb1f7
Clickatell API calls as GET request
felixmaier1989 Apr 23, 2015
3a2d17a
Merge branch 'smskaufen' into master-dev
felixmaier1989 Apr 23, 2015
48f3351
Fixed BC
felixmaier1989 Apr 23, 2015
9bfd193
Fixed BC
felixmaier1989 Apr 23, 2015
172aa6e
Merge branch 'clickatell' into master-dev
felixmaier1989 Apr 23, 2015
329f7f4
First draft for ClickatellGateway::parseResponse()
felixmaier1989 Apr 24, 2015
27d004a
Parsing Clickatell response
felixmaier1989 Apr 24, 2015
62e17f4
Clickatell: bulk sending in one API call
felixmaier1989 Apr 24, 2015
0d3832d
Clickatell: bulk sending in one API call, even for more than 100 addr…
felixmaier1989 Apr 24, 2015
18040db
Merge branch 'clickatell' into master-dev
felixmaier1989 Apr 24, 2015
0833735
Renamed composer package to be able to register package
felixmaier1989 Apr 24, 2015
8f880d3
Changed parsing of response string
felixmaier1989 May 6, 2015
66a5e80
Changed parsing of response string
felixmaier1989 May 6, 2015
64cea57
Autentication function
felixmaier1989 May 6, 2015
a8e75bb
Merge branch 'clickatell'
felixmaier1989 May 6, 2015
8719a2f
composer package name
felixmaier1989 May 11, 2015
ef1efea
Merge branch 'master' of https://github.com/xi-project/xi-sms into cl…
felixmaier1989 Jul 24, 2015
286d83f
[clickatell] fixes after merge with master
felixmaier1989 Jul 24, 2015
86fb5a7
[clickatell] Fixed deletion of SmsMessage::setTo()
felixmaier1989 Jul 24, 2015
b547f1f
[clickatell] Methods should not throw that many exceptions
felixmaier1989 Jul 24, 2015
6c433fa
[clickatell] Revert change of package name
felixmaier1989 Jul 24, 2015
d536d53
update to valid licence type in composer.json
beinbm Jan 29, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Short messaging for PHP 5.3",
"keywords": ["SMS"],
"homepage": "http://github.com/xi-project/xi-sms",
"license": "BSD",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Mikko Forsström",
Expand Down
114 changes: 104 additions & 10 deletions library/Xi/Sms/Gateway/ClickatellGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*
* For copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* This class implements Clickatell API
* @link https://www.clickatell.com/downloads/http/Clickatell_HTTP.pdf
*/

namespace Xi\Sms\Gateway;
Expand Down Expand Up @@ -45,20 +48,111 @@ public function __construct(
$this->endpoint = $endpoint;
}

/**
* Authentication
* @return array
* @return bool|string Success|Session ID
*/
public function authenticate()
{
$params = array(
'api_id' => $this->apiKey,
'user' => $this->user,
'password' => $this->password,
);

$response_string = $this->getClient()->get(
$this->endpoint . '/http/auth?'.http_build_query($params),
array()
);

$response = $this->parseResponse($response_string);
if ($response === false) {
return false;
}
if (!empty($response['ERR'])) {
return false;
}
if (empty($response['OK'])) {
return false;
}
return $response['OK'];
}

/**
* @see GatewayInterface::send
* @todo Implement a smarter method of sending (batch)
* @param SmsMessage $message
* @return bool Success
*/
public function send(SmsMessage $message)
{
$body = urlencode(utf8_decode($message->getBody()));
$from = urlencode($message->getFrom());

foreach ($message->getTo() as $to) {
$url = "{$this->endpoint}/http/sendmsg?api_id={$this->apiKey}&user={$this->user}" .
"&password={$this->password}&to={$to}&text={$body}&from={$from}";
$this->getClient()->post($url, array());
}
return true;
// Sending is limited to max 100 addressees
if (count($message->getTo()) > 100) {
foreach (array_chunk($message->getTo(), 100) as $tos) {
$message_alt = new SmsMessage(
$message->getBody(),
$message->getFrom(),
$tos
);
$this->send($message_alt);
}
return true;
}

$params = array(
'api_id' => $this->apiKey,
'user' => $this->user,
'password' => $this->password,
'to' => implode(',', $message->getTo()),
'text' => utf8_decode($message->getBody()),
'from' => $message->getFrom()
);

$response_string = $this->getClient()->get(
$this->endpoint . '/http/sendmsg?'.http_build_query($params),
array()
);
$response = $this->parseResponse($response_string);
if (!empty($response['ERR'])) {
return false;
}
if (empty($response['ID'])) {
return false;
}
return true;
}

/**
* Parses a Clickatell HTTP API response
* @param string $response
* @return array error messages, messages IDs, phone numbers...
* @return bool|array Success|Parsed API response
*/
public static function parseResponse($response) {
$return = array(
'id' => null,
'error' => null
);
if (preg_match_all('/((ERR|ID|OK): ([^\n]*))+/', $response, $matches)) {
for ($i = 0; $i < count($matches[0]); $i++) {
$phone_number = null;
if (preg_match('/(.*)( To: ([0-9]+))$/', $matches[3][$i], $ms)) {
$message = $ms[1];
$phone_number = $ms[3];
} else {
$message = $matches[3][$i];
}

$key = $matches[2][$i];
if ($phone_number) {
$return[$key][$phone_number] = $message;
} else {
$return[$key] = $message;
}
}
return $return;
} else {
return false;
}
}
}
224 changes: 218 additions & 6 deletions tests/Xi/Sms/Tests/Gateway/ClickatellGatewayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,210 @@

namespace Xi\Sms\Tests\Gateway;

use Xi\Sms\SmsMessage;
use Xi\Sms\SmsService;
use Xi\Sms\SmsException;
use Xi\Sms\Gateway\ClickatellGateway;
use Buzz\Message\Response;

class ClickatellGatewayTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function authenticateFail()
{
$gateway = new ClickatellGateway('lussavain', 'lussuta', 'tussia');

$browser = $this->getMockBuilder('Buzz\Browser')
->disableOriginalConstructor()
->getMock();

$gateway->setClient($browser);

$browser
->expects($this->once())
->method('get')
->with(
$this->callback(function($actual) {
$url = parse_url($actual);
parse_str($url['query'], $query);
return
$url['path'] === '/http/auth' &&
$query['api_id'] === 'lussavain' &&
$query['user'] === 'lussuta' &&
$query['password'] === 'tussia';
}),
array()
)
->will($this->returnValue(''));

$this->assertFalse($gateway->authenticate());
}

/**
* @test
*/
public function authenticateOk()
{
$gateway = new ClickatellGateway('lussavain', 'lussuta', 'tussia', 'http://api.dr-kobros.com');

$browser = $this->getMockBuilder('Buzz\Browser')
->disableOriginalConstructor()
->getMock();

$gateway->setClient($browser);

$browser
->expects($this->once())
->method('get')
->with(
$this->callback(function($actual) {
$url = parse_url($actual);
parse_str($url['query'], $query);
return
$url['path'] === '/http/auth' &&
$query['api_id'] === 'lussavain' &&
$query['user'] === 'lussuta' &&
$query['password'] === 'tussia';
}),
array()
)
->will($this->returnValue('OK: QWERTYUI12345678'));

$this->assertEquals('QWERTYUI12345678', $gateway->authenticate());
}

/**
* @test
*/
public function sendMultipleMoreThan100()
{
$gateway = new ClickatellGateway('lussavain', 'lussuta', 'tussia', 'http://api.dr-kobros.com');

$browser = $this->getMockBuilder('Buzz\Browser')
->disableOriginalConstructor()
->getMock();

$gateway->setClient($browser);

$addressees = array();
for ($i = 0; $i < 345; $i++) {
$addressees[] = rand();
}

$browser
->expects($this->exactly(4))
->method('get')
->with(
$this->callback(function($actual) {
$url = parse_url($actual);
parse_str($url['query'], $query);
return count(explode(',', $query['to'])) === 100 ||
count(explode(',', $query['to'])) === 45;
}),
$this->isType('array')
)
->will($this->returnValue("ID: QWERTYUI12345678 To: 358503028030\nID: 12345678QWERTYUI To: 49123456789"));

$message = new \Xi\Sms\SmsMessage(
'Pekkis tassa lussuttaa.',
'358503028030',
$addressees
);
$ret = $gateway->send($message);
}

/**
* @test
*/
public function sendMultiple()
{
$gateway = new ClickatellGateway('lussavain', 'lussuta', 'tussia', 'http://api.dr-kobros.com');

$browser = $this->getMockBuilder('Buzz\Browser')
->disableOriginalConstructor()
->getMock();

$gateway->setClient($browser);

$browser
->expects($this->once())
->method('get')
->with(
$this->callback(function($actual) {
$url = parse_url($actual);
parse_str($url['query'], $query);
return $query['to'] === '358503028030,49123456789';
}),
$this->isType('array')
)
->will($this->returnValue("ID: QWERTYUI12345678 To: 358503028030\nID: 12345678QWERTYUI To: 49123456789"));

$message = new \Xi\Sms\SmsMessage(
'Pekkis tassa lussuttaa.',
'358503028030',
array('358503028030', '49123456789')
);
$ret = $gateway->send($message);
}

/**
* @test
*/
public function parseResponseMassSendingError()
{
$response = ClickatellGateway::parseResponse("ERR: 114, Cannot route message To: 49123456789\nERR: 567, Bla bla bla To: 4987654321");
$this->assertEquals('114, Cannot route message', $response['ERR']['49123456789']);
$this->assertEquals('567, Bla bla bla', $response['ERR']['4987654321']);
}

/**
* @test
*/
public function parseResponseMassSendingId()
{
$response = ClickatellGateway::parseResponse("ID: CE07B3BFEFF35F4E2667B3A47116FDD2 To: 49123456789\nID: QWERTYUIO123456789ASDFGHJK To: 4987654321");
$this->assertEquals('CE07B3BFEFF35F4E2667B3A47116FDD2', $response['ID']['49123456789']);
$this->assertEquals('QWERTYUIO123456789ASDFGHJK', $response['ID']['4987654321']);
}

/**
* @test
*/
public function parseResponseErrorParse()
{
$response = ClickatellGateway::parseResponse('foo bar');
$this->assertFalse($response);
}

/**
* @test
*/
public function parseResponseOK()
{
$response = ClickatellGateway::parseResponse("OK: CE07B3BFEFF35F4E2667B3A47116FDD2");
$this->assertEquals('CE07B3BFEFF35F4E2667B3A47116FDD2', $response['OK']);
}

/**
* @test
*/
public function parseResponseId()
{
$response = ClickatellGateway::parseResponse('ID: CE07B3BFEFF35F4E2667B3A47116FDD2');
$this->assertEquals('CE07B3BFEFF35F4E2667B3A47116FDD2', $response['ID']);
}

/**
* @test
*/
public function parseResponseErrorApi()
{
$response = ClickatellGateway::parseResponse('ERR: 114, Cannot route message');
$this->assertEquals('114, Cannot route message', $response['ERR']);
}

/**
* @test
*/
Expand All @@ -21,20 +221,32 @@ public function sendsRequest()

$browser
->expects($this->once())
->method('post')
->method('get')
->with(
'http://api.dr-kobros.com/http/sendmsg?api_id=lussavain&user=lussuta&password=' .
'tussia&to=358503028030&text=Pekkis+tassa+lussuttaa.&from=358503028030',
$this->callback(function($actual) {
$url = parse_url($actual);
parse_str($url['query'], $query);
return
$url['scheme'] === 'http' &&
$url['host'] === 'api.dr-kobros.com' &&
$url['path'] === '/http/sendmsg' &&
$query['api_id'] === 'lussavain' &&
$query['user'] === 'lussuta' &&
$query['password'] === 'tussia' &&
$query['to'] === '358503028030' &&
urldecode($query['text']) === 'Pekkis tassa lussuttaa.' &&
$query['from'] === '358503028030';
}),
array()
);
)
->will($this->returnValue('ID: QWERTYUI12345678'));

$message = new \Xi\Sms\SmsMessage(
'Pekkis tassa lussuttaa.',
'358503028030',
'358503028030'
);

$ret = $gateway->send($message);
$this->assertTrue($ret);
$this->assertTrue($gateway->send($message));
}
}