|
為什么要用 cURL?
是的,我們可以通過其他辦法獲取網(wǎng)頁內(nèi)容。大多數(shù)時候,我因為想偷懶,都直接用簡單的php函數(shù):
$content = file_get_contents("http://www.jb51.NET");
// or
$lines = file("http://www.jb51.NET");
// or
readfile(http://www.jb51.NET);
不過,這種做法缺乏靈活性和有效的錯誤處理。而且,你也不能用它完成一些高難度任務(wù)――比如處理coockies、驗證、表單提交、文件上傳等等。
引用:
cURL 是一種功能強大的庫,支持很多不同的協(xié)議、選項,能提供 URL 請求相關(guān)的各種細節(jié)信息。
基本結(jié)構(gòu)
在學(xué)習(xí)更為復(fù)雜的功能之前,先來看一下在php中建立cURL請求的基本步驟:
- 初始化
- 設(shè)置變量
- 執(zhí)行并獲取結(jié)果
- 釋放cURL句柄
// 1. 初始化
$ch = curl_init();
// 2. 設(shè)置選項,包括URL
curl_setopt($ch, CURLOPT_URL, "http://www.jb51.NET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 3. 執(zhí)行并獲取HTML文檔內(nèi)容
$output = curl_exec($ch);
// 4. 釋放curl句柄
curl_close($ch);
第二步(也就是 curl_setopt() )最為重要,一切玄妙均在此。有一長串cURL參數(shù)可供設(shè)置,它們能指定URL請求的各個細節(jié)。要一次性全部看完并理解可能比較困難,所以今天我們只試一下那些更常用也更有用的選項。
檢查錯誤
你可以加一段檢查錯誤的語句(雖然這并不是必需的):
// ...
$output = curl_exec($ch);
if ($output === FALSE) {
echo "cURL Error: " . curl_error($ch);
}
// ...
請注意,比較的時候我們用的是“=== FALSE”,而非“== FALSE”。因為我們得區(qū)分 空輸出 和 布爾值FALSE,后者才是真正的錯誤。
獲取信息
這是另一個可選的設(shè)置項,能夠在cURL執(zhí)行后獲取這一請求的有關(guān)信息:
// ...
curl_exec($ch);
$info = curl_getinfo($ch);
echo '獲取'. $info['url'] . '耗時'. $info['total_time'] . '秒';
// ...
返回的數(shù)組中包括了以下信息:
- “url” //資源網(wǎng)絡(luò)地址
- “content_type” //內(nèi)容編碼
- “http_code” //HTTP狀態(tài)碼
- “header_size” //header的大小
- “request_size” //請求的大小
- “filetime” //文件創(chuàng)建時間
- “ssl_verify_result” //SSL驗證結(jié)果
- “redirect_count” //跳轉(zhuǎn)技術(shù)
- “total_time” //總耗時
- “namelookup_time” //DNS查詢耗時
- “connect_time” //等待連接耗時
- “pretransfer_time” //傳輸前準(zhǔn)備耗時
- “size_upload” //上傳數(shù)據(jù)的大小
- “size_download” //下載數(shù)據(jù)的大小
- “speed_download” //下載速度
- “speed_upload” //上傳速度
- “download_content_length”//下載內(nèi)容的長度
- “upload_content_length” //上傳內(nèi)容的長度
- “starttransfer_time” //開始傳輸?shù)臅r間
- “redirect_time”//重定向耗時
基于瀏覽器的重定向
在第一個例子中,我們將提供一段用于偵測服務(wù)器是否有基于瀏覽器的重定向的代碼。例如,有些網(wǎng)站會根據(jù)是否是手機瀏覽器甚至用戶來自哪個國家來重定向網(wǎng)頁。
我們利用 CURLOPT_HTTPHEADER 選項來設(shè)定我們發(fā)送出的HTTP請求頭信息(http headers),包括user agent信息和默認語言。然后我們來看看這些特定網(wǎng)站是否會把我們重定向到不同的URL。
// 測試用的URL |
首先,我們建立一組需要測試的URL,接著指定一組需要測試的瀏覽器信息。最后通過循環(huán)測試各種URL和瀏覽器匹配可能產(chǎn)生的情況。
因為我們指定了cURL選項,所以返回的輸出內(nèi)容則只包括HTTP頭信息(被存放于 $output 中)。利用一個簡單的正則,我們檢查這個頭信息中是否包含了“Location:”字樣。
運行這段代碼應(yīng)該會返回如下結(jié)果:
用POST方法發(fā)送數(shù)據(jù)
當(dāng)發(fā)起GET請求時,數(shù)據(jù)可以通過“查詢字串”(query string)傳遞給一個URL。例如,在google中搜索時,搜索關(guān)鍵即為URL的查詢字串的一部分:
http://www.google.com/search?q=NETtuts
這種情況下你可能并不需要cURL來模擬。把這個URL丟給“file_get_contents()”就能得到相同結(jié)果。
不過有一些HTML表單是用POST方法提交的。這種表單提交時,數(shù)據(jù)是通過 HTTP請求體(request body) 發(fā)送,而不是查詢字串。例如,當(dāng)使用CodeIgniter論壇的表單,無論你輸入什么關(guān)鍵字,總是被POST到如下頁面:
http://codeigniter.com/forums/do_search/
你可以用php腳本來模擬這種URL請求。首先,新建一個可以接受并顯示POST數(shù)據(jù)的文件,我們給它命名為post_output.php:
print_r($_POST);
接下來,寫一段php腳本來執(zhí)行cURL請求:
$url = "http://localhost/post_output.php"; |
執(zhí)行代碼后應(yīng)該會得到以下結(jié)果:
這段腳本發(fā)送一個POST請求給 post_output.php ,這個頁面 $_POST 變量并返回,我們利用cURL捕捉了這個輸出。
文件上傳
上傳文件和前面的POST十分相似。因為所有的文件上傳表單都是通過POST方法提交的。
首先新建一個接收文件的頁面,命名為 upload_output.php:
print_r($_FILES);
以下是真正執(zhí)行文件上傳任務(wù)的腳本:
$url = "http://localhost/upload_output.php"; |
如果你需要上傳一個文件,只需要把文件路徑像一個post變量一樣傳過去,不過記得在前面加上@符號。執(zhí)行這段腳本應(yīng)該會得到如下輸出:
cURL批處理(multi cURL)
cURL還有一個高級特性――批處理句柄(handle)。這一特性允許你同時或異步地打開多個URL連接。
// 創(chuàng)建兩個cURL資源 |
這里要做的就是打開多個cURL句柄并指派給一個批處理句柄。然后你就只需在一個while循環(huán)里等它執(zhí)行完畢。
這個示例中有兩個主要循環(huán)。第一個 do-while 循環(huán)重復(fù)調(diào)用 curl_multi_exec() 。這個函數(shù)是無隔斷(non-blocking)的,但會盡可能少地執(zhí)行。它返回一個狀態(tài)值,只要這個值等于常量 CURLM_CALL_MULTI_PERFORM ,就代表還有一些刻不容緩的工作要做(例如,把對應(yīng)URL的http頭信息發(fā)送出去)。也就是說,我們需要不斷調(diào)用該函數(shù),直到返回值發(fā)生改變。
而接下來的 while 循環(huán),只在 $active 變量為 true 時繼續(xù)。這一變量之前作為第二個參數(shù)傳給了 curl_multi_exec() ,代表只要批處理句柄中是否還有活動連接。接著,我們調(diào)用 curl_multi_select() ,在活動連接(例如接受服務(wù)器響應(yīng))出現(xiàn)之前,它都是被“屏蔽”的。這個函數(shù)成功執(zhí)行后,我們又會進入另一個 do-while 循環(huán),繼續(xù)下一條URL。
還是來看一看怎么把這一功能用到實處吧:
WordPress 連接檢查器
想象一下你有一個文章數(shù)目龐大的博客,這些文章中包含了大量外部網(wǎng)站鏈接。一段時間之后,因為這樣那樣的原因,這些鏈接中相當(dāng)數(shù)量都失效了。要么是被和諧了,要么是整個站點都被功夫網(wǎng)了...
我們下面建立一個腳本,分析所有這些鏈接,找出打不開或者404的網(wǎng)站/網(wǎng)頁,并生成一個報告。
請注意,以下并不是一個真正可用的WordPress插件,僅僅是一段獨立功能的腳本而已,僅供演示,謝謝。
好,開始吧。首先,從數(shù)據(jù)庫中讀取所有這些鏈接:
// CONFIG |
我們首先配置好數(shù)據(jù)庫,一系列要排除的域名($excluded_domains),以及最大并發(fā)連接數(shù)($max_connections)。然后,連接數(shù)據(jù)庫,獲取文章和包含的鏈接,把它們收集到一個數(shù)組中($url_list)。
下面的代碼有點復(fù)雜了,因此我將一小步一小步地詳細解釋:
// 1. 批處理器 |
下面解釋一下以上代碼。列表的序號對應(yīng)著代碼注釋中的順序數(shù)字。
- 新建一個批處理器。Created a multi handle.
- 稍后我們將創(chuàng)建一個把URL加入批處理器的函數(shù) add_url_to_multi_handle() 。每當(dāng)這個函數(shù)被調(diào)用,就有一個新url被加入批處理器。一開始,我們給批處理器添加了10個URL(這一數(shù)字由 $max_connections 所決定)。
- 運行 curl_multi_exec() 進行初始化工作是必須的,只要它返回 CURLM_CALL_MULTI_PERFORM 就還有事情要做。這么做主要是為了創(chuàng)建連接,它不會等待完整的URL響應(yīng)。
- 只要批處理中還有活動連接主循環(huán)就會一直持續(xù)。
- curl_multi_select() 會一直等待,直到某個URL查詢產(chǎn)生活動連接。
- cURL的活兒又來了,主要是獲取響應(yīng)數(shù)據(jù)。
- 檢查各種信息。當(dāng)一個URL請求完成時,會返回一個數(shù)組。
- 在返回的數(shù)組中有一個 cURL 句柄。我們利用其獲取單個cURL請求的相應(yīng)信息。
- 如果這是一個死鏈或者請求超時,不會返回http狀態(tài)碼。
- 如果這個頁面找不到了,會返回404狀態(tài)碼。
- 其他情況我們都認為這個鏈接是可用的(當(dāng)然,你也可以再檢查一下500錯誤之類...)。
- 從該批次移除這個cURL句柄,因為它已經(jīng)沒有利用價值了,關(guān)了它!
- 很好,現(xiàn)在可以另外加一個URL進來了。再一次地,初始化工作又開始進行...
- 嗯,該干的都干了。關(guān)閉批處理器,生成報告。
- 回過頭來看給批處理器添加新URL的函數(shù)。這個函數(shù)每調(diào)用一次,靜態(tài)變量 $index 就遞增一次,這樣我們才能知道還剩多少URL沒處理。
我把這個腳本在我的博客上跑了一遍(測試需要,有一些錯誤鏈接是故意加上的),結(jié)果如下:
<img border="0" src="http://files.jb51.NET/upload/201106/20110602225008534.png" /> |
共檢查約40個URL,只耗費兩秒不到。當(dāng)需要檢查更加大量的URL時,其省心省力的效果可想而知!如果你同時打開10個連接,還能再快上10倍!另外,你還可以利用cURL批處理的無隔斷特性來處理大量URL請求,而不會阻塞你的Web腳本。
另一些有用的cURL 選項
HTTP 認證
如果某個URL請求需要基于 HTTP 的身份驗證,你可以使用下面的代碼:
復(fù)制內(nèi)容到剪貼板代碼:
$url = "http://www.somesite.com/members/"; |
FTP 上傳
php 自帶有 FTP 類庫, 但你也能用 cURL:
// 開一個文件指針 |
翻墻術(shù)
你可以用代理發(fā)起cURL請求:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 指定代理地址
curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');
// 如果需要的話,提供用戶名和密碼
curl_setopt($ch, CURLOPT_PROXYUSERPWD,'user:pass');
$output = curl_exec($ch);
curl_close ($ch);
回調(diào)函數(shù)
可以在一個URL請求過程中,讓cURL調(diào)用某指定的回調(diào)函數(shù)。例如,在內(nèi)容或者響應(yīng)下載的過程中立刻開始利用數(shù)據(jù),而不用等到完全下載完。
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://NET.tutsplus.com');
curl_setopt($ch, CURLOPT_WRITEFUNCTION,"progress_function");
curl_exec($ch);
curl_close ($ch);
function progress_function($ch,$str) {
echo $str;
return strlen($str);
}
這個回調(diào)函數(shù)必須返回字串的長度,不然此功能將無法正常使用。
在URL響應(yīng)接收的過程中,只要收到一個數(shù)據(jù)包,這個函數(shù)就會被調(diào)用。
小結(jié)
今天我們一起學(xué)習(xí)了cURL庫的強大功能和靈活的擴展性。希望你喜歡。下一次要發(fā)起URL請求時,考慮下cURL吧!
原文:基于php的cURL快速入門
英文原文:http://NET.tutsplus.com/tutorial%20...%20for-mastering-curl/
原文作者:Burak Guzel
php技術(shù):基于PHP的cURL快速入門教程 (小偷采集程序),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。