summaryrefslogtreecommitdiffstats
path: root/inc/download.inc.php
blob: 39f8e2e25a618cf0e0a71a38b9e6160641340d54 (plain) (blame)
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php

class Download
{

	private static $curlHandle = false;

	/**
	 * Common initialization for download and downloadToFile
	 * Return file handle to header file
	 */
	private static function initCurl($url, $timeout, &$head)
	{
		if (self::$curlHandle === false) {
			self::$curlHandle = curl_init();
			if (self::$curlHandle === false) {
				Util::traceError('Could not initialize cURL');
			}
			curl_setopt(self::$curlHandle, CURLOPT_CONNECTTIMEOUT, ceil($timeout / 2));
			curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $timeout);
			curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
			curl_setopt(self::$curlHandle, CURLOPT_AUTOREFERER, true);
			curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
			curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 6);
		}

		curl_setopt(self::$curlHandle, CURLOPT_URL, $url);

		$tmpfile = tempnam('/tmp/', 'bwlp-');
		$head = fopen($tmpfile, 'w+b');
		unlink($tmpfile);
		if ($head === false)
			Util::traceError("Could not open temporary head file $tmpfile for writing.");
		curl_setopt(self::$curlHandle, CURLOPT_WRITEHEADER, $head);
		return self::$curlHandle;
	}

	/**
	 * Read 10kb from the given file handle, seek to 0 first,
	 * close the file after reading. Returns data read
	 */
	private static function getContents($fh)
	{
		fseek($fh, 0, SEEK_SET);
		$data = fread($fh, 10000);
		fclose($fh);
		return $data;
	}

	/**
	 * Download file, obey given timeout in seconds
	 * Return data on success, false on failure
	 */
	public static function asString($url, $timeout, &$code)
	{
		$ch = self::initCurl($url, $timeout, $head);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		$data = curl_exec($ch);
		$head = self::getContents($head);
		if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) {
			$code = (int) array_pop($out[1]);
		} else {
			$code = 999;
		}
		return $data;
	}

	/**
	 * POST-Download file, obey given timeout in seconds
	 * Return data on success, false on failure
	 * @param string $url URL to fetch
	 * @param array|false $params POST params to set in body, list of key-value-pairs
	 * @param int $timeout timeout in seconds
	 * @param int $code HTTP response code, or 999 on error
	 */
	public static function asStringPost($url, $params, $timeout, &$code)
	{
		$string = '';
		if (is_array($params)) {
			foreach ($params as $k => $v) {
				if (!empty($string)) {
					$string .= '&';
				}
				$string .= $k . '=' . urlencode($v);
			}
		}
		$ch = self::initCurl($url, $timeout, $head);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $string);
		$data = curl_exec($ch);
		$head = self::getContents($head);
		if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) {
			$code = (int) array_pop($out[1]);
		} else {
			$code = 999;
		}
		return $data;
	}

	/**
	 * Download a file from a URL to file.
	 *
	 * @param string $target destination path to download file to
	 * @param string $url URL of file to download
	 * @param int $timeout timeout in seconds
	 * @param int $code HTTP status code passed out by reference
	 * @return boolean
	 */
	public static function toFile($target, $url, $timeout, &$code)
	{
		$fh = fopen($target, 'wb');
		if ($fh === false)
			Util::traceError("Could not open $target for writing.");
		$ch = self::initCurl($url, $timeout, $head);
		curl_setopt($ch, CURLOPT_FILE, $fh);
		$res = curl_exec($ch);
		$head = self::getContents($head);
		fclose($fh);
		if ($res === false) {
			@unlink($target);
			return false;
		}
		if (preg_match_all('#^HTTP/\d+\.\d+ (\d+) #m', $head, $out)) {
			$code = (int) array_pop($out[1]);
		} else {
			$code = '999 ' . curl_error($ch);
		}
		return true;
	}

}