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 |