View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000627 | file | General | public | 2025-02-26 18:33 | 2025-03-10 20:22 |
| Reporter | madprofessor | Assigned To | christos | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Platform | Linux | OS | debian | OS Version | 12 |
| Product Version | 5.44 | ||||
| Fixed in Version | HEAD | ||||
| Summary | 0000627: file shows php script as C++ source | ||||
| Description | testfile is a php script. # ls -l testfile -rwxr-xr-x 1 root root 9396 Jan 13 09:48 testfile root@smsapi-lon1a:/tmp# file testfile testfile: C++ source, ASCII text | ||||
| Steps To Reproduce | do as in description | ||||
| Tags | No tags attached. | ||||
|
|
testfile (9,396 bytes)
#!/usr/bin/php
<?php
// Am using php for this because Perl's Net::RabbitMQ intermittently (and very often) generated
// "frame read error" errors (or words to that effect) when trying to consume from the queue. I
// couldnt' figure out why, but that made it very unreliable.
namespace
{
print "WORKER STDOUT\n";
error_log("WORKER STDERR");
// define this so that the callbacks from the service proiders get the proper versioned path to the callback endpoint:
define ('KREST_ENDPOINT_PATH_PREFIX', '/v1');
$parent_dir = dirname(__DIR__);
set_include_path("$parent_dir/lib:".get_include_path());
require_once 'ClassAutoloader.php';
require_once "$parent_dir/vendor/autoload.php";
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$provider_key = 'sinch';
$provider_keyword = Config::Get("RabbitMQ/sms/providers/$provider_key/keyword");
$providerID = \Provider::GetID($provider_keyword);
$MB_queue_name = Config::Get("RabbitMQ/sms/providers/$provider_key/queue_name");
$MB_host = Config::Get('RabbitMQ/host');
$MB_port = Config::Get('RabbitMQ/port');
$MB_heartbeat_interval = Config::GetOptional('RabbitMQ/heartbeat_interval') ?? 0;
$MB_user = Config::Get('RabbitMQ/sms/consume_user');
$MB_pass = Config::Get('RabbitMQ/sms/consume_pass');
$MB_vhost = Config::Get('RabbitMQ/sms/vhost');
while (1)
{
try
{
print "Connecting to database\n";
$db = DBH::RW();
print "Connected to database\n";
print "Connecting to $MB_host, vhost=$MB_vhost\n";
$MQconnection = new AMQPStreamConnection
(
host: $MB_host,
port: $MB_port,
user: $MB_user,
password: $MB_pass,
vhost: $MB_vhost,
heartbeat: $MB_heartbeat_interval,
keepalive: true
);
print "Connected to $MB_host, vhost=$MB_vhost\n";
$channel = $MQconnection->channel();
$channel->basic_qos
(
prefetch_size: 0,
prefetch_count: 1,
a_global: false
);
$message_handler = function (\PhpAmqpLib\Message\AMQPMessage $msg) use ($db)
{ return submitSMS($db, $msg); };
$channel->basic_consume
(
queue: $MB_queue_name,
consumer_tag: '',
no_local: false,
no_ack: false,
exclusive: false,
nowait: false,
callback: $message_handler,
ticket: NULL,
arguments:
[
//'count' => 1,
]
);
print "Consuming RabbitMQ queue $MB_queue_name\n";
$channel->consume();
print "Finished consuming from RabbitMQ\n";
}
catch (\Exception $e)
{
error_log("Caught ".get_class($e).": ".$e->getMessage());
sleep(10);
}
}
$channel->close();
$MQconnection->close();
// function barf(string $msg)
// { throw new \Exception($msg); }
function submitSMS(\DBO $db, \PhpAmqpLib\Message\AMQPMessage $MBmsg)
{
$msgstruct = NULL;
try
{
$db->beginTransaction();
echo date('H:i:s').' received ', $MBmsg->body, "\n";
$msg = new \MsgQtoSMSC\MsgOutParsed($MBmsg->body);
# get the records locked to this transaction:
$recipIDs = $msg->recipIDs;
$recipIDCSVQ = $db->quoteListCSV($recipIDs);
$lockedIDs = $db->selectAllColumn("SELECT ID FROM message_out_recipients WHERE ID IN ($recipIDCSVQ) FOR UPDATE");
if (count($lockedIDs) !== count($recipIDs))
{ throw new TempError(sprintf("Failed to lock all rows; expected %d but locked %d", count($recipIDs), count($lockedIDs))); }
$submit_res = \LibSMS\Message::SubmitToSMSC
(
from: $msg->from,
to: $msg->to,
body: $msg->body,
internal_messageID: $msg->internal_messageID,
clusterID: $msg->clusterID,
expires_at: $msg->expires_at
);
if (!$submit_res)
{
$db->rollback();
error_log("Failed to submit SMS message to SMSC");
return false;
}
$query = "UPDATE message_out_recipients SET ".
"status='submitted',".
"statusCode=102,".
"submitted_at_ms=UNIX_TIMESTAMP_MS(),".
"service_providerID=?,".
"provider_messageID=? ".
"WHERE messageID=? ".
"AND status IN ('queued','pending') ". # should never be pending, but just in case that bit went wrong
"AND ID IN ($recipIDCSVQ)";
$db->exec($query, $submit_res['service_providerID'], $submit_res['provider_messageID'], $msg->internal_messageID);
$MBmsg->ack(multiple: false);
$db->commit();
}
catch (MsgQtoSMSC\TempError $e)
{
$db->rollback();
error_log("Temp sms submit failure: ".$e->getMessage());
}
catch (MsgQtoSMSC\PermError $e)
{
$db->rollback();
error_log("Permanent sms submit failure: ".$e->getMessage());
error_log("Need to write to failure queue, or something");
$MBmsg->ack(multiple: false);
}
catch (Exception $e)
{
$db->rollback();
error_log("Error submitting message: ".$e->getMessage());
}
}
} // namespace
namespace MsgQtoSMSC
{
class MsgOutParsed
{
private $props = [];
public function __construct(string $json_src)
{
try
{
$struct = json_decode
(
$json_src,
associative: false,
flags: JSON_THROW_ON_ERROR
);
}
catch (\Exception $e)
{ throw new PermError("Unable to decode message: ".$e->getMessage()."\nBODY=$json_src"); }
foreach (['internal_messageID','type','direction','from','to','body','clusterID','recipIDs','expires_at'] as $reqprop)
{
if (!isset($struct->$reqprop))
{ throw new PermError(get_class().": src property missing or not set: $reqprop"); }
}
if ($struct->type !== 'sms')
{ throw new PermError("Message type is not 'sms'; it is '{$struct->type}'"); }
if ($struct->direction !== 'out')
{ throw new PermError("Message direction is not 'out'; it is '{$struct->direction}'"); }
foreach (['internal_messageID','clusterID'] as $intprop)
{
if (!is_numeric($struct->$intprop) || !preg_match('/^[0-9]+$/', $struct->$intprop))
{ throw new PermError(get_class().": src property $intprop non-valid: {$struct->$intprop}"); }
}
foreach (['to','recipIDs'] as $non_empty_arrayprop)
{
if (!is_array($struct->$non_empty_arrayprop))
{ throw new PermError(get_class().": src property $non_empty_arrayprop is not an array"); }
if (empty($struct->$non_empty_arrayprop))
{ throw new PermError(get_class().": src property $non_empty_arrayprop is empty"); }
}
foreach ($struct->recipIDs as $recipID)
{
if (!preg_match('/^[0-9]+$/', $recipID))
{ throw new PermError("Non-valid recipID in source data: $recipID"); }
}
try
{
foreach ($struct->to as $i=>&$recip)
{ $recip = new \TelNum($recip); }
}
catch (\Exception $e)
{ throw new PermError("Bad recipient number at offset $i: $recip"); }
try
{ $struct->expires_at = new \Timestamp($struct->expires_at); }
catch (\Exception $e)
{
error_log("Bad src struct: ".print_r($struct,1));
throw new PermError("Bad expires_at value: {$struct->expires_at}");
}
$this->props = (array) $struct;
}
public function __get($prop)
{
if (($val = $this->props[$prop] ?? NULL) !== NULL)
{ return $val; }
if (array_key_exists($prop, $this->props))
{ return NULL; }
throw new \Exception("No such property: ".get_class($this)."->$prop");
}
}
class TempError extends \Exception
{
}
class PermError extends \Exception
{
}
}
|
|
|
fixed, thanks! |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2025-02-26 18:33 | madprofessor | New Issue | |
| 2025-02-26 18:33 | madprofessor | File Added: testfile | |
| 2025-03-10 20:22 | christos | Assigned To | => christos |
| 2025-03-10 20:22 | christos | Status | new => assigned |
| 2025-03-10 20:22 | christos | Status | assigned => resolved |
| 2025-03-10 20:22 | christos | Resolution | open => fixed |
| 2025-03-10 20:22 | christos | Fixed in Version | => HEAD |
| 2025-03-10 20:22 | christos | Note Added: 0004185 |