PHP HTTP POST не работает, когда данные cURL> 1024

Примечание: решение в конце

Если я попытаюсь выполнить HTTP POST с более чем 1024 символами, это не сработает. Зачем? Вот минимальный пример:

recipient.php:

<?php if (strlen(file_get_contents('php://input')) > 1000 || strlen($HTTP_RAW_POST_DATA) > 1000) { echo "This was a triumph."; } ?> 

sender.php:

 <?php function try_to_post($char_count) { $url = 'http://gpx3quaa.joyent.us/test/recipient.php'; $post_data = str_repeat('x', $char_count); $c = curl_init(); curl_setopt_array($c, array( CURLOPT_URL => $url, CURLOPT_HEADER => false, CURLOPT_CONNECTTIMEOUT => 999, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post_data ) ); $result = curl_exec($c); echo "{$result}\n"; curl_close($c); } for ($i=1020;$i<1030;$i++) { echo "Trying {$i} - "; try_to_post($i); } ?> 

вывод:

 Trying 1020 - This was a triumph. Trying 1021 - This was a triumph. Trying 1022 - This was a triumph. Trying 1023 - This was a triumph. Trying 1024 - This was a triumph. Trying 1025 - Trying 1026 - Trying 1027 - Trying 1028 - Trying 1029 - 

конфигурация:

 PHP Version 5.2.6 libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3 libidn/1.8 lighttpd-1.4.19 

Решение

Добавьте следующий параметр для cURL:

 curl_setopt($ch,CURLOPT_HTTPHEADER,array("Expect:")); 

Причина в том, что любой POST более 1024 символов вызывает отправку HTTP-заголовка «Ожидание: 100-продолжить», а Lighttpd 1.4. * Не поддерживает его. Я нашел для него билет: http://redmine.lighttpd.net/issues/show/1017

Говорят, что это работает в 1.5.

Вы можете убедить, что PHP-реверс завершает работу с 100-продолжением, устанавливая явный заголовок запроса:

 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); 

Таким образом, вы можете отправить запрос, сколько бы вы ни пожелали, и завиток не будет выполнять двухэтапный пост.

Об этом почти два года назад сообщалось в блоге .

Первые мысли …

На странице руководства curl_setopt говорится о CURLOPT_POSTFIELDS

«Полные данные для публикации в HTTP-сообщении« POST ». Чтобы опубликовать файл, добавьте имя файла с помощью @ и используйте полный путь. Это может быть передано как строка с urlencoded, такая как« para1 = val1 & para2 = val2 & … » или как массив с именем поля в качестве ключа и данными поля как значение. "

Может быть, ваша ценность обрабатывается так, как если бы она была указана на urlencoded и, таким образом, выглядела как длинное длинное имя без какой-либо ценности. Что-то где-то решает усечь это имя.

Может быть, вы можете изменить его на что-то вроде

 $post_data = "data=".str_repeat('x', $char_count); 

Оказывается, это было слишком легко, и проблема была немного глубже. Итак, как отлаживать?

Узнайте, что именно отправляет CURL серверу

Другая тактика отладки может заключаться в том, чтобы сформулировать командную строку curl, которая достигает того же самого, и вывести данные HTTP-запроса по мере их создания.

Тестирование сервера вручную

Вы можете исключить сервер из уравнения, выполнив запрос вручную, например, telnetting на порт 80 на вашем сервере и отправив ему запрос> 1024 символов

 POST /test/recipient.php HTTP/1.0 Host: gpx3quaa.joyent.us Content-Length:1028 xxxxx(I put 1028 chars here, no point copying them all here!) 

Я получил этот ответ

 HTTP/1.0 200 OK Connection: close Content-type: text/html; charset=UTF-8 Content-Length: 19 Date: Tue, 20 Jan 2009 21:35:16 GMT Server: lighttpd/1.4.19 This was a triumph.Connection closed by foreign host. 

Итак, по крайней мере, теперь вы знаете, что все это на стороне клиента, возможно, где-то параметр CURL или настройка конфигурации 🙁

Окончательный ответ!

Проблема заинтриговала меня, поэтому я вырыл глубже

Если вы используете CURLOPT_VERBOSE=>true , вы увидите, что CURL отправляет дополнительный заголовок на более крупные сообщения: Expect: 100-Continue . Казалось бы, вашему серверу lighttpd это не понравится.

Вы можете остановить CURL от этого, заставив его использовать HTTP / 1.0 с CURLOPT_HTTP_VERSION=>CURL_HTTP_VERSION_1_0 в вашем массиве параметров curl_setopt.

У меня была аналогичная проблема с сервером IIS с использованием SSL v3.

Я продолжал получать следующую ошибку cURL, когда CURLOPT_POSTFIELDS было больше 1024:

 52 - SSL read: error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number, errno 0 

Добавление CURLOPT_HTTPHEADER: «Ожидайте:» решила проблему для меня.

Большое вам спасибо за эту тему!

Проверьте, включен ли патч Suhosin. По умолчанию он отключает данные POST после определенного количества индексов. Вы можете обойти его в Suhosin config tho.