key === '') { CLI::error('encryption.key 가 비어 있습니다. .env 설정 후 실행하세요. (키 없이 암호화 불가)'); return; } $db = Database::connect(); $piiFields = ['ds_rep_name', 'ds_tel', 'ds_rep_phone', 'ds_email', 'ds_va_account']; $hasTelBidx = $db->fieldExists('ds_tel_bidx', 'designated_shop'); $hasNameBidx = $db->fieldExists('ds_rep_name_bidx', 'designated_shop'); $rows = $db->table('designated_shop')->select('ds_idx, ' . implode(', ', $piiFields))->get()->getResultArray(); CLI::write('대상 행: ' . count($rows) . ($dry ? ' [DRY-RUN: 변경 없음]' : ' [실제 실행]'), $dry ? 'yellow' : 'green'); $encCount = 0; $rowCount = 0; foreach ($rows as $r) { $update = []; foreach ($piiFields as $f) { $v = (string) ($r[$f] ?? ''); if ($v !== '' && strpos($v, 'ENC:') !== 0) { $update[$f] = pii_encrypt($v); $encCount++; } } // 블라인드 인덱스(원본값 기준) if ($hasTelBidx) { $update['ds_tel_bidx'] = pii_blind_index((string) ($r['ds_tel'] ?? '')); } if ($hasNameBidx) { $update['ds_rep_name_bidx'] = pii_blind_index((string) ($r['ds_rep_name'] ?? '')); } if ($update === []) { continue; } $rowCount++; if (! $dry) { $db->table('designated_shop')->where('ds_idx', (int) $r['ds_idx'])->update($update); } } CLI::write('변경 대상 행: ' . $rowCount . ' / 암호화 필드: ' . $encCount, 'green'); if ($dry) { CLI::write('DRY-RUN 이었습니다. 실제 반영하려면 --force 로 다시 실행하세요.', 'yellow'); } else { CLI::write('완료. (멱등: 재실행해도 이미 암호화된 값은 건너뜁니다)', 'green'); } } }