POST /users/verify/phone/preauth.json

Source

  • Legacy controller:/Users/mattsu/Documents/Site/get-lancer-php56/app/Controller/UsersController.php:5804-6044preauth 分支 5834-6005
  • Legacy model:/Users/mattsu/Documents/Site/get-lancer-php56/app/Model/PhoneVerification.php:22-75
  • New endpoint:Endpoint/V1/Users.php:1125-1407,preauth 主段 1168-1347
  • New routing:Lib/Common/RouterRule/Mapping.php:108-111
  • New OTP model:Lib/Model/PhoneVerification.php:27-88
  • New delivery wrapper:Lib/Model/PhoneDelivery.php:27-45
  • New limit / log model:Lib/Model/PhoneVerificationLog.php:18-129

Input / guard

  • 全域 API key;session optional。valid session 會提供 user_id 並以 user email 覆蓋 request email。
  • FormData:phone 必填;另讀 country_codedevice_idemailis_login
  • IP key phone_preauth:同一 IP 60 秒 5 次,鎖 600 秒;超限直接回 legacy HTTP 403 / error=6,不經 Router exception 新增 api_fail_logs
  • 保留 foreign-phone、blocked phone/device、daily limit、just verified、multi-user verified 與 3 秒重送檢查。

Insert 欄位分類

phone_verifications

欄位來源
phonelegacy normalized phone
hashlegacy 8 位亂數、user_id、phone、Security.salt 的 MD5
otplegacy 8 位亂數前 4 位
user_idvalid session user id;未登入時 legacy save 未指派,依 non-strict schema implicit value
created / modifiedschema / DB timestamp 行為

不得加入 verify_code;只有未登入 auth success 才更新。

phone_deliveries

欄位來源
user_idvalid session user id;未登入時 legacy insert 未指派,依 schema implicit value
msisdnnormalized / formatted phone 轉換
message_idSMS provider response
error_codephone
statusschema default 0
created / modifiedschema / DB timestamp 行為

不得自行填 quote_request_idnetwork_code

verify 使用專用 PhoneDelivery::insertLegacyVerify(),依 TW/HK/SG PhoneUtil 產生 MSISDN;既有 PhoneDelivery::insert() caller 不變。

phone_verification_logs

欄位來源
user_idvalid session user id;未登入為 NULL
phonenormalized phone
statusrequest 固定 0
createdlegacy Cake save timestamp;new explicit NOW()

blocked_phone_device_ids

觸發欄位
device 已有不同 phonedevice_id、目前 normalized phonetype=2
blocked phone 且有 devicedevice_id、目前 normalized phonetype=1

created 對齊 legacy Cake save,以 explicit NOW() 寫入;不得加入其他欄位。

Response

  • success:hasherror=0message=Success 或 phone 已被使用時 message=in_used
  • failure 保留 legacy error code 179 與翻譯文字。

Payment / queue / activity

  • preauth 不寫 payment、wallet、transaction、referral、activity、task queue 或 event queue。
  • 只有 foreign / repeated verification threshold 可能寫 email queue;SMS / voice delivery 另外寫 provider log 與 phone_deliveries

Log / notification

  • Legacy phone_verify channel 會記錄 request data;RouterV3 generic log 也會記 request。本次先保持 legacy endpoint log,token / OTP log 重複與敏感資料風險待 reviewer 決定是否只保留 generic log。
  • foreign-phone 達門檻會寫 log 並寄送 bdEmailList;同 phone 成功驗證累計超過 10 次會寄 csEmailList

Config

  • area:交給 ProConfig::get('area');台灣環境必須維持空值,不可設 area=tw
  • Security.salt:legacy app/Config/core.phpc:191;new 對應 Lib/Model/PhoneVerification.php:23 常數。
  • SMS:sms_platform_localsms_platform_other 與 provider credentials;本地 mapping 為 infobip / nexmo
  • template:sms.verify_message
  • new shared SmsUtil::send() 另有 legacy 沒有的 empty / test phone / length shortcut,因此本 API 使用 PhoneVerification::sendLegacySms() wrapper,從 format phone 後直接進相同 provider mapping;沒有直接改 shared behavior。

PHP 5.6 -> 8.2

  • request array / null 先轉成 legacy-compatible string,避免 rawurldecode(null)、字串串接 array 造成 PHP 8.2 TypeError。
  • valid_phone=false 仍沿用 legacy error branch,不把 false 傳入有 string type declaration 的 helper。
  • LimitIpUtil::isInLimit() 補回 legacy optional count reference,foreign threshold 才能取得 try_count
  • IP symbol 只讀 legacy 的 HTTP_X_FORWARDED_FOR;PHP 8.2 缺 header 時傳 NULL 並由 LimitIpUtil no-op,不自行 fallback 到 REMOTE_ADDR 改變 guard。

Tests / 未確認

  • 2026-07-16 PHP 8.2 容器:與 phone/auth、voice/preauth 共 9 tests / 85 assertions
  • 已驗證 missing phone、anonymous staging bypass、response hash string、route、legacy IP-limit response、TW/HK/SG delivery MSISDN;測試使用 transaction rollback,沒有再增加 client_usage_users orphan row。
  • 2026-07-16 new staging logged-in preauth:response error=0message=in_usedphone_verification_logs.id=30846/status=0sms_logs.id=4010phone_deliveries.id=32562。Infobip callback 將 delivery 更新為 status=7error_code=Message delivered to handset,MSISDN 為 TW 國碼格式。
  • 同日初次部署誤走 every8d 並回 -101 密碼錯誤;同步 sms_platform_local=infobip 與 Infobip endpoint / API key 後送達。credential 值不寫入文件。
  • new staging 已確認 local SMS 使用 Infobip;other / voice 與 production config 待確認。Configuration.php.gitignore 忽略,部署需另外同步。
  • 待補 invalid / blocked phone、3 秒 duplicate、is_login、foreign limit 與完整 legacy/new raw response diff。真實 SMS 不放進 PHPUnit。
  • legacy alert email 使用 email.admin.from_email(STAGING) subject prefix;new shared EmailQueue 使用 EmailTemplate.from_email(staging),目前尚未對齊。production 前必須修正或取得 reviewer migration decision。
  • 若其他 deployment 的 sms_platform_local=mitake,new SmsUtil::sendWith() 沒有 mitake branch,部署前必須確認。