<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ankur&#039;s PHP and Javascript blog &#187; cURL</title>
	<atom:link href="http://www.ankur.com/blog/tag/curl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ankur.com/blog</link>
	<description>PHP and javascript blog</description>
	<lastBuildDate>Tue, 10 Nov 2009 14:28:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Resume HTTP downloads in PHP using cURL or fsockopen</title>
		<link>http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=resume-http-downloads-php-curl-fsockopen</link>
		<comments>http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 17:14:29 +0000</pubDate>
		<dc:creator>Ankur Motreja</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cURL]]></category>
		<category><![CDATA[HTTP]]></category>

		<guid isPermaLink="false">http://www.ankur.com/blog/?p=106</guid>
		<description><![CDATA[This post describes a method to download a file using a PHP script and resume the download if the previous download was interrupted. The code here could be used while downloading a new version of a PHP application from the application author&#8217;s website. Two implementation examples are provided &#8211; one using cURL and another using [...]


Related posts:<ol><li><a href='http://www.ankur.com/blog/68/php/curl-wrapper-class-cli-php-extension-support/' rel='bookmark' title='Permanent Link: cURL wrapper class with executable and PHP extension support'>cURL wrapper class with executable and PHP extension support</a></li><li><a href='http://www.ankur.com/blog/90/php/domain-whois-query-php/' rel='bookmark' title='Permanent Link: Domain name WHOIS query using PHP'>Domain name WHOIS query using PHP</a></li><li><a href='http://www.ankur.com/blog/83/php/javascript-css-compression-yui-compressor-php-gzip/' rel='bookmark' title='Permanent Link: Javascript and CSS compression using YUI compressor, PHP and gzip'>Javascript and CSS compression using YUI compressor, PHP and gzip</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>This post describes a method to download a file using a PHP script and resume the download if the previous download was interrupted. The code here could be used while downloading a new version of a PHP application from the application author&#8217;s website. Two implementation examples are provided &#8211; one using cURL and another using fsockopen.</p>
<p><span id="more-106"></span></p>
<h3>Range header of the HTTP protocol</h3>
<p>First, lets start by seeing how the HTTP protocol allows downloads to be resumed. If you don&#8217;t already have PuTTY, get it from <a rel="nofollow" title="PuTTY" rel="nofollow" href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html" target="_blank">here</a>. We will use PuTTY to directly connect to a HTTP server, send it some HTTP headers and see the response.</p>
<p>Create a text file with some text in it (at least 20 characters long to make it easier for us to test). Upload it so it is accessible at http://localhost/file.txt . I have used the URL http://localhost/file.txt . Change the settings below according to your URL. Open PuTTY and use the following settings:</p>
<p>Host Name: localhost<br />
Port: 80<br />
Connection Type: Raw<br />
Close window on exit: Never</p>
<p>Click on Open. In the window that shows up, type the following:</p>
<pre class="brush: plain;">
GET /file.txt HTTP/1.1
Host: localhost
Range: bytes=5-
Connection: Close
</pre>
<p>Make sure you hit enter twice after typing the text above. You should see something like the text below if you had used something like &#8220;abcdefghijklmnopqrstuvwxyz&#8221; as the contents of file.txt:</p>
<pre class="brush: plain;">
HTTP/1.1 206 Partial Content
Date: Fri, 06 Nov 2009 16:25:07 GMT
Server: Apache/2.2.12 (Win32) mod_ssl/2.2.12 OpenSSL/0.9.8k
Last-Modified: Fri, 06 Nov 2009 15:56:25 GMT
ETag: &quot;4000000044a82-1a-477b5e2d8093c&quot;
Accept-Ranges: bytes
Content-Length: 21
Content-Range: bytes 5-25/26
Connection: close
Content-Type: text/plain

fghijklmnopqrstuvwxyz
</pre>
<p>You can see that it has returned a few headers followed by the contents of the file starting from the 6th byte. Try it a few more times modifying the Range header (for example, 5-15 to get bytes 6 to 16).</p>
<h3>Using cURL to resume downloads</h3>
<p>Resuming a download using cURL is quite straight forward. We use the CURLOPT_RANGE option to set the range if the file we are trying to download already exists and use the &#8220;a&#8221; option to fopen to append the contents to the file. The code is below:</p>
<pre class="brush: php;">
$url=&quot;http://localhost/file.txt&quot;;
$fileName = &quot;file.txt&quot;;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);

if (file_exists($fileName)) {
	$from = filesize($fileName);
	curl_setopt($ch, CURLOPT_RANGE, $from . &quot;-&quot;);
}

$fp = fopen($fileName, &quot;a&quot;);
if (!$fp) {
	exit;
}
curl_setopt($ch, CURLOPT_FILE, $fp);
$result = curl_exec($ch);
curl_close($ch);

fclose($fp);
</pre>
<h3>Using fsockopen to resume downloads</h3>
<p>Resuming a download with fsockopen is more involved as it requires us to send the request headers and then parse the response headers:</p>
<pre class="brush: php;">
$url=&quot;http://localhost/file.txt&quot;;
$fileName = &quot;file.txt&quot;;

$partialContent = false;
$finalFileSize = 0;

$urlParts = parse_url($url);
$socketHandler = fsockopen($urlParts[&quot;host&quot;], 80, $errno, $errstr, 30);
if (!$socketHandler) {
	exit;
} else {
	$from = 0;

	if (file_exists($fileName)) {
		$from = filesize($fileName);
	}

	$out = &quot;GET &quot; . $urlParts[&quot;path&quot;] . &quot; HTTP/1.1\r\n&quot;;
	$out .= &quot;Host: &quot; . $urlParts[&quot;host&quot;] . &quot;\r\n&quot;;
	$out .= &quot;Range: bytes=&quot; . $from . &quot;-\r\n&quot;;
	$out .= &quot;Connection: Close\r\n\r\n&quot;;

	$headerFound = false;

	if (!$fileHandler = fopen($fileName, &quot;a&quot;)) {
		exit;
	}

	fwrite($socketHandler, $out);
	while (!feof($socketHandler)) {
		if ($headerFound) {
			if ($partialContent) {
				$result = fread($socketHandler, 8192);

				if (fwrite($fileHandler, $result) === false) {
					exit;
				}
			} else {
				fclose($fileHandler);
				fclose($socketHandler);
				exit;
			}
		} else {
			$result = fgets($socketHandler, 8192);
			$result = trim($result);
			if ($result === &quot;&quot;) {
				$headerFound = true;
			}

			if (strstr($result, &quot;206 Partial Content&quot;)) {
				$partialContent = true;
			}

			if (preg_match(&quot;/^Content-Range: bytes (\d+)-(\d+)\/(\d+)$/&quot;, $result, $matches)) {
				$finalFileSize = intval($matches[3]);
			}
		}
	}
	fclose($fileHandler);
	fclose($socketHandler);

	clearstatcache();

	if (filesize($fileName) == $finalFileSize) {
		// success
	} else {
		exit;
	}
}
</pre>


<p>Related posts:<ol><li><a href='http://www.ankur.com/blog/68/php/curl-wrapper-class-cli-php-extension-support/' rel='bookmark' title='Permanent Link: cURL wrapper class with executable and PHP extension support'>cURL wrapper class with executable and PHP extension support</a></li><li><a href='http://www.ankur.com/blog/90/php/domain-whois-query-php/' rel='bookmark' title='Permanent Link: Domain name WHOIS query using PHP'>Domain name WHOIS query using PHP</a></li><li><a href='http://www.ankur.com/blog/83/php/javascript-css-compression-yui-compressor-php-gzip/' rel='bookmark' title='Permanent Link: Javascript and CSS compression using YUI compressor, PHP and gzip'>Javascript and CSS compression using YUI compressor, PHP and gzip</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cURL wrapper class with executable and PHP extension support</title>
		<link>http://www.ankur.com/blog/68/php/curl-wrapper-class-cli-php-extension-support/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=curl-wrapper-class-cli-php-extension-support</link>
		<comments>http://www.ankur.com/blog/68/php/curl-wrapper-class-cli-php-extension-support/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 17:19:19 +0000</pubDate>
		<dc:creator>Ankur Motreja</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[cURL]]></category>

		<guid isPermaLink="false">http://www.ankur.com/blog/?p=68</guid>
		<description><![CDATA[Most cURL wrapper classes I found could handle either the PHP extension or the command line executable version of cURL. I needed a class where I could set one variable and have it switch from using the PHP cURL extension to the cURL executable without having to change the other variable of the class.
The class [...]


Related posts:<ol><li><a href='http://www.ankur.com/blog/76/php/aes-wrapper-class-pure-php-mcrypt-extension-support/' rel='bookmark' title='Permanent Link: AES wrapper class with pure php and MCrypt extension support'>AES wrapper class with pure php and MCrypt extension support</a></li><li><a href='http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/' rel='bookmark' title='Permanent Link: Resume HTTP downloads in PHP using cURL or fsockopen'>Resume HTTP downloads in PHP using cURL or fsockopen</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>Most cURL wrapper classes I found could handle either the PHP extension or the command line executable version of cURL. I needed a class where I could set one variable and have it switch from using the PHP cURL extension to the cURL executable without having to change the other variable of the class.</p>
<p><span id="more-68"></span>The class I came up with is below:</p>
<pre class="brush: php; collapse: true; light: false; toolbar: true;">

class Curl {

	// Set to &quot;PHP&quot; or the path to the curl executable (binary)
	var $curlExecutable = &quot;PHP&quot;;

	// URL to request, request type (GET or POST), request parameters as an associative array or null for none
	var $url;
	var $requestType = &quot;GET&quot;;
	var $parameters = null;

	// request headers as an array
	var $requestHeaders = array();

	// certification authority, return data with headers, follow redirects and verify peer if URL is https
	var $cainfo = null;
	var $outputWithHeaders = false;
	var $followLocation = false;
	var $SSLVerifyPeer = true;

	// connect to remote server timeout and timeout to download the entire page
	var $connectTimeout = 30;
	var $timeout = 10800;

	// if there was an error, errorNumber and error is populated. data contains the page downloaded
	var $error = null;
	var $errorNumber = null;
	var $data = null;

	function fetchPage() {

		if ($this-&gt;curlExecutable == &quot;PHP&quot;) {
			$ch = curl_init();

			if ($this-&gt;cainfo) {
				curl_setopt($ch, CURLOPT_CAINFO, $this-&gt;cainfo);
			}

			if ($this-&gt;SSLVerifyPeer) {
				curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
			} else {
				curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			}

			if ($this-&gt;requestType === &quot;POST&quot;) {
				curl_setopt($ch, CURLOPT_POST, 1);

				if ($this-&gt;parameters) {
					if (is_array($this-&gt;parameters)) {

						$encodedParameters = &quot;&quot;;
						$join = &quot;&quot;;

						foreach ($this-&gt;parameters as $name =&gt; $value) {
							$encodedParameters = $encodedParameters . $join . rawurlencode($name) . &quot;=&quot; . rawurlencode($value);
							$join = &quot;&amp;&quot;;
						}

						curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedParameters);

					} elseif (is_string($this-&gt;parameters)) {

						curl_setopt($ch, CURLOPT_POSTFIELDS, $this-&gt;parameters);

					}
				}

			} else {
				curl_setopt($ch, CURLOPT_POST, 0);

				if ($this-&gt;parameters) {
					$encodedParameters = &quot;&quot;;
					$join = &quot;?&quot;;

					foreach ($this-&gt;parameters as $name =&gt; $value) {
						$encodedParameters = $encodedParameters . $join . rawurlencode($name) . &quot;=&quot; . rawurlencode($value);
						$join = &quot;&amp;&quot;;
					}

					$this-&gt;url = $this-&gt;url . $encodedParameters;
				}

			}

			curl_setopt($ch, CURLOPT_HTTPHEADER, $this-&gt;requestHeaders);

			if ($this-&gt;outputWithHeaders) {
				curl_setopt($ch, CURLOPT_HEADER, 1);
			} else {
				curl_setopt($ch, CURLOPT_HEADER, 0);
			}

			if ($this-&gt;followLocation) {
				curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
			} else {
				curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
			}

			curl_setopt($ch, CURLOPT_URL, $this-&gt;url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this-&gt;connectTimeout);
			curl_setopt($ch, CURLOPT_TIMEOUT, $this-&gt;timeout);

			$this-&gt;data = curl_exec($ch);
			$this-&gt;error = curl_error($ch);
			$this-&gt;errorNumber = curl_errno($ch);
			curl_close($ch);

			if ($this-&gt;error) {
				return false;
			} else {
				return true;
			}

		} else {

			$command = $this-&gt;executable;

			$command = $command . &quot; -s -S&quot;;

			$command = $command . &quot; --connect-timeout &quot; . $this-&gt;connectTimeout;
			$command = $command . &quot; --max-time &quot; . $this-&gt;timeout;

			if ($this-&gt;cainfo) {
				$command = $command . &quot; --cacert \&quot;&quot; . $this-&gt;cainfo . &quot;\&quot;&quot;;
			}

			if ($this-&gt;outputWithHeaders) {
				$command = $command . &quot; -i&quot;;
			}

			if ($this-&gt;followLocation) {
				$command = $command . &quot; -L&quot;;
			}

			for ($i = 0; $i &lt; count($this-&gt;requestHeaders); $i++) {
				$command = $command . &quot; -H \&quot;&quot; . $this-&gt;requestHeaders[$i] . &quot;\&quot;&quot;;
			}

			if ($this-&gt;parameters){
				$encodedParameters = &quot;&quot;;
				$join = &quot;&quot;;

				foreach ($this-&gt;parameters as $name =&gt; $value) {
					$encodedParameters = $encodedParameters . $join . rawurlencode($name) . &quot;=&quot; . rawurlencode($value);
					$join = &quot;&amp;&quot;;
				}

				$command = $command . &quot; -d &quot; . escapeshellarg($encodedParameters) . &quot;&quot;;
			}

			if ($this-&gt;requestType === &quot;GET&quot;) {
				$command = $command . &quot; -G&quot;;
			}

			$command = $command . &quot; &quot; . $this-&gt;url;

			$descriptorspec = array(
			0 =&gt; array(&quot;pipe&quot;, &quot;r&quot;),
			1 =&gt; array(&quot;pipe&quot;, &quot;w&quot;),
			2 =&gt; array(&quot;pipe&quot;, &quot;w&quot;)
			);

			$process = proc_open($command, $descriptorspec, $pipes);

			if (is_resource($process)) {

				fclose($pipes[0]);    // close stdin as we are not going to supply any input

				$this-&gt;data = stream_get_contents($pipes[1]);    // read stdout
				$this-&gt;error = stream_get_contents($pipes[2]);    // read stderr

				fclose($pipes[1]);
				fclose($pipes[2]);

				$this-&gt;errorNumber = proc_close($process);

			} else {

				return false;

			}

			if ($this-&gt;errorNumber === 0) {
				return true;
			} else {
				return false;
			}

		}

	}

}
</pre>
<p>The following example fetches http://www.google.com :</p>
<pre class="brush: php; collapse: true; light: false; toolbar: true;">
$request = new Curl;
$request-&gt;curlExecutable = &quot;PHP&quot;;
$request-&gt;followLocation = true;
$request-&gt;url = &quot;http://www.google.com&quot;;
if ( $request-&gt;fetchPage() ) {
	header(&quot;Content-Type:text/plain&quot;);
	echo $request-&gt;data;
} else {
	echo &quot;An error occured: &quot; . $request-&gt;errorNumber . &quot; - &quot; . $request-&gt;error;
}
</pre>
<p>This example fetches a random quote (the ones tou see on the top right of this website):</p>
<pre class="brush: php; collapse: true; light: false; toolbar: true;">
$request = new Curl;
$request-&gt;curlExecutable = &quot;PHP&quot;;
$request-&gt;url = &quot;http://www.ankur.com/quotes.php&quot;;
$request-&gt;requestType = &quot;GET&quot;;
$request-&gt;parameters = array(
	&quot;action&quot; =&gt; &quot;random&quot;
);
if ( $request-&gt;fetchPage() ) {
	header(&quot;Content-Type:text/plain&quot;);
	echo $request-&gt;data;
} else {
	echo &quot;An error occured: &quot; . $request-&gt;errorNumber . &quot; - &quot; . $request-&gt;error;
}
</pre>
<p>Unrelated to the cURL wrapper class, you can try changing the action parameter from random to all to fetch all the quotes.</pre>


<p>Related posts:<ol><li><a href='http://www.ankur.com/blog/76/php/aes-wrapper-class-pure-php-mcrypt-extension-support/' rel='bookmark' title='Permanent Link: AES wrapper class with pure php and MCrypt extension support'>AES wrapper class with pure php and MCrypt extension support</a></li><li><a href='http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/' rel='bookmark' title='Permanent Link: Resume HTTP downloads in PHP using cURL or fsockopen'>Resume HTTP downloads in PHP using cURL or fsockopen</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.ankur.com/blog/68/php/curl-wrapper-class-cli-php-extension-support/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
