在 PHP 中簡化 cURL 的操作

cURL 相關函數對新手不是很友善,但若是要用 PHP 下載大型檔案,又不能將之全部暫存在記憶體,使用 cURL 便是常見的作法。本篇宣告一個簡化後的 cURL :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function curl_download(
string|array $options, // 選項變數,或是下載源 URL
string $dest = '', // 要儲存的目的地
string $header_dest = '' // 儲存 http response header 的地方,如果想存的話。
) {
if (gettype($options) === 'string')
$options = array(CURLOPT_URL => $options);
if (empty($options[CURLOPT_URL])) throw new Exception;
if (empty(CURLOPT_RETURNTRANSFER) && empty($options[CURLOPT_FILE]) && ! $dest) throw new Exception;

$default = array(
CURLOPT_AUTOREFERER => true,
CURLOPT_FOLLOWLOCATION => true
);
foreach ($default as $k => $v) // 不能用 array_merge ,因為 index 會被改變
if (! array_key_exists($k, $options))
$options[$k] = $v;

if (isset($options[CURLOPT_FILE]) && gettype($options[CURLOPT_FILE]) === 'string')
$dest = $options[CURLOPT_FILE];
if ($dest) {
$options[CURLOPT_RETURNTRANSFER] = false;
$fh_file = fopen($dest, 'w');
$options[CURLOPT_FILE] = $fh_file;
}

if (isset($options[CURLOPT_WRITEHEADER]) && gettype($options[CURLOPT_WRITEHEADER]) === 'string')
$header_dest = $options[CURLOPT_WRITEHEADER];
if ($header_dest) {
// $options[CURLOPT_HEADER] = true; // this shouldn't be included; otherwise either CURLOPT_FILE or CURLOPT_RETURNTRANSFER would starts with response header.
$fh_writeheader = fopen($header_dest, 'w');
$options[CURLOPT_WRITEHEADER] = $fh_writeheader;
}

$ch = curl_init();
curl_setopt_array($ch, $options);

$result = curl_exec($ch);
if ($result === false) $result = array(
'info' => curl_getinfo($ch),
'error' => curl_error($ch)
);
curl_close($ch);

if ($dest) fclose($fh_file);
if ($header_dest) fclose($fh_writeheader);

return $result;
}

原本 CURLOPT_FILECURLOPT_WRITEHEADER 只接受 write stream ,我另外改成也可接收字串作為寫入檔的路徑。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 將目標檔案存到 `test.html`
curl_download('http://example.com', 'test.html');

// 將目標檔案讀入變數
$result = curl_download(array(
CURLOPT_URL => 'http://example.com',
CURLOPT_RETURNTRANSFER => true
));

// 確認有無錯誤
$result = curl_download('http://example.com', 'test.html');
if (is_array($result) && isset($result['error'])) {
echo $result['error'];
print_r($result['info']);
exit();
}

ref: PHP: curl_setopt - Manual