Howto Send and Read SMSs using a GSM modem, AT+ commands and PHP
Join the DZone community and get the full member experience.
Join For FreeThe idea is the following one: We are going to create a main class called Sms. It takes in the constructor (via dependency injection) the HTTP wrapper or the serial one (both with the same interface). That means our Sms class will work exactly in the same way with one interface or another.
Let’s start. First we’re going to create a Dummy Mock object, sharing the same interface than the others. The purpose of that is to test the main class (Sms.php)
<?php class Sms_Dummy implements Sms_Interface { public function deviceOpen() { } public function deviceClose() { } public function sendMessage($msg) { } public function readPort() { return array("OK", array()); } private $_validOutputs = array(); public function setValidOutputs($validOutputs) { $this->_validOutputs = $validOutputs; } }
And we test the code:
<?php require_once('Sms.php'); require_once('Sms/Interface.php'); require_once('Sms/Dummy.php'); $pin = 1234; $serial = new Sms_Dummy; if (Sms::factory($serial)->insertPin($pin) ->sendSMS(555987654, "test Hi")) { echo "SMS sent\n"; } else { echo "SMS not Sent\n"; }
It works. Our Sms class sends a fake sms using Sms_Dummy
Now we only need to create Sms_Serial and Sms_Http. For Sms_Serial I’ve use the great library (with a slight modifications) of Rémy Sanchez to read/write serial port in PHP (you can find it here). We can run it with a script similar than the Dummy one, thanks to dependency injection:
require_once('Sms.php'); require_once('Sms/Interface.php'); require_once('Sms/Serial.php'); $pin = 1234; try { $serial = new Sms_Serial; $serial->deviceSet("/dev/ttyS0"); $serial->confBaudRate(9600); $serial->confParity('none'); $serial->confCharacterLength(8); $sms = Sms::factory($serial)->insertPin($pin); if ($sms->sendSMS(555987654, "test Hi")) { echo "SMS sent\n"; } else { echo "Sent Error\n"; } // Now read inbox foreach ($sms->readInbox() as $in) { echo"tlfn: {$in['tlfn']} date: {$in['date']} {$in['hour']}\n{$in['msg']}\n"; // now delete sms if ($sms->deleteSms($in['id'])) { echo "SMS Deleted\n"; } } } catch (Exception $e) { switch ($e->getCode()) { case Sms::EXCEPTION_NO_PIN: echo "PIN Not set\n"; break; case Sms::EXCEPTION_PIN_ERROR: echo "PIN Incorrect\n"; break; case Sms::EXCEPTION_SERVICE_NOT_IMPLEMENTED: echo "Service Not implemented\n"; break; default: echo $e->getMessage(); } }
And finaly the Http one. As you can see the the script is the same than the Serial one. the only difference is the class passed to the constructor of the Sms class:
<?php require_once('Sms.php'); require_once('Sms/Interface.php'); require_once('Sms/Http.php'); $serialEternetConverterIP = '192.168.1.10'; $serialEternetConverterPort = 1113; $pin = 1234; try { $sms = Sms::factory(new Sms_Http($serialEternetConverterIP, $serialEternetConverterPort)); $sms->insertPin($pin); if ($sms->sendSMS(555987654, "test Hi")) { echo "SMS Sent\n"; } else { echo "Sent Error\n"; } // Now read inbox foreach ($sms->readInbox() as $in) { echo"tlfn: {$in['tlfn']} date: {$in['date']} {$in['hour']}\n{$in['msg']}\n"; // now delete sms if ($sms->deleteSms($in['id'])) { echo "SMS Deleted\n"; } } } catch (Exception $e) { switch ($e->getCode()) { case Sms::EXCEPTION_NO_PIN: echo "PIN Not set\n"; break; case Sms::EXCEPTION_PIN_ERROR: echo "PIN Incorrect\n"; break; case Sms::EXCEPTION_SERVICE_NOT_IMPLEMENTED: echo "Service Not implemented\n"; break; default: echo $e->getMessage(); } }
Serial/Ethernet converters normally have different operational modes. They allow you to create a fake serial port on your PC and work exactly in the same way than if you have your device connected with a serial cable. I don’t like this operation mode. I prefer to use the TCP server mode. With the TCP server mode I can read/write from the serial device with the standard socket functions. So if you dive into Sms_Http class you will find TCP socket’s functions.
And finally I will do a brief excerpt of AT+ commands used to send /read SMSs:
AT+CPIN?\r : checks if SIM has the pin code. It answers +CPIN: READY or +CPIN: SIM PIN if we need to insert the pin number
AT+CMGS=”[number]”\r[text]Control-Z : to send a SMS (in php we have Control-Z with chr(26)). It returns OK or ERROR
AT+CMGF=1\r: set the device to operate in SMS text mode (0=PDU mode and 1=text mode). Returns OK.
AT+CMGL=\”ALL”\r read all the sms stored in the device. We also can use “REC UNREAD” Instead of “ALL”.
AT+CMGD=[ID]\r: Deletes a SMS from the device
You can download the source code from github here
Opinions expressed by DZone contributors are their own.
Comments