diff --git a/application/controllers/mockup/fo/ibl_registration/Patient.php b/application/controllers/mockup/fo/ibl_registration/Patient.php index c0d984d2..cb2bf869 100644 --- a/application/controllers/mockup/fo/ibl_registration/Patient.php +++ b/application/controllers/mockup/fo/ibl_registration/Patient.php @@ -32,7 +32,25 @@ class Patient extends MY_Controller } // Masking untuk kolom plaintext lama (data asli di _enc) - private function _mask_name($v) { if (!$v) return $v; $v=trim($v); $l=mb_strlen($v,'UTF-8'); if($l<=2) return '***'; return mb_substr($v,0,2,'UTF-8').str_repeat('*',min(3,$l-2)); } + private function _mask_name($v) { + if (!$v) return $v; + $v = trim($v); + $words = preg_split('/\s+/', $v); + if (count($words) === 1) { + // Satu kata: tampilkan penuh jika ≤6 huruf, atau 6 huruf + *** + $l = mb_strlen($v, 'UTF-8'); + return $l <= 6 ? $v : mb_substr($v, 0, 6, 'UTF-8') . '***'; + } + // Multi kata: kata pertama penuh + inisial kata berikutnya + * + $first = $words[0]; + $rest = array_slice($words, 1); + $masked = array_map(function($w) { + if (!$w) return ''; + $init = mb_substr($w, 0, 1, 'UTF-8'); + return $init . str_repeat('*', max(3, mb_strlen($w, 'UTF-8') - 1)); + }, $rest); + return $first . ' ' . implode(' ', $masked); + } private function _mask_phone($v) { if (!$v) return $v; $d=preg_replace('/[^0-9]/','',trim($v)); $l=strlen($d); if($l<=4) return '****'; if($l<=8) return substr($d,0,4).str_repeat('*',$l-4); return substr($d,0,4).str_repeat('*',$l-7).substr($d,-3); } private function _mask_email($v) { if (!$v||strpos($v,'@')===false) return $v; [$loc,$dom]=explode('@',$v,2); return mb_substr($loc,0,min(2,mb_strlen($loc,'UTF-8')),'UTF-8').'***@'.$dom; } private function _mask_short($v) { if (!$v) return $v; $v=trim($v); $l=mb_strlen($v,'UTF-8'); if($l<=2) return '***'; return mb_substr($v,0,2,'UTF-8').'***'; } diff --git a/application/controllers/mockup/masterdata/Patientv4.php b/application/controllers/mockup/masterdata/Patientv4.php index 0ea5cd93..0efb35ad 100644 --- a/application/controllers/mockup/masterdata/Patientv4.php +++ b/application/controllers/mockup/masterdata/Patientv4.php @@ -14,7 +14,23 @@ class Patientv4 extends MY_Controller $this->load->library('ibl_encryptor'); } - private function _mask_name($v) { if (!$v) return $v; $v=trim($v); $l=mb_strlen($v,'UTF-8'); if($l<=2) return '***'; return mb_substr($v,0,2,'UTF-8').str_repeat('*',min(3,$l-2)); } + private function _mask_name($v) { + if (!$v) return $v; + $v = trim($v); + $words = preg_split('/\s+/', $v); + if (count($words) === 1) { + $l = mb_strlen($v, 'UTF-8'); + return $l <= 6 ? $v : mb_substr($v, 0, 6, 'UTF-8') . '***'; + } + $first = $words[0]; + $rest = array_slice($words, 1); + $masked = array_map(function($w) { + if (!$w) return ''; + $init = mb_substr($w, 0, 1, 'UTF-8'); + return $init . str_repeat('*', max(3, mb_strlen($w, 'UTF-8') - 1)); + }, $rest); + return $first . ' ' . implode(' ', $masked); + } private function _mask_phone($v) { if (!$v) return $v; $d=preg_replace('/[^0-9]/','',trim($v)); $l=strlen($d); if($l<=4) return '****'; if($l<=8) return substr($d,0,4).str_repeat('*',$l-4); return substr($d,0,4).str_repeat('*',$l-7).substr($d,-3); } private function _mask_email($v) { if (!$v||strpos($v,'@')===false) return $v; [$loc,$dom]=explode('@',$v,2); return mb_substr($loc,0,min(2,mb_strlen($loc,'UTF-8')),'UTF-8').'***@'.$dom; } private function _mask_short($v) { if (!$v) return $v; $v=trim($v); $l=mb_strlen($v,'UTF-8'); if($l<=2) return '***'; return mb_substr($v,0,2,'UTF-8').'***'; } diff --git a/scripts/mask_patient_plaintext.php b/scripts/mask_patient_plaintext.php index a0e67511..3525bb2c 100644 --- a/scripts/mask_patient_plaintext.php +++ b/scripts/mask_patient_plaintext.php @@ -31,10 +31,20 @@ function is_masked($val) { 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)); + $v = trim($v); + $words = preg_split('/\s+/', $v); + if (count($words) === 1) { + $l = mb_strlen($v, 'UTF-8'); + return $l <= 6 ? $v : mb_substr($v, 0, 6, 'UTF-8') . '***'; + } + $first = $words[0]; + $rest = array_slice($words, 1); + $masked = array_map(function($w) { + if (!$w) return ''; + $init = mb_substr($w, 0, 1, 'UTF-8'); + return $init . str_repeat('*', max(3, mb_strlen($w, 'UTF-8') - 1)); + }, $rest); + return $first . ' ' . implode(' ', $masked); } function mask_phone($v) { diff --git a/scripts/remask_patient_name.php b/scripts/remask_patient_name.php new file mode 100644 index 00000000..e734e7a4 --- /dev/null +++ b/scripts/remask_patient_name.php @@ -0,0 +1,76 @@ + PDO::ERRMODE_EXCEPTION] +); + +function mask_name($v) { + if (!$v) return $v; + $v = trim($v); + $words = preg_split('/\s+/', $v); + if (count($words) === 1) { + $l = mb_strlen($v, 'UTF-8'); + return $l <= 6 ? $v : mb_substr($v, 0, 6, 'UTF-8') . '***'; + } + $first = $words[0]; + $rest = array_slice($words, 1); + $masked = array_map(function($w) { + if (!$w) return ''; + $init = mb_substr($w, 0, 1, 'UTF-8'); + return $init . str_repeat('*', max(3, mb_strlen($w, 'UTF-8') - 1)); + }, $rest); + return $first . ' ' . implode(' ', $masked); +} + +echo "=== Re-mask M_PatientName (format baru) ===\n"; +$total = 0; +$batch = 500; +$last_id = 0; + +$stmt = $pdo->prepare( + "UPDATE m_patient SET M_PatientName = ? WHERE M_PatientID = ?" +); + +while (true) { + $rows = $pdo->query( + "SELECT M_PatientID, M_PatientName_enc + FROM m_patient + WHERE M_PatientName_enc IS NOT NULL + AND M_PatientID > {$last_id} + ORDER BY M_PatientID ASC + LIMIT {$batch}" + )->fetchAll(PDO::FETCH_ASSOC); + + if (empty($rows)) break; + + foreach ($rows as $row) { + $real_name = $enc->decrypt($row['M_PatientName_enc']); + if ($real_name !== null) { + $stmt->execute([mask_name($real_name), $row['M_PatientID']]); + } + $last_id = $row['M_PatientID']; + $total++; + } + echo " {$total} rows...\n"; +} + +echo "Selesai: {$total} rows\n";