Following redirects with Curl in PHP.

FROM:https://evertpot.com/curl-redirect-requestbody/

As a good web citizen, I try to always follow redirects. Not just in my browser, 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.

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_POSTFIELDS, "foo");
curl_setopt($curl, CURLOPT_POST, true);

curl_exec($curl);

?>

Assuming the given url actually redirects like this:

HTTP/1.1 301 Moved Permanently
Location: /newendpoint

Curl will automatically just stop. To make it follow redirects, the FOLLOWLOCATION setting is needed, as such:

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_POSTFIELDS, "foo");
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_POST, true);

curl_exec($curl);

?>

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 request after the POST.

GET /newendpoint HTTP/1.1

This is also the default behavior for browsers, but actually non-conforming with 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 of CURLOPT_POST:

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_POSTFIELDS, "foo");
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

curl_exec($curl);

?>

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 request you probably had a request body attached.

There’s two ways to supply a request body, as a string or as a stream. If we were uploading a file it makes much more sense to use a stream, because it unlike 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 nameCURLOPT_PUT fool you, it’s use for every request, and without CURLOPT_PUT, CURLOPT_INFILE is ignored.

For example, this is how we could upload a large file using POST.

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_PUT, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_INFILE, fopen('largefile.json', 'r'));

curl_exec($curl);

?>

This will work great, unless the target location redirects. If it does, curl will throw the following error:

Necessary data rewind wasn't possible (code #65)

This seems to be related to PHP bug #47204.

Basically this means that you cannot use CURLOPT_INFILE and CURLOPT_FOLLOWLOCATION together. There’s two alternatives:

  1. Don’t use CURLOPT_INFILE, but send the request body as a string instead, withCURLOPT_POSTFIELDS.
  2. Don’t use CURLOPT_FOLLOWLOCATION, but instead manually check if the response was a 3xx redirect and manually follow each hop.

Strings

Using CURLOPT_POSTFIELDS you can supply a request body as a string. Lets try to upload our earlier failed request using that method:

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_POSTFIELDS, file_get_contents('largefile.json'));

curl_exec($curl);

?>

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 empty request body.

To fix this, use the undocumented CURLOPT_POSTREDIR option.

<?php

$curl = curl_init('http://example.org/someredirect');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_POSTFIELDS, file_get_contents('largefile.json'));
curl_setopt($curl, CURLOPT_POSTREDIR, 3);

curl_exec($curl);

?>

According to the PHP changelog, this was added in PHP 5.3.2, and according to PHP bug #49571there are four possible values:

0 -> do not set any behavior
1 -> follow redirect with the same type of request only for 301 redirects.
2 -> follow redirect with the same type of request only for 302 redirects.
3 -> follow redirect with the same type of request both for 301 and 302 redirects.
Looking for a PHP developer for your next project? I’m looking for work! Check out my resume or drop me a line!

时间的维度

今天整理几年前的照片,感觉所有的事情都会有一个时间区间。例如,现在用了各种手机各种云服务里面的照片,几年后账户都忘了,再过几年某个云服务关闭,数据清空,那些过往的照片也随之删除。有人说,我可以备份啊,我这里只是举一个照片的例子,你不可能备份所有的照片、视频、邮件、工作文档等等等。

如果放大一点想,你身边的人父母家人亲戚朋友同事等等。在200年之后,基本上都会从存在的人类记忆中删除,除非有一些文字图片视频记录。但谁也不能保证记录能够存留多久…

想问个问题,大家是怎么训练自己发现问题的眼光的?

想问个问题,大家是怎么训练自己发现问题的眼光的?
举个例子,例如现在的理发店都会推销这个推销那个,很讨厌,现在的十元快剪就很流行。

# 2016年4月4日11:05:35,通常一个人气旺的餐馆,反正环境可以达到7-8分,口味6-8分都可以接受,服务态度至少要7分。在观察下其他的差的餐馆,这三点都做的不怎么样