服务器环境下PHP执行Curl发送OTP短信请求异常问题求助
问题排查与解决方法
你当前代码的核心问题是:curl_error()仅能检测CURL执行过程中的网络层、协议层错误(比如无法连接主机、超时、SSL握手失败等),无法检测业务层的错误,哪怕短信接口返回了「参数错误」「余额不足」等失败结果,只要接口正常响应,$err就会为空,你仅通过$err判断发送成功的逻辑本身是错误的。
排查步骤
- 第一步:校验环境变量配置
首先在服务器环境打印App::environment('MSGAUTH')、App::environment('SENDERID')两个配置值,确认和本地正常运行的配置完全一致,不存在多空格、配置遗漏、大小写错误的问题。 - 第二步:打印接口返回值排查业务错误
在curl_exec($curl)之后临时打印$response的完整内容,短信服务提供商通常会在返回值里标注具体失败原因,常见错误包括:模板不匹配、SenderID未备案、账户余额不足、手机号格式错误、国家码不支持等。
你也可以直接在服务器命令行执行如下命令手动调用接口,排查是否是服务器网络限制导致的问题:
如果命令行调用没有返回正常成功结果,检查服务器的安全组、防火墙规则,确认443端口的出站请求没有被拦截,也没有被短信服务商的防火墙拦截服务器IP。curl "https://api.XXX.com/api/sendhttp.php?authkey=替换为你的MSGAUTH值&mobiles=替换为测试手机号&country=替换为测试国家码&sender=替换为你的SENDERID值&route=3&message=Your 2-way authentication OTP is 123456" - 第三步:修复参数编码问题
你当前直接将参数拼接到URL中,没有做URL编码,如果服务器环境编码和本地不一致,很容易导致参数乱码被短信平台拒绝,所有拼接在URL中的参数都需要用urlencode()处理。 - 第四步:删除无效请求头
你发送的是GET请求,参数全部在URL中,但配置了content-type: application/json的请求头,这个配置不符合GET请求的规范,部分严格的短信接口会直接拒绝这类请求,可以直接删掉该请求头配置。
修正后代码示例
public static function send($mobile,$otp,$country_code){ $message = "Your 2-way authentication OTP is $otp"; $curl = curl_init(); $authKey = App::environment('MSGAUTH'); $senderId = App::environment('SENDERID'); // 参数先做URL编码再拼接 $authKey = urlencode($authKey); $mobile = urlencode($mobile); $country_code = urlencode($country_code); $senderId = urlencode($senderId); $message = urlencode($message); curl_setopt_array($curl, array( CURLOPT_URL => "https://api.XXX.com/api/sendhttp.php?authkey=".$authKey."&mobiles=".$mobile."&country=$country_code&sender=".$senderId."&route=3&message=".$message, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, // 删掉了不符合规范的JSON请求头 )); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { return false; } else { // 这里要根据你用的短信平台的返回规则修改判断逻辑 // 比如平台返回成功时包含"success"字符串就返回true,否则返回false // 示例判断逻辑,需要替换成实际平台的成功标识 if(stripos($response, 'success') !== false) { return true; } else { // 可以在这里记录$response的错误日志方便后续排查 return false; } } }
内容的提问来源于stack exchange,提问作者user3653474
相关产品推荐
相关产品推荐

