❗ The library will be experimental until the first major release.
See the specification for more information about protocol.
composer require operation-hardcode/smpp-php
This library requires PHP 8.1 or later.
It is recommended to install the phpinnacle/ext-buffer extension to speed up the phpinnacle/buffer.
- BIND_RECEIVER
- BIND_TRANSMITTER
- BIND_TRANSCEIVER
- ALERT_NOTIFICATION
- CANCEL_SM
- DATA_SM
- DELIVER_SM
- ENQUIRE_LINK
- GENERIC_NACK
- OUTBIND
- QUERY_SM
- REPLACE_SM
- SUBMIT_SM
- UNBIND
- SUBMIT_MULTI
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use OperationHardcode\Smpp;
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Protocol\PDU;
use OperationHardcode\Smpp\Transport\ConnectionContext;
Amp\Loop::run(function (): \Generator {
$executor = Connector::connect()
->asReceiver(ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'));
try {
yield $executor->consume(function (PDU $pdu, Smpp\Interaction\SmppExecutor $executor): \Generator {
var_dump($pdu);
yield $executor->fin();
});
} catch (Smpp\Interaction\ConnectionWasNotEstablished) {
yield $executor->fin();
Amp\Loop::stop();
}
});
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Protocol\Command\SubmitSm;
use OperationHardcode\Smpp\Protocol\Destination;
use OperationHardcode\Smpp\Transport\ConnectionContext;
Amp\Loop::run(function (): \Generator {
$transmitter = Connector::connect()
->asTransmitter(ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'));
yield $transmitter->produce(new SubmitSm(new Destination('xxxx'), new Destination('xxxxx'), 'Hello, world'));
yield $transmitter->fin();
});
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use Amp\Log\ConsoleFormatter;
use Amp\Log\StreamHandler;
use Monolog\Logger;
use Monolog\Processor\MemoryPeakUsageProcessor;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\PsrLogMessageProcessor;
use OperationHardcode\Smpp;
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Protocol\PDU;
use OperationHardcode\Smpp\Transport\ConnectionContext;
use Psr\Log\LoggerInterface;
function stdoutLogger(string $loggerName): LoggerInterface
{
$handler = new StreamHandler(Amp\ByteStream\getStdout());
$handler->setFormatter(new ConsoleFormatter());
return new Logger($loggerName, [$handler], [new PsrLogMessageProcessor(), new MemoryUsageProcessor(), new MemoryPeakUsageProcessor()]);
}
Amp\Loop::run(function (): \Generator {
$transceiver = Connector::connect()->asTransceiver(
ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'),
stdoutLogger('transceiver'),
);
try {
yield $transceiver->consume(function (PDU $pdu, Smpp\Interaction\SmppExecutor $executor): \Generator {
if ($pdu instanceof Smpp\Protocol\Command\Replyable) {
yield $executor->produce($pdu->reply());
}
var_dump($pdu);
return new Amp\Success();
});
} catch (\Throwable $e) {
echo $e->getMessage() . \PHP_EOL;
Amp\Loop::stop();
}
});
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use Amp;
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Transport\ConnectionContext;
use OperationHardcode\Smpp;
Amp\Loop::run(function (): \Generator {
$logger = stdoutLogger('transceiver');
$transceiver = Connector::connect()
->asTransceiver(
ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'),
$logger
);
Amp\Loop::unreference(
Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator {
yield $transceiver->fin();
})
);
try {
yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator {
if ($pdu instanceof Smpp\Protocol\Command\Replyable) {
$reply = $pdu->reply();
yield $executor->produce($reply);
}
return new Amp\Success();
});
} catch (\Throwable $e) {
echo $e->getMessage() . \PHP_EOL;
Amp\Loop::stop();
}
});
If you need more options when working with library, you can write an extension. The library provides 4 hooks that are called by the executor at different times of their work:
- If you want to extend the behaviour on successful connection, implement the
OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionEstablishedExtension
interface. - If you want to extend the behaviour on disconnection, implement the
OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionClosedExtension
interface. - If you want to extend the behaviour on each
PDU
produced by executor, implement theOperationHardcode\Smpp\Interaction\Extensions\AfterPduProducedExtension
interface. - Or vice versa, if you want to extend the behaviour on each
PDU
consumed by executor, implement theOperationHardcode\Smpp\Interaction\Extensions\AfterPduConsumedExtension
interface.
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use Amp;
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Transport\ConnectionContext;
use OperationHardcode\Smpp;
use OperationHardcode\Smpp\Interaction\SmppExecutor;
use OperationHardcode\Smpp\Protocol\PDU;
use Psr\Log\LoggerInterface;
use OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionEstablishedExtension;
use OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionClosedExtension;
use OperationHardcode\Smpp\Interaction\Extensions\AfterPduConsumedExtension;
use OperationHardcode\Smpp\Interaction\Extensions\AfterPduProducedExtension;
final class Debug implements
AfterConnectionEstablishedExtension,
AfterConnectionClosedExtension,
AfterPduConsumedExtension,
AfterPduProducedExtension
{
public function __construct(private LoggerInterface $logger)
{
}
public function afterConnectionEstablished(SmppExecutor $smppExecutor): Amp\Promise
{
return Amp\call(function (): void {
$this->logger->debug('Connection was established.');
});
}
public function afterConnectionClosed(?\Throwable $e = null): Amp\Promise
{
return Amp\call(function () use ($e): void {
$this->logger->debug('Connection was closed.');
});
}
public function afterPduConsumed(PDU $pdu, SmppExecutor $smppExecutor): Amp\Promise
{
return Amp\call(function () use ($pdu): void {
$this->logger->debug('The pdu "{pdu}" was consumed.', [
'pdu' => get_class($pdu),
]);
});
}
public function afterPduProduced(PDU $pdu, SmppExecutor $smppExecutor): Amp\Promise
{
return Amp\call(function () use ($pdu): void {
$this->logger->debug('The pdu "{pdu}" was produced.', [
'pdu' => get_class($pdu),
]);
});
}
}
Amp\Loop::run(function (): \Generator {
$logger = stdoutLogger('transceiver');
$transceiver = Connector::connect()
->asTransceiver(
ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'),
$logger
)
->withExtensions([
new Debug($logger),
]);
Amp\Loop::unreference(
Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator {
yield $transceiver->fin();
})
);
try {
yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator {
if ($pdu instanceof Smpp\Protocol\Command\Replyable) {
$reply = $pdu->reply();
yield $executor->produce($reply);
}
return new Amp\Success();
});
} catch (\Throwable $e) {
echo $e->getMessage() . \PHP_EOL;
Amp\Loop::stop();
}
});
The library provides the Heartbeat
extension which periodically send the ENQUIRE_LINK
command, required by SMPP specification.
You can configure the interval and timeout within which you must receive a ENQUIRE_LINK_RESP
with command status ESME_ROK
.
<?php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
use Amp;
use OperationHardcode\Smpp\Interaction\Connector;
use OperationHardcode\Smpp\Transport\ConnectionContext;
use OperationHardcode\Smpp\Interaction\SmppExecutor;
use OperationHardcode\Smpp\Interaction\Heartbeat\Heartbeat;
use OperationHardcode\Smpp\Time;
Amp\Loop::run(function (): \Generator {
$logger = stdoutLogger('transceiver');
$transceiver = Connector::connect()
->asTransceiver(
ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'),
$logger
)
->withExtensions([
new Heartbeat(
Time::fromSeconds(10), // interval
Time::fromSeconds(2), // timeout
$logger,
),
]);
Amp\Loop::unreference(
Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator {
yield $transceiver->fin();
})
);
try {
yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator {
if ($pdu instanceof Smpp\Protocol\Command\Replyable) {
$reply = $pdu->reply();
yield $executor->produce($reply);
}
return new Amp\Success();
});
} catch (\Throwable $e) {
echo $e->getMessage() . \PHP_EOL;
Amp\Loop::stop();
}
});
$ composer test
The MIT License (MIT). See License File for more information.