在還沒有接觸curl的時候,相信大家在獲取網頁內容的時,使用得最多的一個函數就是:file_get_contents(),但是它的可控制性不夠靈活,無法處理錯誤情況,對於各種復雜情況的采集更是顯得有點無能為力。因此,本文將為你介紹另外一種工具:cURL的使用方法,在后面也還會給出相關的幾個案例,這些都是你使用file_get_contents()無法做到的。
一、cURL庫的介紹
為了更好的理解下面的內容,這里先給出一個curl的最簡單的案例
入門案例:
$url = "http://nosee123.com/test_post.php";
$ch = curl_init($url); //初始化一個cURL會話
curl_exec($ch); //執行一個cURL會話
curl_close($ch); //關閉一個cURL會話
該案例的執行結果就是把$url的網頁內容輸出到你的瀏覽器上,其實這個案例的效果和使用file_get_contents()的結果是一樣的,這是因為它沒有設置任何的參數。但cURL的功能遠遠不止這些,下面我們開始講解cURL更詳細的使用方法。
cURL是一個可以使用URL的語法模擬瀏覽器來傳輸數據的工具庫(libcurl庫),libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap協議。libcurl同時也支持HTTPS認證、HTTP POST、HTTP PUT、 FTP 上傳(這個也能通過PHP的FTP擴展完成)、HTTP 基於表單的上傳、代理、cookies和用戶名+密碼的認證。
注意:在使用cURL庫之前,記得要先將你的配置文件(php.ini)中打開的你cURL模塊,可以使用phpinfo()查看curl模塊是否開啟,如沒有開啟就直接使用相關的方法則會報錯。
二、使用基本步驟
使用 cURL 函數的基本思想是先使用curl_init() 初始化 cURL會話,接着可以通過 curl_setopt() 設置需要的全部選項,然后使用 curl_exec()來執行會話,當執行完會話后使用curl_close()關閉會話。
簡單來說,使用cURL完成簡單的請求主要分為以下四個步驟:
//(1)初始化cURL
$url = "http://nosee123.com/test_post.php";
$ch = curl_init($url); //初始化一個cURL會話
//(2)設置URL和相應的選項
//將curl_exec()獲取的信息以字符串返回,而不是直接輸出。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//(3)抓取URL並把它傳遞給瀏覽器
//由於步驟2對CURLOPT_RETURNTRANSFER的設置,curl_exec()不會直接輸出內容
$str = curl_exec($ch); //執行一個cURL會話
//(4)關閉cURL資源,並且釋放系統資源
curl_close($ch); //關閉一個cURL會話
echo $str; //輸出步驟3獲取的頁面內容
上面的4個步驟將會把獲取到的網頁內容輸出,這是使用cURL最基本的四個步驟。
三、curl_setopt常用參數
cURL之所以強大,只要是體現在它的第二個步驟中。你可以通過curl_setopt靈活地設置請求選項,更多的參數設置查看官網:http://php.net/manual/zh/function.curl-setopt.php
官方上羅列的是所有的參數列表,全部都記住也沒有什么必要。然而實際開發中,我們常用的也就來來去去那幾個,所以在這我也順便把常用的幾個都詳細講講,這樣也方便我們更好的快速的用到實際開發中。但建議有時間的話最好把官網上的都看一篇,這樣至少自己心里也有個底,知道里面有些什么方法,當真正需要的時候也方便過來查找。
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);//將curl_exec()獲取的信息以字符串返回,而不是直接輸出。
curl_setopt($ch, CURLOPT_HEADER,false);//不輸出頭文件,如果設為true,獲得的網頁源代碼最前邊會帶有'HTTP/1.1 200 OK'等內容
curl_setopt($ch, CURLOPT_FILE, $fp);//設置輸出文件,默認為STDOUT (瀏覽器)。
curl_setopt($ch, CURLOPT_POST, 1);// 設置請求為post類型
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);// 添加post數據到請求中
四、cURL常用函數
除了上面基本的4個步驟用到的4個函數,cURL還提供了其他很多實用的函數,如curl_error、curl_getinfo等。
獲取curl請求的具體信息: curl_getinfo()
在執行一個cURL請求后,你也可以使用curl_getinfo獲取該請求的具體信息:
curl_exec($ch);
$curl_info= curl_getinfo($ch);
echo "收到的http回復的code為: {$curl_info['http_code']}";
上述$curl_info是一個關聯數組,可以從中獲取很多的具體請求信息。
參考:http://php.net/manual/zh/function.curl-getinfo.php
錯誤處理:curl_error()
$response = curl_exec($ch);
if ($response === FALSE) {
echo "cURL 具體出錯信息: " . curl_error($ch);
}
注意了,在做上述判斷時務必要使用===,因為請求的回復可能是空字符串,curl在請求出錯的情況下回返回FALSE值,所以我們必須使用===,而不是==
參考:http://php.net/manual/zh/function.curl-error.php
五、實用案例
案例1:使用curl發送post請求
$url = "http://nosee123.com/test_post.php";
$post_data = array (
"name" => "nosee",
"url" => "http://www.nosee123.com",
"action" => "Submit"
);
$ch = curl_init($url );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, 1);// 設置請求為post類型
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);// 添加post數據到請求中
$str = curl_exec($ch);// 執行post請求,獲得回復
curl_close($ch);
echo $str ;
案例2:將獲取到的內容輸出到文件(文件下載)
$url = "http://nosee123.com/86-1.zip"; //遠程服務器上要下載的文件
$fp = fopen("output.zip", "w"); //打開一個本地文件指針資源
$ch = curl_init($url); //初始化一個cURL會話
curl_setopt($ch, CURLOPT_FILE, $fp); //設置輸出文件,默認為STDOUT (瀏覽器)。
$str = curl_exec($ch); //執行一個cURL會話
if ($str === FALSE) {
echo "cURL 具體出錯信息: " . curl_error($ch);
}
curl_close($ch); //關閉一個cURL會話
fclose($fp); //關閉一個已打開的文件指針
案例3:文件上傳
PHP使用CURL上傳文件只需發送一個POST請求就可以了,在請求中設置某個字段為需要上傳的文件全路徑,並且以“@”開頭,然后使用CURL把該變量以POST方式發送到服務器,在服務端即可以從超級全局變量$_FILES中取到相應的上傳文件信息。需要注意的是,上傳文件的變量不是存在着$_POST中,而是在$_FILES中。
以下代碼是存在我本地服務器的腳本:
$url = "http://nosee123.com/test_post.php";
$post_data = array (
//要上傳的本地的文件地址
"attachment" => "@D:/web/www/wp70/readme.html""
);
//初始化cURL會話
$ch = curl_init();
//設置請求的url
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
//設置為post請求類型
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);//重點!下面詳細講解
//設置具體的post數據
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$response = curl_exec($ch);
if ($response === FALSE) {
echo "cURL 具體出錯信息: " . curl_error($ch);
}
curl_close($ch);
print_r($response);
我的遠程服務端處理請求的腳本文件:test_post.php 如下:
//首先使用var_export將$_FILES變量輸出到標准輸出
echo var_export($_FILES,true);
//然后使用file_get_contents讀取$_FILES[‘attachment’][‘tmp_name’]所指文件的內容,並輸出到標准輸出
echo file_get_contents($_FILES['attachment']['tmp_name']);
//然后把$_FILES[‘attachment’][‘tmp_name’]所指文件自制到當前目錄的log_copy.txt文件中
copy($_FILES['attachment']['tmp_name'], "./testdata_copy.txt");
可以看到$_FILES變量中有一個attachment數組,對應到上傳文件描述信息,其中name和type分別表示名稱和類型。tmp_name比較關鍵,服務端在接收到上傳文件之后,會把文件寫在一個臨時文件中,這個臨時文件的名字就是tmp_name的值,這也是為什么我們讀取該文件可以獲取一testdata.txt的文件內容。一般在服務端接收到上傳文件后都需要立即讀取該文件或者把文件復制到別外一個文件中,因為tmp_name所指的臨時文件在服務端腳本執行完畢后會被刪除掉,test_post.php腳本的最后一行就是把臨時文件復制到我們的目標文件中。
還有一個重點問題,這個問題也是折騰了我整整一天的,因為一開始我的請求代碼里面沒有加curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);這一段代碼,上傳文件一直失敗,@后面的文件地址無法被解析。一直到最后我才發現了那是因為php版本兼容性的問題。對於PHP5.6及以上的版本是不會直接識別@綁定的后面的地址,那要怎么解決這個兼容性問題呢?有兩種解決方法:
1)就如我上面的代碼,使用配置參數 CURLOPT_SAFE_UPLOAD ,在 PHP5.5中默認值是 false ,而在 PHP5.6中已經默認為 true 了。 所以只需要增加一行強制設置為 false 就行,如下:
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
注意:該參數的設置順序,必須在設置 CURLOPT_POSTFIELDS 參數之前才有效哦!!!
2)使用 CURLFile 類來處理文件
在上面代碼的基礎上,把變量$post_data修改為如下代碼即可:
$post_data = array (
"attachment" => new CURLFile("D:/web/www/wp70/readme.html")
);
詳細參考官方文檔:http://php.net/manual/zh/class.curlfile.php
案例4:發送json數據
$posturl='http://nosee123.com/test_json.php';
$array=array ('key'=>'abc','phone'=>'18813912321','userid'=>'1234321');
$jsoninfo = json_encode($array); //把數組進行json編碼
//模擬post請求
$ch = curl_init();//初始化curl
if ( $ch === FALSE ){
return 'ERROR: Sorry , you cannot open curl. --- nosee';
}
curl_setopt($ch, CURLOPT_URL,$posturl); //抓取指定網頁
curl_setopt($ch, CURLOPT_HEADER, 0); //設置header
//這一步為最關鍵!!設置head頭的請求數據格式為json
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-type:application/json;charset=utf-8",
"Content-Length: " . strlen($jsoninfo)
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求結果為字符串且輸出到屏幕上
curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsoninfo); //添加請求的json數據
$data = curl_exec($ch); //運行curl 返回請求的json數據
$json = json_decode($data); //把json數據轉為php的對象類型
curl_close($ch); //關閉curl
使用用curl傳輸json數據的實際案例可查看我的上一篇文章:使用php接入圖靈機器人的方法
向圖靈機器人的API提交json數據的POST請求中,本人使用的就是這個方法。
更多cURL的案例和使用方法可查看官方文檔,地址如下:
http://php.net/manual/zh/book.curl.php
感謝閱讀
原文地址:https://www.jianshu.com/p/97243d2153c2