Files
BE_IBL/scripts/migrate_encrypt_results.php
sas.fajri c410d7bbd9 FHM31052601IBL - implementasi enkripsi PII pasien dan data medis (UU PDP)
- Tambah .env loader di index.php untuk IBL_ENCRYPT_KEY dan IBL_ENCRYPT_SEARCH_KEY
- Library Ibl_encryptor: AES-256-GCM encrypt/decrypt + trigram blind index untuk partial search
- SQL migration: tambah kolom _enc dan _bidx di 16 tabel (m_patient, m_patientaddress, hasil lab, log)
- Script backup_pdp_tables.sh: backup tabel terdampak sebelum migrasi
- Script migrate_encrypt_patient.php: enkripsi batch 178K data PII pasien
- Script migrate_encrypt_results.php: enkripsi data medis hasil lab dan log
- Patient.php: search via trigram blind index, add_new/edit enkripsi sebelum save

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

139 lines
5.2 KiB
PHP

<?php
/**
* Batch migration: enkripsi data medis hasil lab dan log
* Jalankan via: php scripts/migrate_encrypt_results.php
* Aman dijalankan berulang: skip row yang sudah ada _enc-nya
*/
// Load .env
$env_file = __DIR__ . '/../.env';
if (!file_exists($env_file)) {
die("ERROR: .env tidak ditemukan di " . realpath(__DIR__ . '/..') . PHP_EOL);
}
foreach (file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $l) {
if (strpos(trim($l), '#') === 0) continue;
[$k, $v] = array_map('trim', explode('=', $l, 2));
if ($k !== '') $_ENV[$k] = $v;
}
define('BASEPATH', true);
require __DIR__ . '/../application/libraries/Ibl_encryptor.php';
$enc = new Ibl_encryptor();
include __DIR__ . '/../application/config/database.php';
$cfg = $db['default'];
$pdo = new PDO(
"mysql:host={$cfg['hostname']};dbname={$cfg['database']};charset=utf8",
$cfg['username'],
$cfg['password'],
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$batch = 500;
// Helper: migrate tabel dengan field-field sederhana (tanpa bidx)
function migrate_simple(PDO $pdo, Ibl_encryptor $enc, string $table, string $pk, array $fields, string $check_field): void
{
echo "=== {$table} ===\n";
$total = 0;
$cols_sel = implode(', ', array_merge([$pk], $fields));
$sets = implode(', ', array_map(fn($f) => "{$f}_enc = ?", $fields));
$stmt = $pdo->prepare("UPDATE {$table} SET {$sets} WHERE {$pk} = ?");
while (true) {
$rows = $pdo->query(
"SELECT {$cols_sel} FROM {$table} WHERE {$check_field}_enc IS NULL LIMIT 500"
)->fetchAll(PDO::FETCH_ASSOC);
if (empty($rows)) break;
foreach ($rows as $row) {
$params = array_map(fn($f) => $enc->encrypt((string)($row[$f] ?? '')), $fields);
$params[] = $row[$pk];
$stmt->execute($params);
$total++;
}
echo " {$total} rows...\n";
}
echo "selesai: {$total} rows\n\n";
}
// ============================================================
// one_lab tables
// ============================================================
migrate_simple($pdo, $enc, 't_orderdetail', 'T_OrderDetailID',
['T_OrderDetailResult', 'T_OrderDetailNote'],
'T_OrderDetailResult');
migrate_simple($pdo, $enc, 't_orderheader', 'T_OrderHeaderID',
['T_OrderHeaderDiagnose'],
'T_OrderHeaderDiagnose');
migrate_simple($pdo, $enc, 'so_resultentrydetail', 'So_ResultEntryDetailID',
['So_ResultEntryDetailResult'],
'So_ResultEntryDetailResult');
migrate_simple($pdo, $enc, 'so_resultentrydetail_other', 'So_ResultEntryDetailOtherID',
['So_ResultEntryDetailOtherResult', 'So_ResultEntryDetailOtherResultBefore'],
'So_ResultEntryDetailOtherResult');
migrate_simple($pdo, $enc, 'so_resultentry_fisik_umum', 'So_ResultEntryFisikUmumID',
['So_ResultEntryFisikUmumDetails'],
'So_ResultEntryFisikUmumDetails');
migrate_simple($pdo, $enc, 'so_resultentry_fisik_summary', 'So_ResultEntryFisikSummaryID',
['So_ResultEntryFisikSummaryValue', 'So_ResultEntryFisikSummaryValue2'],
'So_ResultEntryFisikSummaryValue');
migrate_simple($pdo, $enc, 'so_resultentry_other', 'So_ResultEntryOtherID',
['So_ResultEntryOtherNote'],
'So_ResultEntryOtherNote');
migrate_simple($pdo, $enc, 'so_resultentry_fisioterapi', 'So_ResultEntdyFisioterapiID',
['So_ResultEntdyFisioterapiDetails'],
'So_ResultEntdyFisioterapiDetails');
migrate_simple($pdo, $enc, 'so_resultentry_smwt', 'So_ResultentrySmwtID', [
'So_ResultentrySmwtWeight', 'So_ResultentrySmwtHeight', 'So_ResultentrySmwtBMI',
'So_ResultentrySmwtPreTensi', 'So_ResultentrySmwtPreSPO2', 'So_ResultentrySmwtPreNadi',
'So_ResultentrySmwtPostTensi', 'So_ResultentrySmwtPostSPO2', 'So_ResultentrySmwtPostNadi',
'So_ResultentrySmwtVOMax', 'So_ResultentrySmwtKategoriKebugaran',
], 'So_ResultentrySmwtWeight');
migrate_simple($pdo, $enc, 'so_resultentry_srq29_conclusion', 'So_ResultentrySrq29ConclusionID',
['So_ResultentrySrq29ConclusionResult'],
'So_ResultentrySrq29ConclusionResult');
migrate_simple($pdo, $enc, 'so_resultentrysdsinterpretation', 'So_ResultEntrySDSInterpretationID',
['So_ResultEntrySDSInterpretationDisplay'],
'So_ResultEntrySDSInterpretationDisplay');
migrate_simple($pdo, $enc, 'member_eligible', 'Member_EligibleID',
['Member_EligibleDescription'],
'Member_EligibleDescription');
// ============================================================
// one_lab_log tables (ganti koneksi ke DB log)
// ============================================================
$cfg_log = $db['one_lab_log'];
$pdo_log = new PDO(
"mysql:host={$cfg_log['hostname']};dbname={$cfg_log['database']};charset=utf8",
$cfg_log['username'],
$cfg_log['password'],
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
migrate_simple($pdo_log, $enc, 'log_patient', 'Log_PatientID',
['Log_PatientJsonBefore', 'Log_PatientJsonAfter'],
'Log_PatientJsonBefore');
migrate_simple($pdo_log, $enc, 'log_fo', 'Log_FoID',
['Log_FoJson'],
'Log_FoJson');
migrate_simple($pdo_log, $enc, 'log_resultentry', 'Log_ResultEntryID',
['Log_ResultEntryJSONBefore', 'Log_ResultEntryJSONAfter'],
'Log_ResultEntryJSONBefore');
echo "=== Semua migrasi hasil lab selesai ===\n";