Files
BE_IBL/application/controllers/tools/Birt_proxy.php
sas.fajri d7930d5dbc FHM31052601IBL - BIRT proxy + 5 SP header decrypt via patient_print_cache
- Birt_proxy.php: decrypt PII sebelum call BIRT, cache 5 menit
- 5 SP (hasil_header, _2, _eng, fo_001, card_patient): tambah LEFT JOIN
  ke patient_print_cache dengan COALESCE fallback ke masked data
- SP signature tidak berubah, .rptdesign tidak perlu diupdate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 17:33:02 +07:00

194 lines
6.5 KiB
PHP

<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Birt_proxy — PHP proxy untuk semua BIRT report call
*
* Flow:
* 1. Terima request dari frontend (report_code + params)
* 2. Decrypt patient PII dari _enc
* 3. INSERT ke patient_print_cache
* 4. Call BIRT via file_get_contents (internal)
* 5. DELETE cache
* 6. Stream PDF ke frontend
*
* Endpoint: POST /tools/birt_proxy/stream
* Params : report_code, PT_OrderHeaderID, PUsername, (optional) PID_patient
*/
class Birt_proxy extends MY_Controller
{
private $db_onedev;
private $birt_base = 'http://localhost:8080';
public function __construct()
{
parent::__construct();
$this->db_onedev = $this->load->database('onedev', true);
$this->load->library('ibl_encryptor');
}
// POST /tools/birt_proxy/stream
public function stream()
{
if (!$this->isLogin) {
$this->sys_error('Invalid Token');
return;
}
$prm = $this->sys_input;
$report_code = $prm['report_code'] ?? '';
$order_id = intval($prm['PT_OrderHeaderID'] ?? 0);
$username = $prm['PUsername'] ?? ($this->sys_user['userName'] ?? 'system');
$tm = round(microtime(true) * 1000);
if (!$report_code) {
$this->sys_error('report_code wajib diisi');
return;
}
// 1. Ambil URL template dari print_transaction
$row = $this->db_onedev->query(
"SELECT Print_TransactionUrl FROM print_transaction WHERE Print_TransactionCode = ? LIMIT 1",
[$report_code]
)->row_array();
if (!$row) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$url = $row['Print_TransactionUrl'];
$url = str_replace('PT_OrderHeaderID', $order_id, $url);
$url = str_replace('PUsername', urlencode($username), $url);
$url = str_replace('TS', $tm, $url);
// 2. Decrypt patient PII dan populate cache
$cache_id = null;
if ($order_id > 0) {
$cache_id = $this->_populate_cache($order_id);
}
// 3. Build full BIRT URL dan fetch PDF
$full_url = $this->birt_base . $url;
$context = stream_context_create([
'http' => [
'timeout' => 120,
'method' => 'GET',
]
]);
$pdf = @file_get_contents($full_url, false, $context);
// 4. Hapus cache
if ($cache_id) {
$this->db_onedev->query(
"DELETE FROM patient_print_cache WHERE ppc_id = ?",
[$cache_id]
);
}
if ($pdf === false) {
$this->sys_error('Gagal generate report dari BIRT server');
return;
}
// 5. Stream PDF ke frontend
$filename = $report_code . '_' . $order_id . '_' . date('Ymd') . '.pdf';
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Length: ' . strlen($pdf));
echo $pdf;
exit;
}
// Hanya return URL (untuk iframe/window.open) — tanpa stream
// Frontend membuka URL ini secara langsung
public function get_url()
{
if (!$this->isLogin) {
$this->sys_error('Invalid Token');
return;
}
$prm = $this->sys_input;
$report_code = $prm['report_code'] ?? '';
$order_id = intval($prm['PT_OrderHeaderID'] ?? 0);
$username = $prm['PUsername'] ?? ($this->sys_user['userName'] ?? 'system');
$tm = round(microtime(true) * 1000);
$row = $this->db_onedev->query(
"SELECT Print_TransactionUrl FROM print_transaction WHERE Print_TransactionCode = ? LIMIT 1",
[$report_code]
)->row_array();
if (!$row) {
$this->sys_error("Report code tidak ditemukan: {$report_code}");
return;
}
$url = $row['Print_TransactionUrl'];
$url = str_replace('PT_OrderHeaderID', $order_id, $url);
$url = str_replace('PUsername', urlencode($username), $url);
$url = str_replace('TS', $tm, $url);
// Pre-populate cache — frontend buka URL langsung ke BIRT
// Cache hidup 5 menit, cukup untuk BIRT generate PDF
if ($order_id > 0) {
$this->_populate_cache($order_id);
}
$this->sys_ok(['url' => $url]);
}
// Decrypt patient PII dan simpan ke cache
private function _populate_cache($order_id)
{
// Ambil _enc columns dari m_patient via t_orderheader
$patient = $this->db_onedev->query(
"SELECT M_PatientID,
M_PatientName_enc, M_PatientDOB_enc, M_PatientHP_enc,
M_PatientEmail_enc, M_PatientDOB
FROM t_orderheader
JOIN m_patient ON T_OrderHeaderM_PatientID = M_PatientID
WHERE T_OrderHeaderID = ? LIMIT 1",
[$order_id]
)->row_array();
if (!$patient) return null;
$addr = $this->db_onedev->query(
"SELECT M_PatientAddressDescription_enc
FROM m_patientaddress
WHERE M_PatientAddressM_PatientID = ?
AND M_PatientAddressIsActive = 'Y'
AND M_PatientAddressNote = 'Utama'
LIMIT 1",
[$patient['M_PatientID']]
)->row_array();
$enc = $this->ibl_encryptor;
$name = $enc->decrypt($patient['M_PatientName_enc'] ?? '') ?? '';
$dob = $enc->decrypt($patient['M_PatientDOB_enc'] ?? '') ?? date('d-m-Y', strtotime($patient['M_PatientDOB'] ?? 'now'));
$hp = $enc->decrypt($patient['M_PatientHP_enc'] ?? '') ?? '';
$email= $enc->decrypt($patient['M_PatientEmail_enc']?? '') ?? '';
$address = $enc->decrypt($addr['M_PatientAddressDescription_enc'] ?? '') ?? '';
// Hapus cache lama untuk order ini + cleanup expired
$this->db_onedev->query(
"DELETE FROM patient_print_cache WHERE ppc_order_id = ? OR ppc_created < NOW() - INTERVAL 5 MINUTE",
[$order_id]
);
// Insert cache baru
$this->db_onedev->query(
"INSERT INTO patient_print_cache
(ppc_order_id, ppc_patient_id, ppc_name, ppc_dob, ppc_hp, ppc_email, ppc_address, ppc_created)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())",
[$order_id, $patient['M_PatientID'], $name, $dob, $hp, $email, $address]
);
return $this->db_onedev->insert_id();
}
}