PHP SMPP delivery report deliver_sm_resp not receiving? - php

<?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.

Related

Torrent with Laravel using Laratracker

I am implementing the laratracker , a bittorrent tracker built in laravel, but unable to start the download. Only one peer appears to be seeding, Sometimes it is saying "Connecting to peers" and remains at it is. The code which i am using is :
<?php
namespace App\Http\Controllers\Announce;
use App\Helpers\BencodeHelper;
use App\Models\Peer;
use App\Models\PeerTorrent;
use App\Models\Torrent;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Log;
class AnnounceController extends Controller
{
const __INTERVAL = 1000;
const __TIMEOUT = 120;
const __INTERVAL_MIN = 60;
const __MAX_PPR = 20;
public function announce(Request $request)
{
Log::info($request->fullUrl());
$status = 200;
$content = "";
$passkey = Input::get('passkey');
$peer_id = Input::get('peer_id');
$port = Input::get('port');
$info_hash = Input::get('info_hash');
$downloaded = Input::get('uploaded') ? intval(Input::get('uploaded')) : 0;
$uploaded = Input::get('uploaded') ? intval(Input::get('uploaded')) : 0;
$left = Input::get('left') ? intval(Input::get('left')) : 0;
$compact = Input::get('compact') ? intval(Input::get('compact')) : 0;
$no_peer_id = Input::get('no_peer_id') ? intval(Input::get('no_peer_id')) : 0;
$ipAddress = '';
// Check for X-Forwarded-For headers and use those if found
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && ('' !== trim($_SERVER['HTTP_X_FORWARDED_FOR']))) {
$ipAddress = (trim($_SERVER['HTTP_X_FORWARDED_FOR']));
} else {
if (isset($_SERVER['REMOTE_ADDR']) && ('' !== trim($_SERVER['REMOTE_ADDR']))) {
$ipAddress = (trim($_SERVER['REMOTE_ADDR']));
}
}
$port = $_SERVER['REMOTE_PORT'];
/*if(!$port || !ctype_digit($port) || intval($port) < 1 || intval($port) > 65535)
{
$content = BencodeHelper::track("Invalid client port.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
if ($port == 999 && substr($peer_id, 0, 10) == '-TO0001-XX') {
die("d8:completei0e10:incompletei0e8:intervali600e12:min intervali60e5:peersld2:ip12:72.14.194.184:port3:999ed2:ip11:72.14.194.14:port3:999ed2:ip12:72.14.194.654:port3:999eee");
}*/
if (!$passkey) {
$content = BencodeHelper::track("Missing passkey.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$torrent = Torrent::getByInfoHash(sha1($info_hash));
if (!$torrent || $torrent == null) {
$content = "Torrent not registered with this tracker.";
$status = 404;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$user = User::has('passkeys', '=', $passkey)->get();
if ($user == null) {
$content = BencodeHelper::track("Invalid passkey.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$peer = Peer::getByHashAndPasskey(bin2hex($peer_id), $passkey);
if ($peer == null) {
$peer = Peer::create([
'hash' => bin2hex($peer_id),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'ip_address' => $ipAddress,
'passkey' => $passkey,
'port' => $port
]);
}
if (!$info_hash || strlen($info_hash) != 20) {
$content = BencodeHelper::track("Invalid info_hash.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$peer_torrent = PeerTorrent::getByPeerAndTorrent($peer, $torrent);
if ($peer_torrent == null) {
$peer_torrent = PeerTorrent::create([
'peer_id' => $peer->id,
'torrent_id' => $torrent->id,
'uploaded' => $uploaded,
'downloaded' => $downloaded,
'left' => $left,
'stopped' => false
]);
} else {
$peer_torrent->uploaded = $uploaded;
$peer_torrent->downloaded = $downloaded;
$peer_torrent->left = $left;
$peer_torrent->save();
}
$seeders = $torrent->getSeedersCount();
$leechers = $torrent->getLeechersCount();
$resp = "";
if ($compact != 1) {
$resp = "d" . $this->benc_str("interval") . "i" . AnnounceController::__INTERVAL . "e" . $this->benc_str("peers") . "l";
} else {
$resp = "d" . $this->benc_str("interval") . "i" . AnnounceController::__INTERVAL . "e" . $this->benc_str("min interval") . "i" . 300 . "e5:" . "peers";
}
$peer = array();
$peer_num = 0;
foreach ($torrent->getPeersArray() as $row) {
if ($compact != 1) {
if ($row["peer_id"] === $peer->hash) {
continue;
}
$resp .= "d" . $this->benc_str("ip") . $this->benc_str($row['ip']);
if ($no_peer_id == 0) {
$resp .= $this->benc_str("peer id") . $this->benc_str($row["peer_id"]);
}
$resp .= $this->benc_str("port") . "i" . $row["port"] . "e" . "e";
} else {
$peer_ip = explode('.', $row["ip"]);
$peer_ip = pack("C*", $peer_ip[0], $peer_ip[1], $peer_ip[2], $peer_ip[3]);
$peer_port = pack("n*", (int)$row["port"]);
$time = intval((time() % 7680) / 60);
if ($left == 0) {
$time += 128;
}
$time = pack("C", $time);
$peer[] = $time . $peer_ip . $peer_port;
$peer_num++;
}
}
if ($compact != 1) {
$resp .= "ee";
} else {
$o = "";
for ($i = 0; $i < $peer_num; $i++) {
$o .= substr($peer[$i], 1, 6);
}
$resp .= strlen($o) . ':' . $o . 'e';
}
$this->benc_resp_raw($resp);
}
public function benc_resp($d)
{
return $this->benc_resp_raw($this->benc(array('type' => 'dictionary', 'value' => $d)));
}
public function benc_resp_raw($x)
{
header("Content-Type: text/plain");
header("Pragma: no-cache");
if ($_SERVER['HTTP_ACCEPT_ENCODING'] == 'gzip') {
header("Content-Encoding: gzip");
echo gzencode($x, 9, FORCE_GZIP);
} else {
echo $x;
}
}
function benc($obj)
{
if (!is_array($obj) || !isset($obj["type"]) || !isset($obj["value"]))
return;
$c = $obj["value"];
switch ($obj["type"]) {
case "string":
return $this->benc_str($c);
case "integer":
return $this->benc_int($c);
case "list":
return $this->benc_list($c);
case "dictionary":
return $this->benc_dict($c);
default:
return;
}
}
public function benc_str($s)
{
return strlen($s) . ":$s";
}
public function benc_int($i)
{
return "i" . $i . "e";
}
public function benc_list($a)
{
$s = "l";
foreach ($a as $e) {
$s .= $this->benc($e);
}
$s .= "e";
return $s;
}
public function benc_dict($d)
{
$s = "d";
$keys = array_keys($d);
sort($keys);
foreach ($keys as $k) {
$v = $d[$k];
$s .= $this->benc_str($k);
$s .= $this->benc($v);
}
$s .= "e";
return $s;
}
public function hex2bin($hex)
{
$r = '';
for ($i = 0; $i < strlen($hex); $i += 2) {
$r .= chr(hexdec($hex{$i} . $hex{($i + 1)}));
}
return $r;
}
}
<?php
Not sure what to add or modify to the code to get it working . Help appreciated for the solution .

base64 in PHP Otp Library

I trying to make some simple library for encrypting files in PHP with OTP method. My problem is that some chars in decrypted code are different than original. I worked on it almost one week but without result. Is there problem with base64 chars or with encoding/decoding mechanism ?
Many thanks for the answers.
final class Otp
{
private static $charSet = array('+','/','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z');
public static function encryptFile($originalFilePath, $encryptedFilePath, $keyFilePath)
{
if(!self::existsFile($keyFilePath) || !self::existsFile($encryptedFilePath)) {
if($originalFileData = self::existsFile($originalFilePath)) {
$originalFileBase64Data = base64_encode($originalFileData);
$originalFileBase64DataLength = strlen($originalFileBase64Data) - 1;
$originalFileBase64DataArray = str_split($originalFileBase64Data);
$encryptedData = NULL;
$encryptedDataKey = NULL;
for ($i = 0; $i <= $originalFileBase64DataLength; $i++) {
$randKey = rand(0, sizeOf(self::$charSet) - 1);
$arrayKey = array_search($originalFileBase64DataArray[$i], self::$charSet);
if($randKey > $arrayKey) {
$str = '-' . ($randKey - $arrayKey);
} elseif($randKey < $arrayKey) {
$str = ($randKey + $arrayKey);
} else {
$str = $randKey;
}
$encryptedData .= self::$charSet[$randKey];
$encryptedDataKey .= $str. ';';
}
$encryptedDataString = $encryptedData;
$encryptedDataKeyString = $encryptedDataKey;
if(!self::existsFile($keyFilePath)) {
file_put_contents($keyFilePath, $encryptedDataKeyString);
}
if(!self::existsFile($encryptedFilePath)) {
file_put_contents($encryptedFilePath, $encryptedDataString);
}
return 'OK';
} else {
return 'Source file not exists';
}
} else {
return 'Encrypted data already exists';
}
}
public static function decryptFile($encryptedFilePath, $keyFilePath, $decryptedFilePath)
{
$keyFileData = self::existsFile($keyFilePath);
$encryptedFileData = self::existsFile($encryptedFilePath);
$encryptedFileDataLength = strlen($encryptedFileData) - 1;
if($encryptedFileData && $keyFileData) {
$encryptedFileDataArray = str_split($encryptedFileData);
$keyFileDataArray = explode(';', $keyFileData);
$decryptedData = NULL;
for ($i = 0; $i <= $encryptedFileDataLength; $i++) {
$poziciaaktualneho = array_search($encryptedFileDataArray[$i], self::$charSet);
$poziciasifrovana = $keyFileDataArray[$i];
if($poziciasifrovana < 0) {
$move = $poziciasifrovana + $poziciaaktualneho;
} elseif($poziciasifrovana > 0) {
$move = $poziciasifrovana - $poziciaaktualneho;
} else {
$move = '0';
}
$decryptedData .= self::$charSet[$move];
}
if(!self::existsFile($decryptedFilePath)) {
file_put_contents($decryptedFilePath, base64_decode($decryptedData));
return 'OK';
} else {
return 'Decrypted data already exists';
}
}
}
private static function existsFile($filePath)
{
$fileData = #file_get_contents($filePath);
if($fileData) {
return $fileData;
}
return FALSE;
}
}
$originalFilePath = 'original.jpg';
$keyFilePath = 'Otp_Key_' . $originalFilePath;
$encryptedFilePath = 'Otp_Data_' . $originalFilePath;
$decryptedFilePath = 'Otp_Decrypted_' . $originalFilePath;
echo Otp::encryptFile($originalFilePath, $encryptedFilePath, $keyFilePath);
echo Otp::decryptFile($encryptedFilePath, $keyFilePath, $decryptedFilePath);
The problem seems to be only happening when $poziciaaktualneho is equal to $poziciasifrovana and so by adding another if statement on line 78 to check for this and instead set $move equal to $poziciasifrovana I was able to fix the problem. The below script should work:
final class Otp
{
private static $charSet = array('+','/','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z');
public static function encryptFile($originalFilePath, $encryptedFilePath, $keyFilePath)
{
if(!self::existsFile($keyFilePath) || !self::existsFile($encryptedFilePath)) {
if($originalFileData = self::existsFile($originalFilePath)) {
$originalFileBase64Data = base64_encode($originalFileData);
$originalFileBase64DataLength = strlen($originalFileBase64Data) - 1;
$originalFileBase64DataArray = str_split($originalFileBase64Data);
$encryptedData = NULL;
$encryptedDataKey = NULL;
for ($i = 0; $i <= $originalFileBase64DataLength; $i++) {
$randKey = rand(0, sizeOf(self::$charSet) - 1);
$arrayKey = array_search($originalFileBase64DataArray[$i], self::$charSet);
if($randKey > $arrayKey) {
$str = '-' . ($randKey - $arrayKey);
} elseif($randKey < $arrayKey) {
$str = ($randKey + $arrayKey);
} else {
$str = $randKey;
}
$encryptedData .= self::$charSet[$randKey];
$encryptedDataKey .= $str. ';';
}
$encryptedDataString = $encryptedData;
$encryptedDataKeyString = $encryptedDataKey;
if(!self::existsFile($keyFilePath)) {
file_put_contents($keyFilePath, $encryptedDataKeyString);
}
if(!self::existsFile($encryptedFilePath)) {
file_put_contents($encryptedFilePath, $encryptedDataString);
}
return 'OK';
} else {
return 'Source file not exists';
}
} else {
return 'Encrypted data already exists';
}
}
public static function decryptFile($encryptedFilePath, $keyFilePath, $decryptedFilePath)
{
$keyFileData = self::existsFile($keyFilePath);
$encryptedFileData = self::existsFile($encryptedFilePath);
$encryptedFileDataLength = strlen($encryptedFileData) - 1;
if($encryptedFileData && $keyFileData) {
$encryptedFileDataArray = str_split($encryptedFileData);
$keyFileDataArray = explode(';', $keyFileData);
$decryptedData = NULL;
for ($i = 0; $i <= $encryptedFileDataLength; $i++) {
$poziciaaktualneho = array_search($encryptedFileDataArray[$i], self::$charSet);
$poziciasifrovana = $keyFileDataArray[$i];
if ($poziciasifrovana == $poziciaaktualneho) {
$move = $poziciasifrovana;
} elseif($poziciasifrovana < 0) {
$move = $poziciasifrovana + $poziciaaktualneho;
} elseif($poziciasifrovana > 0) {
$move = $poziciasifrovana - $poziciaaktualneho;
} else {
$move = '0';
}
$decryptedData .= self::$charSet[$move];
}
if(!self::existsFile($decryptedFilePath)) {
file_put_contents($decryptedFilePath, base64_decode($decryptedData));
return 'OK';
} else {
return 'Decrypted data already exists';
}
}
}
private static function existsFile($filePath)
{
$fileData = #file_get_contents($filePath);
if($fileData) {
return $fileData;
}
return FALSE;
}
}
$originalFilePath = 'original.jpg';
$keyFilePath = 'Otp_Key_' . $originalFilePath;
$encryptedFilePath = 'Otp_Data_' . $originalFilePath;
$decryptedFilePath = 'Otp_Decrypted_' . $originalFilePath;
echo Otp::encryptFile($originalFilePath, $encryptedFilePath, $keyFilePath);
echo Otp::decryptFile($encryptedFilePath, $keyFilePath, $decryptedFilePath);
Warning: I would not recommend using my solution in an enterprise setting if at all since I do not know why this fixes your script or what was
originally wrong with it and it is most likely not air tight.

BitTorrent: Download not starting

I am trying to implement a bittorrent tracker in Laravel. However, I am stuck at the moment as the download won't start. There is one peer which it appears to be seeding and I am 100% sure that it is connectable. But, when I run a second client on a different machine, the download won't start. It is stuck at "Connecting to peers" (uTorrent).
From the tracker I am sending the following response when the client makes an announce:
d8:intervali1000e12:min intervali300e5:peers18:�ؤ�i�ؑ�XÚJU�6e
In the downloading client I have the following data:
Here's my announce code:
<?php
namespace App\Http\Controllers\Announce;
use App\Helpers\BencodeHelper;
use App\Models\Peer;
use App\Models\PeerTorrent;
use App\Models\Torrent;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Log;
class AnnounceController extends Controller
{
const __INTERVAL = 1000;
const __TIMEOUT = 120;
const __INTERVAL_MIN = 60;
const __MAX_PPR = 20;
public function announce(Request $request)
{
Log::info($request->fullUrl());
$status = 200;
$content = "";
$passkey = Input::get('passkey');
$peer_id = Input::get('peer_id');
$port = Input::get('port');
$info_hash = Input::get('info_hash');
$downloaded = Input::get('uploaded') ? intval(Input::get('uploaded')) : 0;
$uploaded = Input::get('uploaded') ? intval(Input::get('uploaded')) : 0;
$left = Input::get('left') ? intval(Input::get('left')) : 0;
$compact = Input::get('compact') ? intval(Input::get('compact')) : 0;
$no_peer_id = Input::get('no_peer_id') ? intval(Input::get('no_peer_id')) : 0;
$ipAddress = '';
// Check for X-Forwarded-For headers and use those if found
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && ('' !== trim($_SERVER['HTTP_X_FORWARDED_FOR']))) {
$ipAddress = (trim($_SERVER['HTTP_X_FORWARDED_FOR']));
} else {
if (isset($_SERVER['REMOTE_ADDR']) && ('' !== trim($_SERVER['REMOTE_ADDR']))) {
$ipAddress = (trim($_SERVER['REMOTE_ADDR']));
}
}
$port = $_SERVER['REMOTE_PORT'];
/*if(!$port || !ctype_digit($port) || intval($port) < 1 || intval($port) > 65535)
{
$content = BencodeHelper::track("Invalid client port.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
if ($port == 999 && substr($peer_id, 0, 10) == '-TO0001-XX') {
die("d8:completei0e10:incompletei0e8:intervali600e12:min intervali60e5:peersld2:ip12:72.14.194.184:port3:999ed2:ip11:72.14.194.14:port3:999ed2:ip12:72.14.194.654:port3:999eee");
}*/
if (!$passkey) {
$content = BencodeHelper::track("Missing passkey.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$torrent = Torrent::getByInfoHash(sha1($info_hash));
if (!$torrent || $torrent == null) {
$content = "Torrent not registered with this tracker.";
$status = 404;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$user = User::has('passkeys', '=', $passkey)->get();
if ($user == null) {
$content = BencodeHelper::track("Invalid passkey.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$peer = Peer::getByHashAndPasskey(bin2hex($peer_id), $passkey);
if ($peer == null) {
$peer = Peer::create([
'hash' => bin2hex($peer_id),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'ip_address' => $ipAddress,
'passkey' => $passkey,
'port' => $port
]);
}
if (!$info_hash || strlen($info_hash) != 20) {
$content = BencodeHelper::track("Invalid info_hash.");
$status = 401;
return (new Response(AnnounceController::track($content), $status))
->header('Content-Type', $value);
}
$peer_torrent = PeerTorrent::getByPeerAndTorrent($peer, $torrent);
if ($peer_torrent == null) {
$peer_torrent = PeerTorrent::create([
'peer_id' => $peer->id,
'torrent_id' => $torrent->id,
'uploaded' => $uploaded,
'downloaded' => $downloaded,
'left' => $left,
'stopped' => false
]);
} else {
$peer_torrent->uploaded = $uploaded;
$peer_torrent->downloaded = $downloaded;
$peer_torrent->left = $left;
$peer_torrent->save();
}
$seeders = $torrent->getSeedersCount();
$leechers = $torrent->getLeechersCount();
$resp = "";
if ($compact != 1) {
$resp = "d" . $this->benc_str("interval") . "i" . AnnounceController::__INTERVAL . "e" . $this->benc_str("peers") . "l";
} else {
$resp = "d" . $this->benc_str("interval") . "i" . AnnounceController::__INTERVAL . "e" . $this->benc_str("min interval") . "i" . 300 . "e5:" . "peers";
}
$peer = array();
$peer_num = 0;
foreach ($torrent->getPeersArray() as $row) {
if ($compact != 1) {
if ($row["peer_id"] === $peer->hash) {
continue;
}
$resp .= "d" . $this->benc_str("ip") . $this->benc_str($row['ip']);
if ($no_peer_id == 0) {
$resp .= $this->benc_str("peer id") . $this->benc_str($row["peer_id"]);
}
$resp .= $this->benc_str("port") . "i" . $row["port"] . "e" . "e";
} else {
$peer_ip = explode('.', $row["ip"]);
$peer_ip = pack("C*", $peer_ip[0], $peer_ip[1], $peer_ip[2], $peer_ip[3]);
$peer_port = pack("n*", (int)$row["port"]);
$time = intval((time() % 7680) / 60);
if ($left == 0) {
$time += 128;
}
$time = pack("C", $time);
$peer[] = $time . $peer_ip . $peer_port;
$peer_num++;
}
}
if ($compact != 1) {
$resp .= "ee";
} else {
$o = "";
for ($i = 0; $i < $peer_num; $i++) {
$o .= substr($peer[$i], 1, 6);
}
$resp .= strlen($o) . ':' . $o . 'e';
}
$this->benc_resp_raw($resp);
}
public function benc_resp($d)
{
return $this->benc_resp_raw($this->benc(array('type' => 'dictionary', 'value' => $d)));
}
public function benc_resp_raw($x)
{
header("Content-Type: text/plain");
header("Pragma: no-cache");
if ($_SERVER['HTTP_ACCEPT_ENCODING'] == 'gzip') {
header("Content-Encoding: gzip");
echo gzencode($x, 9, FORCE_GZIP);
} else {
echo $x;
}
}
function benc($obj)
{
if (!is_array($obj) || !isset($obj["type"]) || !isset($obj["value"]))
return;
$c = $obj["value"];
switch ($obj["type"]) {
case "string":
return $this->benc_str($c);
case "integer":
return $this->benc_int($c);
case "list":
return $this->benc_list($c);
case "dictionary":
return $this->benc_dict($c);
default:
return;
}
}
public function benc_str($s)
{
return strlen($s) . ":$s";
}
public function benc_int($i)
{
return "i" . $i . "e";
}
public function benc_list($a)
{
$s = "l";
foreach ($a as $e) {
$s .= $this->benc($e);
}
$s .= "e";
return $s;
}
public function benc_dict($d)
{
$s = "d";
$keys = array_keys($d);
sort($keys);
foreach ($keys as $k) {
$v = $d[$k];
$s .= $this->benc_str($k);
$s .= $this->benc($v);
}
$s .= "e";
return $s;
}
public function hex2bin($hex)
{
$r = '';
for ($i = 0; $i < strlen($hex); $i += 2) {
$r .= chr(hexdec($hex{$i} . $hex{($i + 1)}));
}
return $r;
}
}
I am not quite sure what am I missing here.
Maybe it's because you constantly set
->header('Content-Type', $value);
without ever setting $value? So the "Announce-Response" is malformed?
$port = $_SERVER['REMOTE_PORT'];
I think the problem is that the tracker instead of register the port that the connecting peer sends in the announce string, the tracker register the remote port that the peer is connecting from.
That is almost certainly the wrong port to use.

WebSocket connection with PHP

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);
?>

phpMQTT publish not working

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

Categories