GithubHelp home page GithubHelp logo

php8-smpp's Introduction

php8-smpp

SMPP Client (v 3.4) on PHP8

ATTENTION!

In development! Not production ready!


PHP SMPP (v3.4) client

Install:

composer require alexandr-mironov/php8-smpp

Example of wrapper (php>=7.0) for this Client. In this case we got ALPHANUMERIC sender value 'github_example':

<?php

declare(strict_types=1);

namespace app\components\Sms;

use Exception;
use smpp\{Address, Client as SmppClient, Smpp, transport\Socket};

class SmsBuilder
{
    /** @var string 11 chars limit */
    public const DEFAULT_SENDER = 'example';

    protected Socket $transport;

    protected SmppClient $smppClient;

    protected bool $debug = false;

    protected Address $from;

    protected Address $to;

    protected string $login;

    protected string $password;

    /**
     * SmsBuilder constructor.
     *
     * @param string $address SMSC IP
     * @param int $port SMSC port
     * @param string $login
     * @param string $password
     * @param int $timeout timeout of reading PDU in milliseconds
     * @param bool $debug - debug flag when true output additional info
     */
    public function __construct(
        string $address,
        int $port,
        string $login,
        string $password,
        int $timeout = 10000,
        bool $debug = false
    ) {
        $this->transport = new Socket([$address], $port);
        // Activate binary hex-output of server interaction
        $this->transport->debug = $debug;
        $this->transport->setRecvTimeout($timeout);
        $this->smppClient = new SmppClient($this->transport);

        $this->login = $login;
        $this->password = $password;

        $this->from = new Address(self::DEFAULT_SENDER, SMPP::TON_ALPHANUMERIC);
    }

    /**
     * @param string $sender
     * @param int $ton
     *
     * @return $this
     * @throws Exception
     */
    public function setSender(string $sender, int $ton): SmsBuilder
    {
        return $this->setAddress($sender, 'from', $ton);
    }

    /**
     * @param string $address
     * @param string $type
     * @param int $ton
     * @param int $npi
     *
     * @return $this
     * @throws Exception
     */
    protected function setAddress(
        string $address,
        string $type,
        int $ton = SMPP::TON_UNKNOWN,
        int $npi = SMPP::NPI_UNKNOWN
    ): SmsBuilder {
        // some example of data preparation
        if ($ton === SMPP::TON_INTERNATIONAL) {
            $npi = SMPP::NPI_E164;
        }
        $this->$type = new Address($address, $ton, $npi);

        return $this;
    }

    /**
     * @param string $address
     * @param int $ton
     *
     * @return $this
     * @throws Exception
     */
    public function setRecipient(string $address, int $ton): SmsBuilder
    {
        return $this->setAddress($address, 'to', $ton);
    }

    /**
     * @param string $message
     *
     * @throws Exception
     */
    public function sendMessage(string $message): void
    {
        $this->transport->open();
        $this->smppClient->bindTransceiver($this->login, $this->password);
        // strongly recommend use SMPP::DATA_CODING_UCS2 as default encoding in project to prevent problems with non latin symbols
        $this->smppClient->sendSMS($this->from, $this->to, $message, null, SMPP::DATA_CODING_UCS2);
        $this->smppClient->close();
    }
}

This wrapper implement some kind of Builder pattern, usage example:

<?php
// replace address, port, login and password to your values
(new your_namespace\SmsBuilder('192.168.1.1', '2776', 'your_login', 'your_password', 10000))
    ->setRecipient('79000000000', \smpp\SMPP::TON_INTERNATIONAL) //msisdn of recipient
    ->sendMessage('Тестовое сообщение на русском and @noth3r$Ymb0ls');

Original description

PHP-based SMPP client lib

This is a simplified SMPP client lib for sending or receiving smses through SMPP v3.4.

In addition to the client, this lib also contains an encoder for converting UTF-8 text to the GSM 03.38 encoding, and a socket wrapper. The socket wrapper provides connection pool, IPv6 and timeout monitoring features on top of PHP's socket extension.

This lib has changed significantly from it's first release, which required namespaces and included some worker components. You'll find that release at 1.0.1-namespaced

This lib requires the sockets PHP-extension, and is not supported on Windows. A windows-compatible version is also available.

Connection pools

You can specify a list of connections to have the SocketTransport attempt each one in succession or randomly. Also if you give it a hostname with multiple A/AAAA-records it will try each one. If you want to monitor the DNS lookups, set defaultDebug to true before constructing the transport.

