route(); class ApiPacs { private $dcmHost = '128.199.154.150'; private $dcmPort = 2575; public function route() { $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $action = basename($path); if (method_exists($this, $action)) { $this->$action(); } else { http_response_code(404); $this->sys_error("Endpoint not found"); } } public function sendOrder() { if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { $json = file_get_contents('php://input'); $payload = json_decode($json, true); if (!$payload) { http_response_code(400); $this->sys_error("Invalid JSON"); exit; } $hl7json = $this->mapToXml($payload, "XO"); // XO = Send Order $hl7Message = $this->mapToHL7($hl7json); $result = $this->sendHL7($hl7Message, $this->dcmHost, $this->dcmPort); $this->sys_ok([ 'accession_no' => $payload['accession_no'], 'study_instance_uid' => $payload['study_instance_uid'], 'hl7_response' => $result, ], "Successfully sent order"); } catch (\Exception $e) { $this->sys_error($e->getMessage()); exit; } } else { http_response_code(405); $this->sys_error("Method not allowed"); exit; } } public function cancelOrder() { if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { // Get the raw POST data $json = file_get_contents('php://input'); $payload = json_decode($json, true); if (!$payload) { http_response_code(400); $this->sys_error("Invalid JSON"); exit; } $hl7json = $this->mapToXml($payload, "CA"); // CA = Cancel Order $hl7Message = $this->mapToHL7($hl7json); $result = $this->sendHL7($hl7Message, $this->dcmHost, $this->dcmPort); $this->sys_ok([ 'accession_no' => $payload['accession_no'], 'study_instance_uid' => $payload['study_instance_uid'], 'hl7_response' => $result, ], "Successfully canceled order"); } catch (\Exception $e) { $this->sys_error($e->getMessage()); exit; } } else { http_response_code(405); $this->sys_error("Method not allowed"); exit; } } private function mapToXml($payload, $act) { // Extract variables from JSON payload $DepartemenID = isset($payload['departemen_id']) ? $payload['departemen_id'] : ""; $message_seq_id = "2006 - 1010"; $patient_mrn = isset($payload['patient_mrn']) ? $payload['patient_mrn'] : ""; $patient_nm = isset($payload['patient_nm']) ? $payload['patient_nm'] : ""; $patient_birth_dt = isset($payload['patient_birth_dt']) ? $payload['patient_birth_dt'] : ""; $patient_gender = isset($payload['patient_gender']) ? $payload['patient_gender'] : ""; $referring_physician_id = isset($payload['referring_physician_id']) ? $payload['referring_physician_id'] : ""; $referring_physician_nm = isset($payload['referring_physician_nm']) ? $payload['referring_physician_nm'] : ""; $admission_dttm = isset($payload['admission_dttm']) ? $payload['admission_dttm'] : ""; $admission_id = isset($payload['admission_id']) ? $payload['admission_id'] : ""; $ordering_physician_id = isset($payload['ordering_physician_id']) ? $payload['ordering_physician_id'] : ""; $ordering_physician_nm = isset($payload['ordering_physician_nm']) ? $payload['ordering_physician_nm'] : ""; $NamaDepartemen = isset($payload['nama_departemen']) ? $payload['nama_departemen'] : ""; $placer_order_id = isset($payload['placer_order_id']) ? $payload['placer_order_id'] : ""; $filler_order_id = isset($payload['filler_order_id']) ? $payload['filler_order_id'] : ""; $procedure_cd = isset($payload['procedure_cd']) ? $payload['procedure_cd'] : ""; $procedure_nm = isset($payload['procedure_nm']) ? $payload['procedure_nm'] : ""; $order_dttm = isset($payload['order_dttm']) ? $payload['order_dttm'] : ""; $accession_no = isset($payload['accession_no']) ? $payload['accession_no'] : ""; $requested_proc_id = isset($payload['requested_proc_id']) ? $payload['requested_proc_id'] : ""; $scheduled_proc_step_id = isset($payload['scheduled_proc_step_id']) ? $payload['scheduled_proc_step_id'] : ""; $modality_cd = isset($payload['modality_cd']) ? $payload['modality_cd'] : ""; $study_instance_uid = isset($payload['study_instance_uid']) ? $payload['study_instance_uid'] : ""; $scheduled_station_ae = isset($payload['scheduled_station_ae']) ? $payload['scheduled_station_ae'] : ""; $scheduled_station_name = isset($payload['scheduled_station_name']) ? $payload['scheduled_station_name'] : ""; $trxLayananID = isset($payload['trx_layanan_id']) ? $payload['trx_layanan_id'] : ""; $hl7json = [ "MSH" => [ "MSH.3.1" => "HIMS", // Sending Application ID "MSH.4.1" => $DepartemenID, // Sending Facility ID "MSH.5.1" => "ABPACS", // Receiving Application ID "MSH.6.1" => "RAD", // Receiving Facility ID "MSH.7.1" => $this->getCurrentDate("YmdHis"), "MSH.10" => $message_seq_id, /// Messeage Sequence ID ], "PID" => [ "PID.3.1" => $patient_mrn, "PID.5.1" => $patient_nm, "PID.7.1" => date("Ymd", strtotime($patient_birth_dt)), "PID.8.1" => $patient_gender, "PID.10.1" => "2038-8", "PID.11.1" => "", // Street Address "PID.11.2" => "", // Other Designation "PID.11.3" => "", // City "PID.11.4" => "", // State or Province "PID.11.5" => "", // Zip Code "PID.13.1" => "", // Phone Number "PID.18.1" => "", // Patient Account Number ], "PV1" => [ "PV1.8.1" => $referring_physician_id, "PV1.8.2" => $referring_physician_nm, "PV1.44.1" => date("YmdHis", strtotime($admission_dttm)), "PV1.19.1" => $admission_id, // (0038,0010) Admission ID / RegID "PV1.19.4" => "RSAB", // (0038,0011) Issuer of Admission ID ], "ORC" => [ "ORC.1.1" => $act, // Action Code "ORC.2.1" => $placer_order_id, // Placer Order Number "ORC.2.2" => "HIMS", // Placer Order Application Name "ORC.3.1" => $filler_order_id, // Filler Order Number "ORC.3.2" => "", // Filler Order Application Name "ORC.10.1" => "", // User ID created "ORC.10.2" => "", // User last name who created "ORC.10.3" => "", // User first name who created "ORC.12.1" => $ordering_physician_id, // Ordering physician ID "ORC.12.2" => $ordering_physician_nm, // Ordering physician name "ORC.12.3" => "", // Given name "ORC.12.4" => "", // Middle initial "ORC.12.5" => "", // Suffix "ORC.12.6" => "", // Prefix "ORC.13.1" => $NamaDepartemen, // Enterer's point of care "ORC.14.1" => "", // Call back phone number "ORC.15.1" => "", // Order effective datetime "ORC.21.1" => $NamaDepartemen, // Enterer's location ], "OBR" => [ "OBR.2.1" => $placer_order_id, // Placer Order Number "OBR.2.2" => "HIMS", // Placer Order Number Namespace ID "OBR.3.1" => $filler_order_id, // Filler Order Number "OBR.3.2" => "", // Filler Order Number Namespace ID "OBR.4.1" => $procedure_cd, // Service ID "OBR.4.2" => $procedure_nm, // Service Name "OBR.4.3" => "RSABPRC", // Coding for Service Identifier "OBR.4.4" => $procedure_cd, // Alternate Service ID "OBR.4.5" => $procedure_nm, // Alternate Service Name "OBR.4.6" => "L", // Name of Alternate Coding System "OBR.6.1" => date("YmdHis", strtotime($order_dttm)), // Order Request Datetime "OBR.16.1" => $ordering_physician_id, // Ordering physician ID "OBR.16.2" => $ordering_physician_nm, // Ordering physician name "OBR.18.1" => $accession_no, // Accession Number "OBR.19.1" => $trxLayananID, // Requested Procedure ID "OBR.20.1" => $scheduled_proc_step_id, // Scheduled Procedure Step ID "OBR.24.1" => $modality_cd, // Modality Code "OBR.44.1" => $procedure_cd, // Procedure Code "OBR.44.2" => $procedure_nm, // Study Description "OBR.44.3" => "RSAB-PCS", // Procedure Coding System ], "ZDS" => [ "ZDS.1.1" => $study_instance_uid, // (0020,000D) Study Instance UID "ZDS.2.1" => $scheduled_station_ae, // (0040,0001) Scheduled Station AE Title "ZDS.3.1" => $scheduled_station_name, /// (0040,0010) Scheduled Station Name ], "TQ1" => [ "TQ1.7.1" => date("YmdHis", strtotime($order_dttm)), "TQ1.9.1" => "S", // Priority S = Stat, A = ASAP "TQ1.12.1" => "C", // C = Time is Actuation Time ], ]; return $hl7json; } private function mapToHL7($hl7json) { $segments = []; // MSH Segment $segments[] = "MSH|^~\\&|" . $hl7json["MSH"]["MSH.3.1"] . "|" . $hl7json["MSH"]["MSH.4.1"] . "|" . $hl7json["MSH"]["MSH.5.1"] . "|" . $hl7json["MSH"]["MSH.6.1"] . "|" . $hl7json["MSH"]["MSH.7.1"] . "||" . "ORM^O01|" . $hl7json["MSH"]["MSH.10"] . "|P|2.3.1"; // PID Segment $segments[] = "PID|||" . $hl7json["PID"]["PID.3.1"] . "^^^ADT1||" . $hl7json["PID"]["PID.5.1"] . "||" . $hl7json["PID"]["PID.7.1"] . "|" . $hl7json["PID"]["PID.8.1"] . "||" . $hl7json["PID"]["PID.10.1"] . "|" . implode("^", [ $hl7json["PID"]["PID.11.1"], $hl7json["PID"]["PID.11.2"], $hl7json["PID"]["PID.11.3"], $hl7json["PID"]["PID.11.4"], $hl7json["PID"]["PID.11.5"] ]) . "|" . $hl7json["PID"]["PID.13.1"] . "|" . $hl7json["PID"]["PID.18.1"]; // PV1 Segment $segments[] = "PV1||O||||||" . $hl7json["PV1"]["PV1.8.1"] . "^" . $hl7json["PV1"]["PV1.8.2"] . "|||||||||||" . $hl7json["PV1"]["PV1.19.1"] . "^^^" . $hl7json["PV1"]["PV1.19.4"] . "||||||||" . $hl7json["PV1"]["PV1.44.1"]; // ORC Segment $segments[] = "ORC|" . $hl7json["ORC"]["ORC.1.1"] . "|" . $hl7json["ORC"]["ORC.2.1"] . "^" . $hl7json["ORC"]["ORC.2.2"] . "|" . $hl7json["ORC"]["ORC.3.1"] . "^" . $hl7json["ORC"]["ORC.3.2"] . "||||||||" . $hl7json["ORC"]["ORC.10.1"] . "^" . $hl7json["ORC"]["ORC.10.2"] . "^" . $hl7json["ORC"]["ORC.10.3"] . "|||" . $hl7json["ORC"]["ORC.12.1"] . "^" . $hl7json["ORC"]["ORC.12.2"] . "^" . $hl7json["ORC"]["ORC.12.3"] . "^" . $hl7json["ORC"]["ORC.12.4"] . "^" . $hl7json["ORC"]["ORC.12.5"] . "^" . $hl7json["ORC"]["ORC.12.6"] . "|" . $hl7json["ORC"]["ORC.13.1"]; // OBR Segment $segments[] = "OBR|1|" . $hl7json["OBR"]["OBR.2.1"] . "^" . $hl7json["OBR"]["OBR.2.2"] . "|" . $hl7json["OBR"]["OBR.3.1"] . "^" . $hl7json["OBR"]["OBR.3.2"] . "|" . $hl7json["OBR"]["OBR.4.1"] . "^" . $hl7json["OBR"]["OBR.4.2"] . "^" . $hl7json["OBR"]["OBR.4.3"] . "^" . $hl7json["OBR"]["OBR.4.4"] . "^" . $hl7json["OBR"]["OBR.4.5"] . "^" . $hl7json["OBR"]["OBR.4.6"] . "||" . $hl7json["OBR"]["OBR.6.1"] . "||||||||" . $hl7json["OBR"]["OBR.16.1"] . "^" . $hl7json["OBR"]["OBR.16.2"] . "||||" . $hl7json["OBR"]["OBR.18.1"] . "|" . $hl7json["OBR"]["OBR.19.1"] . "|" . $hl7json["OBR"]["OBR.20.1"] . "|||||||||" . $hl7json["OBR"]["OBR.24.1"] . "|||||||" . $hl7json["OBR"]["OBR.44.1"] . "^" . $hl7json["OBR"]["OBR.44.2"] . "^" . $hl7json["OBR"]["OBR.44.3"]; // ZDS Segment $segments[] = "ZDS|" . $hl7json["ZDS"]["ZDS.1.1"] . "^100^Application^DICOM|" . $hl7json["ZDS"]["ZDS.2.1"] . "|" . $hl7json["ZDS"]["ZDS.3.1"]; // TQ1 Segment $segments[] = "TQ1|||||||" . $hl7json["TQ1"]["TQ1.7.1"] . "||" . $hl7json["TQ1"]["TQ1.9.1"] . "|||" . $hl7json["TQ1"]["TQ1.12.1"]; // Join all segments with newline return implode("\n", $segments); } private function sendHL7($hl7Message, $host, $port) { // MLLP delimiters define('MLLP_START', "\x0b"); // define('MLLP_END', "\x1c\x0d"); // $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket === false) { $this->sys_error("Socket creation failed: " . socket_strerror(socket_last_error())); exit; } $result = socket_connect($socket, $host, $port); if ($result === false) { $this->sys_error("Connection failed: " . socket_strerror(socket_last_error())); exit; } // Wrap message in MLLP container $mlllpMessage = MLLP_START . $hl7Message . MLLP_END; // Send message $sentBytes = socket_write($socket, $mlllpMessage, strlen($mlllpMessage)); if ($sentBytes === false) { $this->sys_error("Send failed: " . socket_strerror(socket_last_error())); exit; } $response = ''; socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 5, "usec" => 0]); // Set timeout while (($buf = socket_read($socket, 1024))) { $response .= $buf; if (strpos($response, MLLP_END)) { break; } } $returned = ''; if (strpos($response, "MSA|AA") !== false) { $returned = "Application Accepted"; // Acknowledgment Accepted } elseif (strpos($response, "MSA|AR") !== false) { $returned = "Application Rejected"; // Acknowledgment Rejected } elseif (strpos($response, "MSA|AE") !== false) { $returned = "Application Error"; // Application Error } else { $returned = "Unknown Response"; // In case none of the expected segments are found } return $returned; } public function getCurrentDate($format) { return date($format); } public function sys_ok($data, $message = "") { $result = array( 'status' => 'OK', 'message' => $message, 'data' => $data ); echo json_encode($result); } public function sys_error($message) { $result = array( 'status' => 'ERROR', 'message' => $message, 'data' => '' ); echo json_encode($result); } }