【PHP】curl_init() 如何排错????
文章目錄
- 場景
- 期望
- 問題
- 解決思路
- 考慮超時重試情況;
- 考慮DNS緩存;
- 輸出curl_error($ch);
 
- 最終結果
- 擴展鏈接
- 其他錯誤解決方法:
- SSL: no alternative certificate subject name matches target host name
- curl: (60) SSL certificate problem: unable to get local issuer certificate
- Empty reply from server
 
 
場景
function httpGetWebInfo($url, $iptype = 6, $resolve = [], $timeout = 120) {// $header = ["Cache-Control: no-cache"];$data = [];$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); //post方式提交curl_setopt($ch, CURLOPT_NOSIGNAL, true); // 為true,會導致DNS解析不受時間控制curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 1000 * $timeout);curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000 * $timeout);curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);curl_setopt($ch, CURLOPT_HEADER, false); // 不需要輸出頭部信息 -Icurl_setopt($ch, CURLOPT_NOBODY, true); // 不輸出內容curl_setopt($ch, CURLOPT_IPRESOLVE, 4 == $iptype ? CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_V6);curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); //設置是否將響應結果存入變量,1是存入,0是直接echo出;curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //抓取跳轉 -L --location// curl_setopt($ch, CURLOPT_HTTPHEADER, $header); // HTTP 頭字段的數組// curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); // 強制獲取一個新的連接,而不是緩存中的連接// curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 0); // 禁用DNS緩存 if (!empty($resolve)) {// curl -L -I -6 www.a.com --resolve www.a.com:80:<ipaddr>curl_setopt($ch, CURLOPT_RESOLVE, $resolve);curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); //禁用DNS全局緩存}curl_exec($ch);if (!curl_errno($ch)) {$data = curl_getinfo($ch);}curl_close($ch);return $data; }# 調用 $domainIPAddr = ['www.b.com' => '1.1.1.1','www.b.com' => '240c::2', ];foreach ($domainIPAddr as $domain => $ipaddr) {var_dump(getDnsRecord($domain, DNS_AAAA));$iptype = 判斷ipaddr 類型 ? 4 : 6;$curl = httpGetWebInfo($domain, $iptype, ["{$domain}:80:{$ipaddr}"]);var_dump($curl);$state = empty($curl ) ? 0 : $curl ['http_code'];var_dump([$domain=>$state]); }## 問題: 當打印出resolve IPv6時的 curl 缺總是顯示 IPv4的信息解決方式: 添加curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false);期望
使用IPv6解析DNS,并返回狀態碼
問題
通過CURLOPT_IPRESOLVE 控制使用IPv4解析域名還是IPv6解析,
但是當解析的域名不存在IPv6時,仍舊返回200的狀態碼,
curl_setopt($ch, CURLOPT_NOSIGNAL, true); curl_setopt($ch, CURLOPT_IPRESOLVE, 4 == $iptype ? CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_V6);解決思路
考慮超時重試情況;
因為 curl在請求時,會默認請求域名解析的ipv6地址,如果ipv6地址請求失敗,會timeout秒后請求正常的ipv4地址,所以這個時候,我們強制設置curl請求時,用ipv4地址
后經過排查返回的是結果是使用IPv4地址解析的,所以一直報200;
 是因為 curl_setopt($ch, CURLOPT_NOSIGNAL, true); 導致DNS解析不受超時限制,會自動解析IPv4;
 開啟 CURLOPT_NOSIGNAL 導致DNS解析不受超時限制
考慮DNS緩存;
所以找如何清理DNS緩存;
無法從PHP手動清除DNS緩存。但是你可以使用 CURLOPT_DNS_CACHE_TIMEOUT,您可以將選項設置為0,以用于下一個請求以強制刷新curl的DNS緩存
Pass a long, this sets the timeout in seconds. Name resolves will be kept in memory and used for this number of seconds. Set to zero to completely disable caching, or set to -1 to make the cached entries remain forever. By default, libcurl caches this info for 60 seconds.
curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 0); // 禁用DNS緩存 無效 curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); //禁用DNS全局緩存 有效另補充:禁用鏈接緩存 curl_setopt($ch, CURLOPT_HTTPHEADER, $header); // HTTP 頭字段的數組 curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); // 強制獲取一個新的連接,而不是緩存中的連接輸出curl_error($ch);
報錯信息:curl(7) xxxx permission denied
 然后tcpdump 抓包,發現從 私網IPv6 出發的只有發包沒有回包,也就是說進不到私網地址
 所以考慮 在ip6tables上創建轉發規則 ip6tables -I FORWARD -d <私網IPv6> -j ACCEPT
最終結果
ip6tables -I FORWARD -d <私網IPv6> -j ACCEPT
function httpGetWebInfo($url, $iptype = 6, $resolve = [], $timeout = 10) {$data = [];$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); //post方式提交curl_setopt($ch, CURLOPT_NOSIGNAL, FALSE); // 如何為true,會導致DNS解析不受時間控制,導致程序一直pendingcurl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 1000 * $timeout);curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000 * $timeout);curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);curl_setopt($ch, CURLOPT_HEADER, true); // 不需要輸出頭部信息 -Icurl_setopt($ch, CURLOPT_NOBODY, true); // 不輸出內容curl_setopt($ch, CURLOPT_IPRESOLVE, 4 == $iptype ? CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_V6);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //設置是否將響應結果存入變量,1是存入,0是直接echo出;curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //抓取跳轉 -L --locationif (!empty($resolve)) {// curl -L -I -6 www.a.com --resolve www.a.com:80:<ipaddr>curl_setopt($ch, CURLOPT_RESOLVE, $resolve);curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); //禁用DNS全局緩存 關鍵}curl_exec($ch);if (!curl_errno($ch)) {$data = curl_getinfo($ch);}curl_close($ch);return $data; }擴展鏈接
【PHP】 獲取網站信息
如果要支持毫秒級別的超時設置必須加CURLOPT_NOSIGNAL, 否則直接返回超時,
 當設置了小于1000ms的超時以后, curl不會發起任何請求,而直接返回超時錯誤(Timeout reached 28)】,這是PHP的坑,參考: http://www.laruence.com/2014/01/21/2939.html
 timeout支持毫秒數在cURL 7.16.2中被加入,從PHP 5.2.3起可使用。
其他錯誤解決方法:
SSL: no alternative certificate subject name matches target host name
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);參考:https://www.php.net/manual/zh/function.curl-setopt.php#75711
curl: (60) SSL certificate problem: unable to get local issuer certificate
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // false 禁止 cURL 驗證對等證書(peer's certificate)參考:https://stackoverflow.com/questions/24611640/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate
Empty reply from server
1、檢查你的代理服務器是否正常。可能當前代理服務器無法正常訪問
 2、增加超時時間,每次請求接口時間略長一些就會產生這個錯誤
總結
以上是生活随笔為你收集整理的【PHP】curl_init() 如何排错????的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【正则】匹配html标签里的内容,不含标
- 下一篇: 【Excel】日常记录