The (configurable) send timeout governs how long it will wait for each server to timeout. It can take a long time to try a long list of servers, depending on the timeout. You can change the timeout both before and after the connection attempts are made.

The transport supports IPv6 and will prefer IPv6 addresses over IPv4 when available. You can modify this feature by setting forceIpv6 or forceIpv4 to force it to only use IPv6 or IPv4.

In addition to the DNS lookups, it will also look for local IPv4 addresses using gethostbyname(), so "localhost" works for IPv4. For IPv6 localhost specify "::1".

Implementation notes

  • You can't connect as a transceiver, otherwise supported by SMPP v.3.4
  • The SUBMIT_MULTI operation of SMPP, which sends a SMS to a list of recipients, is not supported atm. You can easily add it though.
  • The sockets will return false if the timeout is reached on read() (but not readAll or write). You can use this feature to implement an enquire_link policy. If you need to send enquire_link for every 30 seconds of inactivity, set a timeout of 30 seconds, and send the enquire_link command after readSMS() returns false.
  • The examples above assume that the SMSC default datacoding is GSM 03.38.
  • Remember to activate registered delivery if you want delivery receipts (set to SMPP::REG_DELIVERY_SMSC_BOTH / 0x01).
  • Both the SmppClient and transport components support a debug callback, which defaults to error_log . Use this to redirect debug information.

F.A.Q.

Can I use this to send messages from my website?
Not on it's own, no. After PHP processes the request on a website, it closes all connections. Most SMPP providers do not want you to open and close connections, you should keep them alive and send enquire_link commands periodically. Which means you probably need to get some kind of long running process, ie. using the process control functions, and implement a form of queue system which you can push to from the website. This requires shell level access to the server, and knowledge of unix processes.

How do I receive delivery receipts or SMS'es?
To receive a delivery receipt or a SMS you must connect a receiver in addition to the transmitter. This receiver must wait for a delivery receipt to arrive, which means you probably need to use the process control functions.

We do have an open source implementation at php-smpp-worker you can look at for inspiration, but we cannot help you with making your own. Perhaps you should look into if your SMSC provider can give you a HTTP based API or using turnkey software such as kannel, this project provides the protocol implementation only and a basic socket wrapper.

I can't send more than 160 chars
There are three built-in methods to send Concatenated SMS (csms); CSMS_16BIT_TAGS, CSMS_PAYLOAD, CSMS_8BIT_UDH. CSMS_16BIT_TAGS is the default, if it don't work try another.

Is this lib compatible with PHP 5.2.x ?
It's tested on PHP 5.3, but is known to work with 5.2 as well.

Can it run on windows?
It requires the sockets extension, which is available on windows, but is incomplete. Use the windows-compatible version instead, which uses fsockopen and stream functions.

Why am I not seeing any debug output?
Remember to implement a debug callback for SocketTransport and SmppClient to use. Otherwise they default to error_log which may or may not print to screen.

Why do I get 'res_nsend() failed' or 'Could not connect to any of the specified hosts' errors?
Your provider's DNS server probably has an issue with IPv6 addresses (AAAA records). Try to set SocketTransport::$forceIpv4=true;. You can also try specifying an IP-address (or a list of IPs) instead. Setting SocketTransport:$defaultDebug=true; before constructing the transport is also useful in resolving connection issues.

I tried forcing IPv4 and/or specifying an IP-address, but I'm still getting 'Could not connect to any of the specified hosts'?
It would be a firewall issue that's preventing your connection, or something else entirely. Make sure debug output is enabled and displayed. If you see something like 'Socket connect to 1.2.3.4:2775 failed; Operation timed out' this means a connection could not be etablished. If this isn't a firewall issue, you might try increasing the connect timeout. The sendTimeout also specifies the connect timeout, call $transport->setSendTimeout(10000); to set a 10-second timeout.

Why do I get 'Failed to read reply to command: 0x4', 'Message Length is invalid' or 'Error in optional part' errors?
Most likely your SMPP provider doesn't support NULL-terminating the message field. The specs aren't clear on this issue, so there is a toggle. Set SmppClient::$sms_null_terminate_octetstrings = false; and try again.

What does 'Bind Failed' mean?
It typically means your SMPP provider rejected your login credentials, ie. your username or password.

Can I test the client library without a SMPP server?
Many service providers can give you a demo account, but you can also use the logica opensmpp simulator (java) or smsforum client test tool (linux binary). In addition to a number of real-life SMPP servers this library is tested against these simulators.

