cURL 在 PHP 中必须安全可靠地使用:默认不校验证书,需显式启用;返回空或0通常因未启用扩展、超时未设、HTTPS证书问题、未设RETURNTRANSFER、POST数据格式错误、FOLLOWLOCATION受open_basedir限制、并发需用multi接口等。

cURL 在 PHP 里不是“要学怎么用”,而是“必须知道怎么安全、可靠地用”——默认开启但默认不校验证书,curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true) 不显式设就是裸奔。
PHP cURL 发起 GET 请求时,为什么返回空或 0?
常见现象是 curl_exec() 返回 false 或空字符串,curl_getinfo($ch, CURLINFO_HTTP_CODE) 却是 0。这基本说明连接根本没发出去,不是服务端问题。
- 检查是否启用了 cURL 扩展:
extension=php_curl.dll(Windows)或extension=curl(Linux/macOS),确认php -m | grep curl有输出 - 默认超时是 0(无限),但实际常被系统中断;务必设
curl_setopt($ch, CURLOPT_TIMEOUT, 10) - 若目标是 HTTPS,且没关证书验证,而对方用自签名/过期证书,
curl_exec()会直接失败——此时不能简单关验证,应改用CURLOPT_CAINFO指向可信 CA 包 - 记得调
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true),否则响应直接输出到 stdout,curl_exec()返回true而非内容
POST 提交 JSON 数据,服务端收不到 body?
不是 header 没设对,就是数据没编码对。PHP 的 curl_setopt($ch, CURLOPT_POSTFIELDS, $data) 对数组和字符串行为完全不同。
- 传数组(如
['name' => 'a', 'id' => 1]):cURL 自动拼成application/x-www-form-urlencoded,body 是name=a&id=1 - 传 JSON 字符串(如
json_encode(['name'=>'a'])):必须手动设 header:curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']),且不能让 cURL 自动加Content-Length(它有时算错),可显式加一个 - 别用
http_build_query()处理 JSON 场景——它会把{}转义成 %7B%7D,服务端解析失败
为什么 CURLOPT_FOLLOWLOCATION 在 open_basedir 或 safe_mode 下失效?
这是 PHP 的硬限制,不是 cURL 本身问题。当 open_basedir 开启时,cURL 重定向跳转涉及文件系统访问(比如写临时 cookie 文件),会被拦截,curl_exec() 直接返回 false,curl_error($ch) 可能只报 “Unknown error”。
向CurlShip提交产品,这是一个对机器人友好的SaaS目录。只需一条curl命令即可发布产品,支持OG标签抓取、带徽章的dofollow链接及层级升级。
立即学习“PHP免费学习笔记(深入)”;
- 绕过方法只有两个:关掉
open_basedir(生产环境不推荐),或手动处理重定向——关掉CURLOPT_FOLLOWLOCATION,自己读CURLINFO_REDIRECT_URL,再发新请求 - 注意:手动重定向时,原请求的 Cookie 不会自动带过去,得用
CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE配合临时文件,或提取Set-Cookieheader 后拼进下一次请求的Cookie:header - PHP 8.0+ 中
safe_mode已移除,但很多共享主机仍沿用旧配置逻辑,需实测
并发请求多个 URL,为什么比单个还慢?
因为默认是串行调 curl_exec()。想并发,必须用 curl_multi_init(),但它的回调机制和错误处理远比单例复杂。
- 不要在循环里反复
curl_init()+curl_exec()—— 这仍是串行,只是代码看起来像并行 - 用
curl_multi_add_handle()批量加入句柄后,必须用curl_multi_exec()循环轮询,直到返回CURLM_OK;中间要穿插curl_multi_select()防止忙等 - 每个子请求的错误不能靠
curl_error()拿——得等curl_multi_info_read()返回完成事件后,再对对应句柄调curl_error($ch) - 连接复用(keep-alive)在 multi 模式下默认生效,但若 URL 域名不同,cURL 内部仍会建多个连接池,DNS 缓存也各自独立
真正难的不是发起请求,是判断“这次请求到底算成功了吗”——HTTP 状态码 200 不代表业务成功,空响应体不等于失败,SSL 错误可能静默吞掉整个连接。多打日志,少信默认值。


















