bool, 'message'=>string, 'enc_phone'=>string, 'raw_phone'=>string, 'ci'=>string, 'carrier'=>string] */ public function validatePassPhoneChange(array $sess, array $passPayload): array { $memNo = (int) ($sess['_mno'] ?? 0); if ($memNo <= 0) { return $this->fail('로그인 정보가 확인되지 않습니다. 다시 로그인 후 시도해 주세요.'); } $rawPhone = $this->normalizePhone((string) Arr::get($passPayload, 'PHONE', '')); $ci = (string) Arr::get($passPayload, 'CI', ''); $carrier = strtoupper((string) Arr::get($passPayload, 'CARRIER', '')); if ($rawPhone === '' || $ci === '') { return $this->fail('인증 정보가 올바르지 않습니다. 다시 시도해 주세요.'); } // 통신사 제한: SKT/KTF/LGT만 허용, 나머지 전부 차단 + MVNO 차단 $allowCarriers = ['SKT', 'KTF', 'LGT']; if (!in_array($carrier, $allowCarriers, true) || $carrier === 'MVNO') { return $this->fail('죄송합니다. SKT/KT/LG U+ 휴대전화만 인증할 수 있습니다. (알뜰폰/기타 통신사 불가)'); } // PASS 전화번호 암호화 (CI 레거시 방식) $encPassPhone = (string) $this->seed->encrypt($rawPhone); // 기존 회원 전화번호와 동일하면 변경 불가 $encMemberPhone = (string) ($sess['_mcell'] ?? ''); if ($encMemberPhone !== '' && $encPassPhone !== '' && hash_equals($encMemberPhone, $encPassPhone)) { return $this->fail('현재 등록된 연락처와 동일합니다. 다른 번호로 인증해 주세요.'); } // PASS 전화번호가 DB에 존재하면 변경 불가 // "존재한다면 이전에 가입된 전화번호가 있습니다. 관리자 문의" if ($this->repo->existsEncryptedCell($encPassPhone, $memNo)) { return $this->fail('이미 가입된 휴대폰 번호가 있습니다. 관리자에게 문의해 주세요.'); } // CI가 회원정보 mem_info.ci와 일치해야 통과 $memberCi = $this->repo->getMemberCi($memNo); if ($memberCi === '' || !hash_equals($memberCi, $ci)) { return $this->fail('가입된 회원정보와 일치하지 않습니다. 관리자에게 문의해 주세요.'); } return [ 'ok' => true, 'message' => '검증이 완료되었습니다.', 'enc_phone' => $encPassPhone, 'raw_phone' => $rawPhone, 'ci' => $ci, 'carrier' => $carrier, ]; } /** * 최종 저장: mem_info.cell 업데이트 * @return array ['ok'=>bool, 'message'=>string, '_cell'=>string] */ public function commitPhoneChange(int $memNo, array $passPayload): array { $Phone = $this->normalizePhone((string) Arr::get($passPayload, 'PHONE', '')); $encPhone = (string) $this->seed->encrypt($Phone); if ($memNo <= 0 || $encPhone === '') { return $this->fail('저장할 정보가 올바르지 않습니다.'); } return DB::transaction(function () use ($memNo, $encPhone) { // 한번 더 중복 방어(레이스 컨디션) if ($this->repo->existsEncryptedCell($encPhone, $memNo)) { return $this->fail('이미 가입된 휴대폰 번호가 있습니다. 관리자에게 문의해 주세요.'); } $affected = $this->repo->updateEncryptedCell($memNo, $encPhone); if ($affected < 1) { return $this->fail('연락처 저장에 실패했습니다. 잠시 후 다시 시도해 주세요.'); } return [ 'ok'=>true, 'message'=>'연락처가 변경되었습니다.', '_cell' => $encPhone, ]; }); } /** * 휴대폰 정규화 (숫자만) */ private function normalizePhone(string $v): string { return preg_replace('/\D+/', '', $v) ?: ''; } private function fail(string $message): array { return [ 'ok' => false, 'message' => $message, 'enc_phone' => '', 'raw_phone' => '', 'ci' => '', 'carrier' => '', ]; } }