FHM31052601IBL - script masking kolom plaintext PII m_patient & m_patientaddress
Semua 300+ controller otomatis tampilkan data termasking tanpa perlu diupdate satu-satu. Data asli tetap aman di kolom _enc. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
169
scripts/mask_patient_plaintext.php
Normal file
169
scripts/mask_patient_plaintext.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* Masking kolom plaintext PII di m_patient dan m_patientaddress
|
||||
* Data asli tetap aman di kolom _enc
|
||||
* Jalankan via: php scripts/mask_patient_plaintext.php
|
||||
* Aman dijalankan berulang: skip row yang sudah termasking
|
||||
*/
|
||||
|
||||
define('BASEPATH', true);
|
||||
|
||||
foreach (file(__DIR__ . '/../.env', 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;
|
||||
}
|
||||
|
||||
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]
|
||||
);
|
||||
|
||||
// Deteksi apakah sudah dimasking: cek apakah M_PatientName masih plaintext
|
||||
// (plaintext = tidak ada '***', sudah masked = ada '***')
|
||||
function is_masked($val) {
|
||||
return $val === null || strpos($val, '***') !== false;
|
||||
}
|
||||
|
||||
function mask_name($v) {
|
||||
if (!$v) return $v;
|
||||
$v = trim($v);
|
||||
$len = mb_strlen($v, 'UTF-8');
|
||||
if ($len <= 2) return '***';
|
||||
return mb_substr($v, 0, 2, 'UTF-8') . str_repeat('*', min(3, $len - 2));
|
||||
}
|
||||
|
||||
function mask_phone($v) {
|
||||
if (!$v) return $v;
|
||||
$digits = preg_replace('/[^0-9]/', '', $v);
|
||||
$len = strlen($digits);
|
||||
if ($len <= 4) return '****';
|
||||
if ($len <= 8) return substr($digits, 0, 4) . str_repeat('*', $len - 4);
|
||||
return substr($digits, 0, 4) . str_repeat('*', $len - 7) . substr($digits, -3);
|
||||
}
|
||||
|
||||
function mask_email($v) {
|
||||
if (!$v || strpos($v, '@') === false) return $v;
|
||||
[$local, $domain] = explode('@', $v, 2);
|
||||
$show = mb_substr($local, 0, min(2, mb_strlen($local, 'UTF-8')), 'UTF-8');
|
||||
return $show . '***@' . $domain;
|
||||
}
|
||||
|
||||
function mask_short($v) {
|
||||
if (!$v) return $v;
|
||||
$v = trim($v);
|
||||
$len = mb_strlen($v, 'UTF-8');
|
||||
if ($len <= 2) return '***';
|
||||
return mb_substr($v, 0, 2, 'UTF-8') . '***';
|
||||
}
|
||||
|
||||
function mask_id($v) {
|
||||
if (!$v) return $v;
|
||||
$v = trim($v);
|
||||
$len = strlen($v);
|
||||
if ($len <= 4) return '****';
|
||||
return substr($v, 0, 4) . str_repeat('*', max(3, $len - 6)) . ($len > 6 ? substr($v, -2) : '');
|
||||
}
|
||||
|
||||
function mask_address($v) {
|
||||
if (!$v) return $v;
|
||||
$v = trim($v);
|
||||
$len = mb_strlen($v, 'UTF-8');
|
||||
if ($len <= 5) return '***';
|
||||
return mb_substr($v, 0, 5, 'UTF-8') . '***';
|
||||
}
|
||||
|
||||
$batch = 500;
|
||||
|
||||
// ============================================================
|
||||
// m_patient
|
||||
// ============================================================
|
||||
echo "=== Masking m_patient ===\n";
|
||||
$total = 0;
|
||||
|
||||
$stmt = $pdo->prepare("UPDATE m_patient SET
|
||||
M_PatientName = ?,
|
||||
M_PatientHP = ?,
|
||||
M_PatientPhone = ?,
|
||||
M_PatientEmail = ?,
|
||||
M_PatientPOB = ?,
|
||||
M_PatientIDNumber = ?,
|
||||
M_PatientNIK = ?,
|
||||
M_PatientNIP = ?
|
||||
WHERE M_PatientID = ?");
|
||||
|
||||
while (true) {
|
||||
// Skip rows already masked (ada '***' di nama)
|
||||
$rows = $pdo->query(
|
||||
"SELECT M_PatientID, M_PatientName, M_PatientHP, M_PatientPhone,
|
||||
M_PatientEmail, M_PatientPOB, M_PatientIDNumber, M_PatientNIK, M_PatientNIP
|
||||
FROM m_patient
|
||||
WHERE M_PatientName_enc IS NOT NULL
|
||||
AND M_PatientName NOT LIKE '%***%'
|
||||
LIMIT {$batch}"
|
||||
)->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($rows)) break;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$stmt->execute([
|
||||
mask_name($row['M_PatientName']),
|
||||
mask_phone($row['M_PatientHP']),
|
||||
mask_phone($row['M_PatientPhone']),
|
||||
mask_email($row['M_PatientEmail']),
|
||||
mask_short($row['M_PatientPOB']),
|
||||
mask_id($row['M_PatientIDNumber']),
|
||||
mask_id($row['M_PatientNIK']),
|
||||
mask_id($row['M_PatientNIP']),
|
||||
$row['M_PatientID'],
|
||||
]);
|
||||
$total++;
|
||||
}
|
||||
echo " {$total} rows...\n";
|
||||
}
|
||||
echo "m_patient selesai: {$total} rows\n\n";
|
||||
|
||||
// ============================================================
|
||||
// m_patientaddress
|
||||
// ============================================================
|
||||
echo "=== Masking m_patientaddress ===\n";
|
||||
$total = 0;
|
||||
|
||||
$stmt2 = $pdo->prepare("UPDATE m_patientaddress SET
|
||||
M_PatientAddressDescription = ?,
|
||||
M_PatientAddressEmail = ?,
|
||||
M_PatientAddressPhone = ?
|
||||
WHERE M_PatientAddressID = ?");
|
||||
|
||||
while (true) {
|
||||
$rows = $pdo->query(
|
||||
"SELECT M_PatientAddressID, M_PatientAddressDescription,
|
||||
M_PatientAddressEmail, M_PatientAddressPhone
|
||||
FROM m_patientaddress
|
||||
WHERE M_PatientAddressDescription_enc IS NOT NULL
|
||||
AND (M_PatientAddressDescription IS NULL
|
||||
OR M_PatientAddressDescription NOT LIKE '%***%')
|
||||
LIMIT {$batch}"
|
||||
)->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($rows)) break;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$stmt2->execute([
|
||||
mask_address($row['M_PatientAddressDescription']),
|
||||
mask_email($row['M_PatientAddressEmail']),
|
||||
mask_phone($row['M_PatientAddressPhone']),
|
||||
$row['M_PatientAddressID'],
|
||||
]);
|
||||
$total++;
|
||||
}
|
||||
echo " {$total} rows...\n";
|
||||
}
|
||||
echo "m_patientaddress selesai: {$total} rows\n\n";
|
||||
|
||||
echo "=== Masking plaintext selesai ===\n";
|
||||
echo "Catatan: data asli tetap tersimpan aman di kolom _enc\n";
|
||||
Reference in New Issue
Block a user