Files
config-pacs-docker/nv/html/ApiPacs.php
2025-02-26 14:49:25 +07:00

396 lines
17 KiB
PHP

<?php
/*
* Use Case: Untuk API antara BISONE dengan DCM4CHE PACS Server
* Location: PACS Server /data/docker/nv/html/ApiPacs.php
* Input: JSON
* Proses: HL7 ke DCM4CHE
* Return: JSON
* Version: 1.0
* Date: 2024-12-13
*/
header('Content-Type: application/json');
// Entry point
require_once 'ApiPacs.php';
// Create an instance and route the request
$apiPacs = new ApiPacs();
$apiPacs->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"); // <VT>
define('MLLP_END', "\x1c\x0d"); // <FS><CR>
$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);
}
}