POST /users/verify/phone/preauth.json
Source
- Legacy controller:
/Users/mattsu/Documents/Site/get-lancer-php56/app/Controller/UsersController.php:5804-6044,preauth分支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_code、device_id、email、is_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
| 欄位 | 來源 |
|---|---|
phone | legacy normalized phone |
hash | legacy 8 位亂數、user_id、phone、Security.salt 的 MD5 |
otp | legacy 8 位亂數前 4 位 |
user_id | valid session user id;未登入時 legacy save 未指派,依 non-strict schema implicit value |
created / modified | schema / DB timestamp 行為 |
不得加入 verify_code;只有未登入 auth success 才更新。
phone_deliveries
| 欄位 | 來源 |
|---|---|
user_id | valid session user id;未登入時 legacy insert 未指派,依 schema implicit value |
msisdn | normalized / formatted phone 轉換 |
message_id | SMS provider response |
error_code | phone |
status | schema default 0 |
created / modified | schema / DB timestamp 行為 |
不得自行填 quote_request_id、network_code。
verify 使用專用 PhoneDelivery::insertLegacyVerify(),依 TW/HK/SG PhoneUtil 產生 MSISDN;既有 PhoneDelivery::insert() caller 不變。
phone_verification_logs
| 欄位 | 來源 |
|---|---|
user_id | valid session user id;未登入為 NULL |
phone | normalized phone |
status | request 固定 0 |
created | legacy Cake save timestamp;new explicit NOW() |
blocked_phone_device_ids
| 觸發 | 欄位 |
|---|---|
| device 已有不同 phone | device_id、目前 normalized phone、type=2 |
| blocked phone 且有 device | device_id、目前 normalized phone、type=1 |
created 對齊 legacy Cake save,以 explicit NOW() 寫入;不得加入其他欄位。
Response
- success:
hash、error=0、message=Success或 phone 已被使用時message=in_used。 - failure 保留 legacy error code
1到7、9與翻譯文字。
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_verifychannel 會記錄 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:legacyapp/Config/core.phpc:191;new 對應Lib/Model/PhoneVerification.php:23常數。- SMS:
sms_platform_local、sms_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並由LimitIpUtilno-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
hashstring、route、legacy IP-limit response、TW/HK/SG delivery MSISDN;測試使用 transaction rollback,沒有再增加client_usage_usersorphan row。 - 2026-07-16 new staging logged-in preauth:response
error=0、message=in_used;phone_verification_logs.id=30846/status=0、sms_logs.id=4010、phone_deliveries.id=32562。Infobip callback 將 delivery 更新為status=7、error_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 sharedEmailQueue使用EmailTemplate.from_email與(staging),目前尚未對齊。production 前必須修正或取得 reviewer migration decision。 - 若其他 deployment 的
sms_platform_local=mitake,newSmsUtil::sendWith()沒有 mitake branch,部署前必須確認。