In curl's tradition of only doing the basics unless you tell it differently, it does not follow HTTP redirects by default. Use the -L, -location to tell it to do that. When following redirects is enabled, curl will follow up to 50 redirects by default. There's a maximum limit mostly. DESCRIPTION curl is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP). The command is designed to work without user interaction. CURL and HTTP Transaction Timing. Curl is one of the most used commands for HTTP transactions. It’s a Swiss army knife for network and application engineers when they want to quickly test whether a server application is responsive, and it also has a myriad of options to configure proxy servers, username-password pairs, encryption protocols, redirections, and much more. This is one of the often forgotten little gems in the curl arsenal of command line options.write-out or just -w for short, writes out information after a transfer has completed and it has a large range of variables that you can include in the output, variables that have been set with values and information from the transfer. In curl's tradition of only doing the basics unless you tell it differently, it does not follow HTTP redirects by default. Use the -L, -location to tell it to do that. When following redirects is enabled, curl will follow up to 50 redirects by default. There's a maximum limit mostly to avoid the risk of getting caught in endless loops.
As a good web citizen, I try to always follow redirects. Not just in mybrowser, where I actually don’t have all that much control over things,but also a consumer of web services.
When doing requests with CURL, redirects are not followed by default.
Assuming the given url actually redirects like this:
Curl will automatically just stop. To make it follow redirects, theFOLLOWLOCATION
setting is needed, as such:
CURLOPT_FOLLOWLOCATION
will follow the redirects up to 5 times (by default).
However, if you look at the second request, it actually does a GET
requestafter the POST
.
This is also the default behavior for browsers, but actually non-conformingwith the HTTP standard, and also not desirable for consumers of web services.
To fix this, all you have to do is use CURLOPT_CUSTOMREQUEST
instead ofCURLOPT_POST
:
Streams
After doing this, the secondary request will be a POST
request as well.There’s one more issue though, if you were doing a POST
or a PUT
requestyou probably had a request body attached.
There’s two ways to supply a request body, as a string or as a stream. If wewere uploading a file it makes much more sense to use a stream, because itunlike posting a string, a stream doesn’t have to be kept in memory.
To upload a stream with curl, you need CURLOPT_PUT
and CURLOPT_INFILE
.Don’t let the name CURLOPT_PUT
fool you, it’s use for every request, andwithout CURLOPT_PUT
, CURLOPT_INFILE
is ignored.
For example, this is how we could upload a large file using POST.
This will work great, unless the target location redirects. If it does, curlwill throw the following error:
This seems to be related to PHP bug #47204.
Basically this means that you cannot use CURLOPT_INFILE
andCURLOPT_FOLLOWLOCATION
together. There’s two alternatives:
- Don’t use
CURLOPT_INFILE
, but send the request body as a string instead,withCURLOPT_POSTFIELDS
. - Don’t use
CURLOPT_FOLLOWLOCATION
, but instead manually check if theresponse was a 3xx redirect and manually follow each hop.
Strings
Using CURLOPT_POSTFIELDS
you can supply a request body as a string. Letstry to upload our earlier failed request using that method:
Curl Redirect Output To File
This also will not work exactly as you expect. While the second request to/someredirect
will still be a POST request, it will be sent with an emptyrequest body.
To fix this, use the undocumented CURLOPT_POSTREDIR
option.
Curl Suppress Follow Redirect
According to the PHP changelog, this was added in PHP 5.3.2, and according toPHP bug #49571 there are four possible values:
Curl Php Follow Redirect
Here are the response codes ready for pasting in an ini-style file. Can be used to provide more descriptive message, corresponding to 'http_code' index of the arrray returned by curl_getinfo().
These are taken from the W3 consortium HTTP/1.1: Status Code Definitions, found at
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
[Informational 1xx]
100='Continue'
101='Switching Protocols'
[Successful 2xx]
200='OK'
201='Created'
202='Accepted'
203='Non-Authoritative Information'
204='No Content'
205='Reset Content'
206='Partial Content'
[Redirection 3xx]
300='Multiple Choices'
301='Moved Permanently'
302='Found'
303='See Other'
304='Not Modified'
305='Use Proxy'
306='(Unused)'
307='Temporary Redirect'
[Client Error 4xx]
400='Bad Request'
401='Unauthorized'
402='Payment Required'
403='Forbidden'
404='Not Found'
405='Method Not Allowed'
406='Not Acceptable'
407='Proxy Authentication Required'
408='Request Timeout'
409='Conflict'
410='Gone'
411='Length Required'
412='Precondition Failed'
413='Request Entity Too Large'
414='Request-URI Too Long'
415='Unsupported Media Type'
416='Requested Range Not Satisfiable'
417='Expectation Failed'
[Server Error 5xx]
500='Internal Server Error'
501='Not Implemented'
502='Bad Gateway'
503='Service Unavailable'
504='Gateway Timeout'
505='HTTP Version Not Supported'
And an example usage:
<?php
$ch = curl_init(); // create cURL handle (ch)
if (!$ch) {
die('Couldn't initialize a cURL handle');
}
// set some cURL options
$ret = curl_setopt($ch, CURLOPT_URL, 'http://mail.yahoo.com');
$ret = curl_setopt($ch, CURLOPT_HEADER, 1);
$ret = curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$ret = curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
$ret = curl_setopt($ch, CURLOPT_TIMEOUT, 30);
// execute
$ret = curl_exec($ch);
if (empty($ret)) {
// some kind of an error happened
die(curl_error($ch));
curl_close($ch); // close cURL handler
} else {
$info = curl_getinfo($ch);
curl_close($ch); // close cURL handler
if (empty($info['http_code'])) {
die('No HTTP code was returned');
} else {
// load the HTTP codes
$http_codes = parse_ini_file('path/to/the/ini/file/I/pasted/above');
// echo results
echo 'The server responded: <br />';
echo $info['http_code'] . ' ' . $http_codes[$info['http_code']];
}
}
?>