I want to connect to webSocket server with PHP, but for some reason do not succeed, but a displays message is "Connected".
PHP:
$host="i[..].herokuapp.com" ;
$port=443;
$timeout=30;
$sk=fsockopen($host,$port,$errnum,$errstr,$timeout) ;
echo $errstr;
if (!is_resource($sk)) {
exit("connection fail: ".$errnum." ".$errstr) ;
} else {
echo "Connected";
fwrite($sk, '{""mi":1,"ertek":"a"}') or die('Error:' . $errno . ':' . $errstr);
fclose($sk);
}
And Nodejs Websocket server:
var WebSocketServer = require("ws").Server;
var http = require("http");
var express = require("express");
var app = express();
var port = process.env.PORT || 5000;
app.use(express.static(__dirname + "/"));
var server = http.createServer(app);
server.listen(port);
var wss = new WebSocketServer({server: server});
wss.on("connection", function(ws) {
[...]
});
This working:
public function __construct() { }
public function __destruct()
{
$this->disconnect();
}
public function sendData($data, $type = 'text', $masked = true, $return = false)
{
if(!$this->_connected)
{
//echo "Not connected";
return false;
}
if( !is_string($data)) {
//echo "Not a string data was given.";
return false;
}
if (strlen($data) == 0)
{
return false;
}
$res = fwrite($this->_Socket, $this->_hybi10Encode($data, $type, $masked));
if($res === 0 || $res === false)
{
return false;
}
$buffer = ' ';
if($return){
while(!empty($buffer))
{
$buffer = fread($this->_Socket, 512);// drop?
}
return $buffer;
}else{
return true;
}
}
public function connect($host, $port = 80, $path = 'into.hu', $origin = true)
{
$this->_host = $host;
$this->_port = $port;
$this->_path = $path;
$this->_origin = $origin;
$key = base64_encode($this->_generateRandomString(16, false, true));
$header = "GET ws://".$host . " HTTP/1.1\r\n";
$header.= "Host: ".$host.":".$port."\r\n";
$header.= "Connection: Upgrade\r\n";
$header.= "Pragma: no-cache\r\n";
$header.= "Cache-Control: no-cache\r\n";
$header.= "Upgrade: websocket\r\n";
$header.= "Sec-WebSocket-Version: 13\r\n";
$header.= "User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36\r\n";
$header.= "Accept-Language: hu,en;q=0.8,en-US;q=0.6,en-AU;q=0.4\r\n";
$header.= "Sec-WebSocket-Key: " . $key . "\r\n";
if($origin !== false)
{
$header.= "Origin: ".$path."\r\n";
$header.= "Sec-WebSocket-Origin: " . $origin . "\r\n";
}
$header.= "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n";
$this->_Socket = fsockopen($host, $port, $errno, $errstr, 2);
//socket_set_timeout($this->_Socket, 0, 10000);
fwrite($this->_Socket, $header);
$response = fread($this->_Socket, 200);
if(!empty($response)){
$this->_connected = true;
}
/*
preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches);
if ($matches) {
$keyAccept = trim($matches[1]);
$expectedResonse = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$this->_connected = ($keyAccept === $expectedResonse) ? true : false;
}
*/
return $this->_connected;
}
public function checkConnection()
{
$this->_connected = false;
// send ping:
$data = 'ping?';
#fwrite($this->_Socket, $this->_hybi10Encode($data, 'ping', true));
$response = #fread($this->_Socket, 300);
if(empty($response))
{
return false;
}
$response = $this->_hybi10Decode($response);
if(!is_array($response))
{
return false;
}
if(!isset($response['type']) || $response['type'] !== 'pong')
{
return false;
}
$this->_connected = true;
return true;
}
public function disconnect()
{
$this->_connected = false;
is_resource($this->_Socket) and fclose($this->_Socket);
}
public function reconnect()
{
sleep(2);
$this->_connected = false;
fclose($this->_Socket);
$this->connect($this->_host, $this->_port, $this->_path, $this->_origin);
}
private function _generateRandomString($length = 10, $addSpaces = true, $addNumbers = true)
{
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
$useChars = array();
// select some random chars:
for($i = 0; $i < $length; $i++)
{
$useChars[] = $characters[mt_rand(0, strlen($characters)-1)];
}
// add spaces and numbers:
if($addSpaces === true)
{
array_push($useChars, ' ', ' ', ' ', ' ', ' ', ' ');
}
if($addNumbers === true)
{
array_push($useChars, rand(0,9), rand(0,9), rand(0,9));
}
shuffle($useChars);
$randomString = trim(implode('', $useChars));
$randomString = substr($randomString, 0, $length);
return $randomString;
}
private function _hybi10Encode($payload, $type = 'text', $masked = true)
{
$frameHead = array();
$frame = '';
$payloadLength = strlen($payload);
switch($type)
{
case 'text':
// first byte indicates FIN, Text-Frame (10000001):
$frameHead[0] = 129;
break;
case 'close':
// first byte indicates FIN, Close Frame(10001000):
$frameHead[0] = 136;
break;
case 'ping':
// first byte indicates FIN, Ping frame (10001001):
$frameHead[0] = 137;
break;
case 'pong':
// first byte indicates FIN, Pong frame (10001010):
$frameHead[0] = 138;
break;
}
// set mask and payload length (using 1, 3 or 9 bytes)
if($payloadLength > 65535)
{
$payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
$frameHead[1] = ($masked === true) ? 255 : 127;
for($i = 0; $i < 8; $i++)
{
$frameHead[$i+2] = bindec($payloadLengthBin[$i]);
}
// most significant bit MUST be 0 (close connection if frame too big)
if($frameHead[2] > 127)
{
$this->close(1004);
return false;
}
}
elseif($payloadLength > 125)
{
$payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
$frameHead[1] = ($masked === true) ? 254 : 126;
$frameHead[2] = bindec($payloadLengthBin[0]);
$frameHead[3] = bindec($payloadLengthBin[1]);
}
else
{
$frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
}
// convert frame-head to string:
foreach(array_keys($frameHead) as $i)
{
$frameHead[$i] = chr($frameHead[$i]);
}
if($masked === true)
{
// generate a random mask:
$mask = array();
for($i = 0; $i < 4; $i++)
{
$mask[$i] = chr(rand(0, 255));
}
$frameHead = array_merge($frameHead, $mask);
}
$frame = implode('', $frameHead);
// append payload to frame:
$framePayload = array();
for($i = 0; $i < $payloadLength; $i++)
{
$frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
}
return $frame;
}
private function _hybi10Decode($data)
{
$payloadLength = '';
$mask = '';
$unmaskedPayload = '';
$decodedData = array();
// estimate frame type:
$firstByteBinary = sprintf('%08b', ord($data[0]));
$secondByteBinary = sprintf('%08b', ord($data[1]));
$opcode = bindec(substr($firstByteBinary, 4, 4));
$isMasked = ($secondByteBinary[0] == '1') ? true : false;
$payloadLength = ord($data[1]) & 127;
switch($opcode)
{
// text frame:
case 1:
$decodedData['type'] = 'text';
break;
case 2:
$decodedData['type'] = 'binary';
break;
// connection close frame:
case 8:
$decodedData['type'] = 'close';
break;
// ping frame:
case 9:
$decodedData['type'] = 'ping';
break;
// pong frame:
case 10:
$decodedData['type'] = 'pong';
break;
default:
return false;
break;
}
if($payloadLength === 126)
{
$mask = substr($data, 4, 4);
$payloadOffset = 8;
$dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset;
}
elseif($payloadLength === 127)
{
$mask = substr($data, 10, 4);
$payloadOffset = 14;
$tmp = '';
for($i = 0; $i < 8; $i++)
{
$tmp .= sprintf('%08b', ord($data[$i+2]));
}
$dataLength = bindec($tmp) + $payloadOffset;
unset($tmp);
}
else
{
$mask = substr($data, 2, 4);
$payloadOffset = 6;
$dataLength = $payloadLength + $payloadOffset;
}
if($isMasked === true)
{
for($i = $payloadOffset; $i < $dataLength; $i++)
{
$j = $i - $payloadOffset;
if(isset($data[$i]))
{
$unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
}
}
$decodedData['payload'] = $unmaskedPayload;
}
else
{
$payloadOffset = $payloadOffset - 4;
$decodedData['payload'] = substr($data, $payloadOffset);
}
return $decodedData;
}
}
$WebSocketClient = new WebsocketClient();
$WebSocketClient->connect('i[..].herokuapp.com',80,'valami.hu');
//$WebSocketClient->reconnect();
$WebSocketClient->sendData('üzenet küldés');
unset($WebSocketClient);
?>
I have installed Mosquitto on the server, and it's running, and working fine.
I have installed Paho mqtt client plugin to check.
and I wrote the code for android and it's working fine on the emulator.
now in my own computer everything works fine, I run the php code and my app in android receives the message and Paho client receives that message too.
but when I upload the file on the server and run it nothing happens, although the php code runs everything successfully, and publishes the message without any error.
and even the mosquitto's publisher executable works fine and clients receive the message.
only this php code on the server doesn't do anything.
$mqtt = new phpMQTT("localhost", 1883, "server");
if ($mqtt->connect()) {
echo"connected\n";
for($i=0;$i<4;++$i){
if($mqtt->publish("new","Hey . ".$i,2)){
echo "published\n";
}
else{
echo "not published\n";
}
}
$mqtt->close();
}
else{
echo"couldn't connect\n";
}
Bluerhinos phpMQTT:
<?php
/* phpMQTT */
class phpMQTT {
private $socket; /* holds the socket */
private $msgid = 1; /* counter for message id */
public $keepalive = 10; /* default keepalive timmer */
public $timesinceping; /* host unix time, used to detect disconects */
public $topics = array(); /* used to store currently subscribed topics */
public $debug = true; /* should output debug messages */
public $address; /* broker address */
public $port; /* broker port */
public $clientid; /* client id sent to brocker */
public $will; /* stores the will of the client */
private $username; /* stores username */
private $password; /* stores password */
function __construct($address, $port, $clientid){
$this->broker($address, $port, $clientid);
}
/* sets the broker details */
function broker($address, $port, $clientid){
$this->address = $address;
$this->port = $port;
$this->clientid = $clientid;
}
/* connects to the broker
inputs: $clean: should the client send a clean session flag */
function connect($clean = true, $will = NULL, $username = NULL, $password = NULL){
if($will) $this->will = $will;
if($username) $this->username = $username;
if($password) $this->password = $password;
$address = $this->address;
$this->socket = fsockopen($address, $this->port, $errno, $errstr, 60);
if (!$this->socket ) {
error_log("fsockopen() $errno, $errstr \n");
return false;
}
stream_set_timeout($this->socket, 5);
stream_set_blocking($this->socket, 0);
$i = 0;
$buffer = "";
$buffer .= chr(0x00); $i++;
$buffer .= chr(0x06); $i++;
$buffer .= chr(0x4d); $i++;
$buffer .= chr(0x51); $i++;
$buffer .= chr(0x49); $i++;
$buffer .= chr(0x73); $i++;
$buffer .= chr(0x64); $i++;
$buffer .= chr(0x70); $i++;
$buffer .= chr(0x03); $i++;
//No Will
$var = 0;
if($clean) $var+=2;
//Add will info to header
if($this->will != NULL){
$var += 4; // Set will flag
$var += ($this->will['qos'] << 3); //Set will qos
if($this->will['retain']) $var += 32; //Set will retain
}
if($this->username != NULL) $var += 128; //Add username to header
if($this->password != NULL) $var += 64; //Add password to header
$buffer .= chr($var); $i++;
//Keep alive
$buffer .= chr($this->keepalive >> 8); $i++;
$buffer .= chr($this->keepalive & 0xff); $i++;
$buffer .= $this->strwritestring($this->clientid,$i);
//Adding will to payload
if($this->will != NULL){
$buffer .= $this->strwritestring($this->will['topic'],$i);
$buffer .= $this->strwritestring($this->will['content'],$i);
}
if($this->username) $buffer .= $this->strwritestring($this->username,$i);
if($this->password) $buffer .= $this->strwritestring($this->password,$i);
$head = " ";
$head{0} = chr(0x10);
$head{1} = chr($i);
fwrite($this->socket, $head, 2);
fwrite($this->socket, $buffer);
$string = $this->read(4);
if(ord($string{0})>>4 == 2 && $string{3} == chr(0)){
if($this->debug) echo "Connected to Broker\n";
}else{
error_log(sprintf("Connection failed! (Error: 0x%02x 0x%02x)\n",
ord($string{0}),ord($string{3})));
return false;
}
$this->timesinceping = time();
return true;
}
/* read: reads in so many bytes */
function read($int = 8192, $nb = false){
// print_r(socket_get_status($this->socket));
$string="";
$togo = $int;
if($nb){
return fread($this->socket, $togo);
}
while (!feof($this->socket) && $togo>0) {
$fread = fread($this->socket, $togo);
$string .= $fread;
$togo = $int - strlen($string);
}
return $string;
}
/* subscribe: subscribes to topics */
function subscribe($topics, $qos = 0){
$i = 0;
$buffer = "";
$id = $this->msgid;
$buffer .= chr($id >> 8); $i++;
$buffer .= chr($id % 256); $i++;
foreach($topics as $key => $topic){
$buffer .= $this->strwritestring($key,$i);
$buffer .= chr($topic["qos"]); $i++;
$this->topics[$key] = $topic;
}
$cmd = 0x80;
//$qos
$cmd += ($qos << 1);
$head = chr($cmd);
$head .= chr($i);
fwrite($this->socket, $head, 2);
fwrite($this->socket, $buffer, $i);
$string = $this->read(2);
$bytes = ord(substr($string,1,1));
$string = $this->read($bytes);
}
/* ping: sends a keep alive ping */
function ping(){
$head = " ";
$head = chr(0xc0);
$head .= chr(0x00);
fwrite($this->socket, $head, 2);
if($this->debug) echo "ping sent\n";
}
/* disconnect: sends a proper disconect cmd */
function disconnect(){
$head = " ";
$head{0} = chr(0xe0);
$head{1} = chr(0x00);
fwrite($this->socket, $head, 2);
}
/* close: sends a proper disconect, then closes the socket */
function close(){
$this->disconnect();
fclose($this->socket);
}
/* publish: publishes $content on a $topic */
function publish($topic, $content, $qos = 0, $retain = 0){
$i = 0;
$buffer = "";
$buffer .= $this->strwritestring($topic,$i);
//$buffer .= $this->strwritestring($content,$i);
if($qos){
$id = $this->msgid++;
$buffer .= chr($id >> 8); $i++;
$buffer .= chr($id % 256); $i++;
}
$buffer .= $content;
$i+=strlen($content);
$head = " ";
$cmd = 0x30;
if($qos) $cmd += $qos << 1;
if($retain) $cmd += 1;
$head{0} = chr($cmd);
$head .= $this->setmsglength($i);
if((fwrite($this->socket, $head, strlen($head)))&&(fwrite($this->socket, $buffer, $i))){
echo "done: ".$this->socket."<br>";
return true;
}
else {
echo $head;
return false;
}
}
/* message: processes a recieved topic */
function message($msg){
$tlen = (ord($msg{0})<<8) + ord($msg{1});
$topic = substr($msg,2,$tlen);
$msg = substr($msg,($tlen+2));
$found = 0;
foreach($this->topics as $key=>$top){
if( preg_match("/^".str_replace("#",".*",
str_replace("+","[^\/]*",
str_replace("/","\/",
str_replace("$",'\$',
$key))))."$/",$topic) ){
if(function_exists($top['function'])){
call_user_func($top['function'],$topic,$msg);
$found = 1;
}
}
}
if($this->debug && !$found) echo "msg recieved but no match in subscriptions\n";
}
/* proc: the processing loop for an "allways on" client
set true when you are doing other stuff in the loop good for watching something else at the same time */
function proc( $loop = true){
if(1){
$sockets = array($this->socket);
$w = $e = NULL;
$cmd = 0;
//$byte = fgetc($this->socket);
if(feof($this->socket)){
if($this->debug) echo "eof receive going to reconnect for good measure\n";
fclose($this->socket);
$this->connect(false);
if(count($this->topics))
$this->subscribe($this->topics);
}
$byte = $this->read(1, true);
if(!strlen($byte)){
if($loop){
usleep(100000);
}
}else{
$cmd = (int)(ord($byte)/16);
if($this->debug) echo "Recevid: $cmd\n";
$multiplier = 1;
$value = 0;
do{
$digit = ord($this->read(1));
$value += ($digit & 127) * $multiplier;
$multiplier *= 128;
}while (($digit & 128) != 0);
if($this->debug) echo "Fetching: $value\n";
if($value)
$string = $this->read($value,"fetch");
if($cmd){
switch($cmd){
case 3:
$this->message($string);
break;
}
$this->timesinceping = time();
}
}
if($this->timesinceping < (time() - $this->keepalive )){
if($this->debug) echo "not found something so ping\n";
$this->ping();
}
if($this->timesinceping<(time()-($this->keepalive*2))){
if($this->debug) echo "not seen a package in a while, disconnecting\n";
fclose($this->socket);
$this->connect(false);
if(count($this->topics))
$this->subscribe($this->topics);
}
}
return 1;
}
/* getmsglength: */
function getmsglength(&$msg, &$i){
$multiplier = 1;
$value = 0 ;
do{
$digit = ord($msg{$i});
$value += ($digit & 127) * $multiplier;
$multiplier *= 128;
$i++;
}while (($digit & 128) != 0);
return $value;
}
/* setmsglength: */
function setmsglength($len){
$string = "";
do{
$digit = $len % 128;
$len = $len >> 7;
// if there are more digits to encode, set the top bit of this digit
if ( $len > 0 )
$digit = ($digit | 0x80);
$string .= chr($digit);
}while ( $len > 0 );
return $string;
}
/* strwritestring: writes a string to a buffer */
function strwritestring($str, &$i){
$ret = " ";
$len = strlen($str);
$msb = $len >> 8;
$lsb = $len % 256;
$ret = chr($msb);
$ret .= chr($lsb);
$ret .= $str;
$i += ($len+2);
return $ret;
}
function printstr($string){
$strlen = strlen($string);
for($j=0;$j<$strlen;$j++){
$num = ord($string{$j});
if($num > 31)
$chr = $string{$j}; else $chr = " ";
printf("%4d: %08b : 0x%02x : %s \n",$j,$num,$num,$chr);
}
}
}
?>
Follow this library publish example and see what happens both logs: the localhost broker and the php log
https://github.com/bluerhinos/phpMQTT/blob/master/examples/publish.php
I'm trying to use IMAP function to detach an attachment received from inbox and save into the server directory specified.
I am doing this for all UNSEEN messages but the problem is that it only does for one message only.
Below is the code (I deleted $host,$login,$password variables for obvious reasons):
$type = 'ReadAttachment';
$obj = new $type;
$obj->getdata($host,$login,$password,$savedirpath,$delete_emails=false);
class ReadAttachment
{
function getdecodevalue($message,$coding) {
switch($coding) {
case 0:
case 1:
$message = imap_8bit($message);
break;
case 2:
$message = imap_binary($message);
break;
case 3:
case 5:
$message = imap_base64($message);
break;
case 4:
$message = imap_qprint($message);
break;
}
return $message;
}
function getdata($host,$login,$password,$savedirpath,$delete_emails=false, $read_type="UNSEEN") {
// make sure save path has trailing slash (/)
//print_r("test");
$savedirpath = str_replace('\\', '/', $savedirpath);
if (substr($savedirpath, strlen($savedirpath) - 1) != '/') {
$savedirpath .= '/';
}
$mbox = imap_open ($host, $login, $password) or die("can't connect: " . imap_last_error());
$message = array();
$message["attachment"]["type"][0] = "text";
$message["attachment"]["type"][1] = "multipart";
$message["attachment"]["type"][2] = "message";
$message["attachment"]["type"][3] = "application";
$message["attachment"]["type"][4] = "audio";
$message["attachment"]["type"][5] = "image";
$message["attachment"]["type"][6] = "video";
$message["attachment"]["type"][7] = "other";
//print_r($message);
$emails = imap_search($mbox,$read_type) or die(print_r(imap_last_error()));
print_r($emails);
$e = imap_search($mbox,$read_type, SE_UID) or die(print_r(imap_last_error()));
print_r($e);
$i=0;
foreach($emails as $email_number) {
$structure = imap_fetchstructure($mbox, $e[$i] , FT_UID) or die(print_r(imap_last_error()));
$parts = $structure->parts;
$fpos=2;
for($i = 1; $i < count($parts); $i++) {
$message["pid"][$i] = ($i);
$part = $parts[$i];
if($part->disposition == "attachment") {
$message["type"][$i] = $message["attachment"]["type"][$part->type] . "/" . strtolower($part->subtype);
$message["subtype"][$i] = strtolower($part->subtype);
$ext=$part->subtype;
$params = $part->dparameters;
$filename=$part->dparameters[0]->value;
$mege="";
$data="";
$mege = imap_fetchbody($mbox,$email_number,$fpos);
$filename="$filename";
$fp=fopen($savedirpath.$filename,"w");
$data=$this->getdecodevalue($mege,$part->type);
//print_r($mege);
fputs($fp,$data);
fclose($fp);
$fpos+=1;
}
}
++$i;
}
// imap_expunge deletes all tagged messages
imap_close($mbox);
}
}
Is there something that I could change above?
I'm not sure whether this is the cause of the problem, or if I even understood your code correctly. However I think your $i=0 needs to go inside the foreach loop, and you need to lose the ++$i at the end.
Let's go through it. First, you set $i=0. foreach gets the first message and enters the for loop, which iterates over incrementing values of $i. Let's say that $i is set to 4 when the for loop ends. At that point, ++$i sets it to 5. The foreach iteration ends and the next email should be processed. But this does not happen because $i is still 5, so when you do:
$structure = imap_fetchstructure($mbox, $e[$i] , FT_UID)
You are picking the wrong email.
Actually looking at the script I think he's using $i in 2 places incorrectly. the $i within the foreach should be a different variable.
for the $structure variable he should use the $i as expected ...
but the mail parts should use a separate variable (I used $p)
i know this is an old post, but it helped me a bit.
<?php
/*
File : smppclass.php
Implements : SMPPClass()
Description : This class can send messages via the SMPP protocol. Also supports unicode and multi-part messages.
License : GNU Lesser Genercal Public License: http://www.gnu.org/licenses/lgpl.html
Commercial advertisement: Contact info#chimit.nl for SMS connectivity and more elaborate SMPP libraries in PHP and other languages.
*/
/*
The following are the SMPP PDU types that we are using in this class.
Apart from the following 5 PDU types, there are a lot of SMPP directives
that are not implemented in this version.
*/
/*
define(CM_BIND_TRANSMITTER, 0x00000002);
define(CM_SUBMIT_SM, 0x00000004);
define(CM_SUBMIT_MULTI, 0x00000021);
define(CM_UNBIND, 0x00000006);
define(CM_ENQUIRELINK, 0x00000015);
*/
define('generic_nack', 0x80000000);
define('bind_receiver', 0x00000001);
define('bind_receiver_resp', 0x80000001);
define('bind_transmitter', 0x00000002);
define('bind_transmitter_resp', 0x80000002);
define('query_sm', 0x00000003);
define('query_sm_resp', 0x80000003);
define('submit_sm', 0x00000004);
define('submit_sm_resp', 0x80000004);
define('deliver_sm', 0x00000005);
define('deliver_sm_resp', 0x80000005);
define('unbind', 0x00000006);
define('unbind_resp', 0x80000006);
define('replace_sm', 0x00000007);
define('replace_sm_resp', 0x80000007);
define('cancel_sm', 0x00000008);
define('cancel_sm_resp', 0x80000008);
define('bind_transceiver', 0x00000009);
define('bind_transceiver_resp', 0x80000009);
define('outbind', 0x0000000B);
define('enquire_link', 0x00000015);
define('enquire_link_resp', 0x80000015);
define('submit_multi', 0x00000021);
define('submit_multi_resp', 0x80000021);
define('alert_notification', 0x00000102);
define('data_sm', 0x00000103);
define('data_sm_resp', 0x80000103);
class SMPPClass
{
// public members:
/*
Constructor.
Parameters:
none.
Example:
$smpp = new SMPPClass();
*/
function SMPPClass()
{
/* seed random generator */
list($usec, $sec) = explode(' ', microtime());
$seed = (float)$sec + ((float)$usec * 100000);
srand($seed);
/* initialize member variables */
$this->_debug = true;
/* set this to false if you want to suppress debug output. */
$this->_socket = null;
$this->_command_status = 0;
$this->_sequence_number = 1;
$this->_source_address = "";
$this->_message_sequence = rand(1, 255);
$this->_message_id = 0;
$this->interface_version = 0x34;
$this->addr_ton = 1;
$this->addr_npi = 1;
$this->address_range = '';
$this->dlvrSms = array();
}
/*
For SMS gateways that support sender-ID branding, the method
can be used to set the originating address.
Parameters:
$from : Originating address
Example:
$smpp->SetSender("31495595392");
*/
function SetSender($from)
{
if (strlen($from) > 20) {
$this->debug("Error: sender id too long.\n");
return;
}
$this->_source_address = $from;
}
/*
This method initiates an SMPP session.
It is to be called BEFORE using the Send() method.
Parameters:
$host : SMPP ip to connect to.
$port : port # to connect to.
$username : SMPP system ID
$password : SMPP passord.
$system_type : SMPP System type
Returns:
true if successful, otherwise false
Example:
$smpp->Start("smpp.chimit.nl", 2345, "chimit", "my_password", "client01");
*/
function getMessageId(){
return $this->_message_id;
}
function Start($host, $port, $username, $password, $system_type, $type)
{
/*
$testarr = stream_get_transports();
$have_tcp = false;
reset($testarr);
while (list(, $transport) = each($testarr)) {
if ($transport == "tcpp") {
$have_tcp = true;
}
}
if (!$have_tcp) {
$this->debug("No TCP support in this version of PHP.\n");
return false;
}
*/
$this->_socket = #fsockopen($host, $port, $errno, $errstr, 120);
// todo: sanity check on input parameters
if (!$this->_socket) {
$this->debug("Error opening SMPP session.\n");
$this->debug("Error was: $errstr.\n");
return;
}
socket_set_timeout($this->_socket, 120);
//$status = $this->SendBindTransmitter($username, $password, $system_type);
if ($type == 'transmitter') {
$status = $this->SendBindTransmitter($username, $password, $system_type);
} elseif ($type == 'receiver') {
$status = $this->SendBindReceiver($username, $password, $system_type);
}
if ($status != 0) {
$this->debug("Error binding to SMPP server. Invalid credentials?\n");
}
return($status == 0);
}
/*
This method sends out one SMS message.
Parameters:
$to : destination address.
$text : text of message to send.
$unicode: Optional. Indicates if input string is html encoded unicode.
Returns:
true if messages sent successfull, otherwise false.
Example:
$smpp->Send("31649072766", "This is an SMPP Test message.");
$smpp->Send("31648072766", "صباحالخير", true);
*/
function Send($to, $text, $unicode = false)
{
if (strlen($to) > 20) {
$this->debug("to-address too long.\n");
return;
}
if (!$this->_socket) {
$this->debug("Not connected, while trying to send SUBMIT_SM.\n");
// return;
}
$service_type = "";
//default source TON and NPI for international sender
$source_addr_ton = 1;
$source_addr_npi = 1;
$source_addr = $this->_source_address;
if (preg_match('/\D/', $source_addr)) {
//alphanumeric sender
$source_addr_ton = 5;
$source_addr_npi = 0;
} elseif (strlen($source_addr) < 11) {
//national or shortcode sender
$source_addr_ton = 2;
$source_addr_npi = 1;
}
$dest_addr_ton = 1;
$dest_addr_npi = 1;
$destination_addr = $to;
$esm_class = 3;
$protocol_id = 0;
$priority_flag = 0;
$schedule_delivery_time = "";
$validity_period = "";
$registered_delivery_flag = 1;
$replace_if_present_flag = 0;
$data_coding = 241;
$sm_default_msg_id = 0;
if ($unicode) {
$text = mb_convert_encoding($text, "UCS-2BE", "HTML-ENTITIES");
/* UCS-2BE */
$data_coding = 8;
/* UCS2 */
$multi = $this->split_message_unicode($text);
} else {
$multi = $this->split_message($text);
}
$multiple = (count($multi) > 1);
if ($multiple) {
$esm_class += 0x00000040;
}
$result = true;
reset($multi);
while (list(, $part) = each($multi)) {
$short_message = $part;
$sm_length = strlen($short_message);
$status = $this->SendSubmitSM($service_type, $source_addr_ton, $source_addr_npi, $source_addr, $dest_addr_ton, $dest_addr_npi, $destination_addr, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message);
if ($status != 0) {
$this->debug("SMPP server returned error $status.\n");
$result = false;
}
}
return $result;
}
/*
This method ends a SMPP session.
Parameters:
none
Returns:
true if successful, otherwise false
Example: $smpp->End();
*/
function end()
{
if (!$this->_socket) {
// not connected
return;
}
$status = $this->SendUnbind();
if ($status != 0) {
$this->debug("SMPP Server returned error $status.\n");
}
fclose($this->_socket);
$this->_socket = null;
return($status == 0);
}
/*
This method sends an enquire_link PDU to the server and waits for a response.
Parameters:
none
Returns:
true if successfull, otherwise false.
Example: $smpp->TestLink()
*/
function TestLink()
{
$pdu = "";
$status = $this->SendPDU(enquire_link, $pdu);
return($status == 0);
}
function ReadSms()
{
$pdu = "";
$status = true;
$m = 0;
echo date('H:i:s') . "\n";
$status = $this->SendPDU(deliver_sm_resp, $pdu);
return $this->dlvrSms;
}
function QuerySms($message_id, $gsm)
{
$this->dlvrSms = array();
socket_set_timeout($this->_socket, 120);
$pdu = "";
$message_id = $message_id;
$source_addr_ton = 1;
$source_addr_npi = 1;
$source_addr = $gsm;
////$pdu = pack($message_id . chr(0), $source_addr_ton . chr(0), $source_addr_npi . chr(0), $source_addr);
$status = $this->SendPDU(deliver_sm, $pdu);
////$this->ExpectPDU(0);
return $this->dlvrSms;
}
/*
This method sends a single message to a comma separated list of phone numbers.
There is no limit to the number of messages to send.
Parameters:
$tolist : comma seperated list of phone numbers
$text : text of message to send
$unicode: Optional. Indicates if input string is html encoded unicode string.
Returns:
true if messages received by smpp server, otherwise false.
Example:
$smpp->SendMulti("31777110204,31649072766,...,...", "This is an SMPP Test message.");
*/
function SendMulti($tolist, $text, $unicode = false)
{
if (!$this->_socket) {
$this->debug("Not connected, while trying to send SUBMIT_MULTI.\n");
// return;
}
$service_type = '';
//default source TON and NPI for international sender
$source_addr_ton = 1;
$source_addr_npi = 1;
$source_addr = $this->_source_address;
if (preg_match('/\D/', $source_addr)) {
//alphanumeric sender
$source_addr_ton = 5;
$source_addr_npi = 0;
} elseif (strlen($source_addr) < 11) {
//national or shortcode sender
$source_addr_ton = 2;
$source_addr_npi = 1;
}
$dest_addr_ton = 1;
$dest_addr_npi = 1;
$destination_arr = explode(",", $tolist);
$esm_class = 3;
$protocol_id = 0;
$priority_flag = 0;
$schedule_delivery_time = "";
$validity_period = "";
$registered_delivery_flag = 1;
$replace_if_present_flag = 0;
$data_coding = 241;
$sm_default_msg_id = 0;
if ($unicode) {
$text = mb_convert_encoding($text, "UCS-2BE", "HTML-ENTITIES");
$data_coding = 8;
/* UCS2 */
$multi = $this->split_message_unicode($text);
} else {
$multi = $this->split_message($text);
}
$multiple = (count($multi) > 1);
if ($multiple) {
$esm_class += 0x00000040;
}
$result = true;
reset($multi);
while (list(, $part) = each($multi)) {
$short_message = $part;
$sm_length = strlen($short_message);
$status = $this->SendSubmitMulti($service_type, $source_addr_ton, $source_addr_npi, $source_addr, $dest_addr_ton, $dest_addr_npi, $destination_arr, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message);
if ($status != 0) {
$this->debug("SMPP server returned error $status.\n");
$result = false;
}
}
return $result;
}
// private members (not documented):
function ExpectPDU($our_sequence_number)
{
do {
$this->debug("\n\nTrying to read PDU.\n");
if (feof($this->_socket)) {
$this->debug("Socket was closed.!!\n");
return false;
}
$elength = fread($this->_socket, 4);
if (empty($elength)) {
$this->debug("Connection lost.\n");
return false;
}
extract(unpack("Nlength", $elength));
$this->debug("Reading PDU : $length bytes.\n");
$stream = fread($this->_socket, $length - 4);
//$stream = fread($this->_socket, 12);
if (!$stream)
return false;
$this->debug("Stream len : " . strlen($stream) . "\n");
$this->debug("Stream Hex : " . $this->printHex($stream) . "\n");
extract(unpack("Ncommand_id/Ncommand_status/Nsequence_number", $stream));
//$info = stream_get_meta_data($this->_socket);
//$this->debug("stream_get_meta_data id : ".var_export($info,true)."\n");
$command_id &= 0x0fffffff;
$this->debug("Command id : $command_id.\n");
$this->debug("Command status : $command_status.\n");
$this->debug("sequence_number : $sequence_number.\n");
$pdu = substr($stream, 12);
//$pdu=$stream;
switch ($command_id) {
case bind_transmitter:
$this->debug("Got bind_transmitter_RESP.\n");
$spec = "asystem_id";
//extract($this->unpack2($spec, $pdu));
$this->debug("system id : $system_id.\n");
break;
case bind_receiver:
$this->debug("Got bind_receiver_RESP.\n");
$spec = "asystem_id";
extract($this->unpack2($spec, $pdu));
$this->debug("system id : $system_id.\n");
break;
case unbind:
$this->debug("Got unbind_RESP.\n");
break;
case submit_sm:
$this->debug("Got submit_sm_RESP.\n");
if ($command_status == 0) {
$spec = "amessage_id";
extract($this->unpack2($spec, $pdu));
$this->debug("message id : $message_id.\n");
$this->_message_id = $message_id;
}
break;
case submit_multi:
$this->debug("Got submit_multi_RESP.\n");
$spec = "amessage_id/cno_unsuccess/";
extract($this->unpack2($spec, $pdu));
$this->debug("message id : $message_id.\n");
$this->debug("no_unsuccess : $no_unsuccess.\n");
break;
case enquire_link:
$this->debug("GOT enquire_link_RESP.\n");
break;
case deliver_sm;
$this->debug("GOT deliver_sm.\n");
$body = substr($stream, 8, $length);
$this->dlvrSms[] = $this->parseSMS($body, $sequence_number);
$this->SendPDU(deliver_sm_resp, "",$sequence_number);
break;
case deliver_sm_resp;
$this->debug("GOT deliver_sm_resp.\n");
//$body = substr($stream,8, $length);
//$this->dlvrSms[]= $this->parseSMS($body);
break;
case query_sm;
$this->debug("GOT deliver_sm.\n");
$body = substr($stream, 8, $length);
$this->dlvrSms[] = $this->parseSMS($body, $sequence_number);
break;
case generic_nack:
$this->debug("Got generic_nack SMPP pdu.\n");
$spec = "ccommand_length/ccommand_id/ccommand_status/csequence_number";
extract($this->unpack2($spec, $pdu));
$this->debug("command_length generic_nack == " . $command_length . "\n");
$this->debug("command_id generic_nack == " . $command_id . "\n");
$this->debug("command_status generic_nack == " . $command_status . "\n");
$this->debug("command_status generic_nack == " . $command_status . "\n");
break;
default:
$this->debug("Got unknow $command_id SMPP pdu.\n");
}
$this->debug("\nReceived PDU: \n");
for ($i = 0; $i < strlen($stream); $i++) {
if (ord($stream[$i]) < 32)
$this->debug("(" . ord($stream[$i]) . ")");
else
$this->debug($stream[$i]);
}
$this->debug("\n");
} while ($sequence_number != $our_sequence_number);
return $command_status;
}
/**
* #private function
* Parse deliver PDU from SMSC.
* #param $pdu - deliver PDU from SMSC.
* #return parsed PDU as array.
*/
function parseSMS($body, $sequence_number)
{
//check command id
//unpack PDU
$ar = unpack("C*", $body);
//$ar=unpack("C*",$pdu['body']);
$sms = array('service_type' => $this->getString($ar, 6), 'source_addr_ton' => array_shift($ar), 'source_addr_npi' => array_shift($ar), 'source_addr' => $this->getString($ar, 21), 'dest_addr_ton' => array_shift($ar), 'dest_addr_npi' => array_shift($ar), 'destination_addr' => $this->getString($ar, 21), 'esm_class' => array_shift($ar), 'protocol_id' => array_shift($ar), 'priority_flag' => array_shift($ar), 'schedule_delivery_time' => array_shift($ar), 'validity_period' => array_shift($ar), 'registered_delivery' => array_shift($ar), 'replace_if_present_flag' => array_shift($ar), 'data_coding' => array_shift($ar), 'sm_default_msg_id' => array_shift($ar), 'sm_length' => array_shift($ar), 'short_message' => $this->getString($ar, 255));
// $this->_sequence_number=$sequence_number;
//send responce of recieving sms
return $sms;
}
function SendPDU($command_id, $pdu, $sequence_number = null)
{
if ($sequence_number == null) {
$sequence_number = $this->_sequence_number;
}
$length = strlen($pdu) + 16;
$header = pack("NNNN", $length, $command_id, $this->_command_status, $sequence_number);
$this->debug("Sending PDU, len == $length\n");
$this->debug("Sending PDU, header-len == " . strlen($header) . "\n");
$this->debug("Sending PDU, command_id == " . $command_id . "\n");
$this->debug("Sending PDU, sequence number == " . $sequence_number . "\n");
$this->debug("Sending PDU, command status == " . $this->_command_status . "\n");
fwrite($this->_socket, $header . $pdu, $length);
$status = $this->ExpectPDU($sequence_number);
$this->_sequence_number = $this->_sequence_number + 1;
return $status;
}
function SendBindTransmitter($system_id, $smpppassword, $system_type)
{
$system_id = $system_id . chr(0);
$system_id_len = strlen($system_id);
$smpppassword = $smpppassword . chr(0);
$smpppassword_len = strlen($smpppassword);
$system_type = $system_type . chr(0);
$system_type_len = strlen($system_type);
$pdu = pack("a{$system_id_len}a{$smpppassword_len}a{$system_type_len}CCCa1", $system_id, $smpppassword, $system_type, $this->interface_version, $this->addr_ton, $this->addr_npi, $this->address_range);
$this->debug("Bind Transmitter PDU: ");
for ($i = 0; $i < strlen($pdu); $i++) {
$this->debug(ord($pdu[$i]) . " ");
}
$this->debug("\n");
$status = $this->SendPDU(bind_transmitter, $pdu);
return $status;
}
function SendBindReceiver($system_id, $smpppassword, $system_type)
{
$system_id = $system_id . chr(0);
$system_id_len = strlen($system_id);
$smpppassword = $smpppassword . chr(0);
$smpppassword_len = strlen($smpppassword);
$system_type = $system_type . chr(0);
$system_type_len = strlen($system_type);
$pdu = pack("a{$system_id_len}a{$smpppassword_len}a{$system_type_len}CCCa1" . (strlen($this->address_range) + 1), $system_id, $smpppassword, $system_type, $this->interface_version, $this->addr_ton, $this->addr_npi, $this->address_range);
$this->debug("Bind Receiver PDU: ");
for ($i = 0; $i < strlen($pdu); $i++) {
$this->debug(ord($pdu[$i]) . " ");
}
$this->debug("\n");
$status = $this->SendPDU(bind_transceiver, $pdu);
return $status;
}
function SendUnbind()
{
$pdu = "";
$status = $this->SendPDU(unbind, $pdu);
return $status;
}
function SendSubmitSM($service_type, $source_addr_ton, $source_addr_npi, $source_addr, $dest_addr_ton, $dest_addr_npi, $destination_addr, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message)
{
$service_type = $service_type . chr(0);
$service_type_len = strlen($service_type);
$source_addr = $source_addr . chr(0);
$source_addr_len = strlen($source_addr);
$destination_addr = $destination_addr . chr(0);
$destination_addr_len = strlen($destination_addr);
$schedule_delivery_time = $schedule_delivery_time . chr(0);
$schedule_delivery_time_len = strlen($schedule_delivery_time);
$validity_period = $validity_period . chr(0);
$validity_period_len = strlen($validity_period);
// $short_message = $short_message . chr(0);
$message_len = $sm_length;
$spec = "a{$service_type_len}cca{$source_addr_len}cca{$destination_addr_len}ccca{$schedule_delivery_time_len}a{$validity_period_len}ccccca{$message_len}";
$this->debug("PDU spec: $spec.\n");
$pdu = pack($spec, $service_type, $source_addr_ton, $source_addr_npi, $source_addr, $dest_addr_ton, $dest_addr_npi, $destination_addr, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message);
$status = $this->SendPDU(submit_sm, $pdu);
return $status;
}
function SendSubmitMulti($service_type, $source_addr_ton, $source_addr_npi, $source_addr, $dest_addr_ton, $dest_addr_npi, $destination_arr, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message)
{
$service_type = $service_type . chr(0);
$service_type_len = strlen($service_type);
$source_addr = $source_addr . chr(0);
$source_addr_len = strlen($source_addr);
$number_destinations = count($destination_arr);
$dest_flag = 1;
$spec = "a{$service_type_len}cca{$source_addr_len}c";
$pdu = pack($spec, $service_type, $source_addr_ton, $source_addr_npi, $source_addr, $number_destinations);
$dest_flag = 1;
reset($destination_arr);
while (list(, $destination_addr) = each($destination_arr)) {
$destination_addr .= chr(0);
$dest_len = strlen($destination_addr);
$spec = "ccca{$dest_len}";
$pdu .= pack($spec, $dest_flag, $dest_addr_ton, $dest_addr_npi, $destination_addr);
}
$schedule_delivery_time = $schedule_delivery_time . chr(0);
$schedule_delivery_time_len = strlen($schedule_delivery_time);
$validity_period = $validity_period . chr(0);
$validity_period_len = strlen($validity_period);
$message_len = $sm_length;
$spec = "ccca{$schedule_delivery_time_len}a{$validity_period_len}ccccca{$message_len}";
$pdu .= pack($spec, $esm_class, $protocol_id, $priority_flag, $schedule_delivery_time, $validity_period, $registered_delivery_flag, $replace_if_present_flag, $data_coding, $sm_default_msg_id, $sm_length, $short_message);
$this->debug("\nMulti PDU: ");
for ($i = 0; $i < strlen($pdu); $i++) {
if (ord($pdu[$i]) < 32)
$this->debug(".");
else
$this->debug($pdu[$i]);
}
$this->debug("\n");
//$this->_command_status='';
$status = $this->SendPDU(submit_multi, $pdu);
return $status;
}
function split_message($text)
{
$this->debug("\n\nIn split_message.\n");
$max_len = 153;
$res = array();
if (strlen($text) <= 160) {
$this->debug("One message: " . strlen($text) . "\n");
$res[] = $text;
return $res;
}
$pos = 0;
$msg_sequence = $this->_message_sequence++;
$num_messages = ceil(strlen($text) / $max_len);
$part_no = 1;
while ($pos < strlen($text)) {
$ttext = substr($text, $pos, $max_len);
$pos += strlen($ttext);
$udh = pack("cccccc", 5, 0, 3, $msg_sequence, $num_messages, $part_no);
$part_no++;
$res[] = $udh . $ttext;
$this->debug("Split: UDH = ");
for ($i = 0; $i < strlen($udh); $i++) {
$this->debug(ord($udh[$i]) . " ");
}
$this->debug("\n");
$this->debug("Split: $ttext.\n");
}
return $res;
}
function split_message_unicode($text)
{
$this->debug("\n\nIn split_message.\n");
$max_len = 134;
$res = array();
if (mb_strlen($text) <= 140) {
$this->debug("One message: " . mb_strlen($text) . "\n");
$res[] = $text;
return $res;
}
$pos = 0;
$msg_sequence = $this->_message_sequence++;
$num_messages = ceil(mb_strlen($text) / $max_len);
$part_no = 1;
while ($pos < mb_strlen($text)) {
$ttext = mb_substr($text, $pos, $max_len);
$pos += mb_strlen($ttext);
$udh = pack("cccccc", 5, 0, 3, $msg_sequence, $num_messages, $part_no);
$part_no++;
$res[] = $udh . $ttext;
$this->debug("Split: UDH = ");
for ($i = 0; $i < strlen($udh); $i++) {
$this->debug(ord($udh[$i]) . " ");
}
$this->debug("\n");
$this->debug("Split: $ttext.\n");
}
return $res;
}
function unpack2($spec, $data)
{
$res = array();
$specs = explode("/", $spec);
$pos = 0;
reset($specs);
while (list(, $sp) = each($specs)) {
$subject = substr($data, $pos);
$type = substr($sp, 0, 1);
$var = substr($sp, 1);
switch ($type) {
case "N":
$temp = unpack("Ntemp2", $subject);
$res[$var] = $temp["temp2"];
$pos += 4;
break;
case "c":
$temp = unpack("ctemp2", $subject);
$res[$var] = $temp["temp2"];
$pos += 1;
break;
case "a":
$pos2 = strpos($subject, chr(0)) + 1;
$temp = unpack("a{$pos2}temp2", $subject);
$res[$var] = $temp["temp2"];
$pos += $pos2;
break;
}
}
return $res;
}
/**
* #private function
* Reads C style zero padded string from the char array.
* #param $ar - input array
* #param $maxlen - maximum length to read.
* #return readed string.
*/
function getString(&$ar, $maxlen = 255)
{
$s = "";
$i = 0;
do {
$c = array_shift($ar);
if ($c != 0)
$s .= chr($c);
$i++;
} while ($i < $maxlen && $c != 0);
return $s;
}
/**
* #private function
* Prints the binary string as hex bytes.
* #param $maxlen - maximum length to read.
*/
function printHex($pdu)
{
$a = "";
$ar = unpack("C*", $pdu);
foreach ($ar as $v) {
$s = dechex($v);
if (strlen($s) < 2)
$s = "0$s";
$a .= "$s ";
}
return $a . "\n";
}
function debug($str)
{
if ($this->_debug) {
echo $str;
}
}
}
?>
Deliver_sm and Deliver_sm_resp is not working, When i request for delivery report the server is sending me deliver_sm but deliver_sm_resp is not working.
Any body know how to receive delivery report of specific sms, although i have message id of every sms.