I have an issue that not mentioned here, what do I do?
Please obtain full debug information, and open an issue here on github. Make sure not to include the Send PDU hex-codes of the BindTransmitter call, since it will contain your username and password. Other hex-output is fine, and greatly appeciated. Any PHP Warnings or Notices could also be important. Please include information about what SMPP server you are connecting to, and any specifics.

php8-smpp's People

Contributors

alexandr-mironov avatar oc666 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

php8-smpp's Issues

Error Log : ignore

production.ERROR:` Failed to read reply to command: 0x6 {"exception":"[object] (smpp\exceptions\SmppException(code: 0): Failed to read reply to command: 0x6 at /home/public_html/vendor/alexandr-mironov/php8-smpp/src/Client.php:948)"}

How to safely ignore this error logging ?

Error "Failed to read reply to command: 0x4"

Hi,

Thank you for your fantastic work with this library! I started using PHP8 with php8-smpp and received the error "Failed to read a reply to command: 0x4" to send SMS regardless of the value $smsNullTerminateOctetstrings.

Do you have any idea how to fix that?

Many thanks in advance.

DLT Tag

We are from India. We cannot send sms without DLT / PEID. No idea how DLT is tagged on this. Can you help?

Unicode SMS segmentation issue, for 3 parts sending as 4 part

Hello, I believe I've resolved an issue in your repository related to the splitting of Unicode SMS messages into 3 parts in the SMPP protocol. Please review the following changes I made:

1- Account for the User Data Header (UDH) when calculating message splits. The UDH for concatenated messages is typically 6 octets (or bytes) in length.
2- Ensure that when calculating the length of a UCS2 encoded message, we account for the fact that each character is represented by 2 octets.
Here's the modified code:

in /src/Client.php at sendSMS function

`
public function sendSMS(
Address $from,
Address $to,
string $message,
array $tags = null,
int $dataCoding = Smpp::DATA_CODING_DEFAULT,
int $priority = 0x00,
$scheduleDeliveryTime = null,
$validityPeriod = null
): bool|string {
$messageLength = strlen($message);

if ($messageLength > 160 && !in_array($dataCoding, [Smpp::DATA_CODING_UCS2, Smpp::DATA_CODING_DEFAULT])) {
    return false;
}

$udhLength = 6; // Typically 6 octets for concatenated SMS

switch ($dataCoding) {
         case Smpp::DATA_CODING_UCS2:
        // in octets, 70 UCS-2 chars
        $singleSmsOctetLimit = 140;  // 70 characters * 2 bytes per character

        // Adjusting for UDH and ensuring we don't split a UCS character
        // Also, considering the UDH length (6 octets for concatenated messages)
        $udhLength = ($messageLength > $singleSmsOctetLimit) ? 6 : 0;  // UDH only for multipart
        $csmsSplit = $singleSmsOctetLimit - $udhLength;  // Reduce available size by UDH length

        $message = mb_convert_encoding($message, 'UCS-2BE', 'auto');  // Ensure correct encoding
        $messageLength = mb_strlen($message, '8bit');  // Count bytes, not characters

        // Calculate the number of messages
        $numMessages = ceil($messageLength / $csmsSplit);  // Total parts
        if ($numMessages > 1) {
            // If multipart, adjust split to ensure it's even (UCS-2 characters are 2 bytes)
            $csmsSplit -= ($csmsSplit % 2);
        }
        break;
    case Smpp::DATA_CODING_DEFAULT:
        // we send data in octets, but GSM 03.38 will be packed in septets (7-bit) by SMSC.
        $singleSmsOctetLimit = 160;
        // Adjust for UDH and decide based on the csms method
        $csmsSplit = (self::$csmsMethod == self::CSMS_8BIT_UDH) ? (153 - $udhLength) : (152 - $udhLength);
        break;
    default:
        $singleSmsOctetLimit = 254; // From SMPP standard
        break;
}
`

Relax loggerinterface requirement

Would it be acceptable to relax the definition of the logging for this library so that any PSR\Logger\LoggerInterface can be used?

I'm using this as part of a wider system and want to use the centralised loggers but the requirement for smpp\LoggerInterface is causing me problems.

If that's acceptable I'll submit a suggestion and a pull request.

Multipart messages - Delivery Status

The delivery report of multipart messages is difficult to read. In transmitter mode the last ID output is received as response. The receiver reads only the first ID and skips the rest. A miss match occurs because the operator sends status to all parts of the message but does not read the last ID. Is there a way to read all the ids without skipping them?

NB :: if the status of outgoing messages is 'DELIRVD' then this error is not seen; This issue is only with REJECT and FAILED status.

sbumit_multi

hi alexandr
if you can implemntaion sbumit_multi function to send to multi Recipients

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.