Блогът на Гонзо

Качване на файлове с cURL към Lighttpd

Днес се сблъсках с един проблем, решението на който, макар и лесно, въобще не беше очевидно. Трябваше да направим така, че когато потребителя изпрати файл към сървъра, PHP да го изпрати на друг сървър, на който инструмент, написан на Java, да го обработи, и ако всичко е ОК, нашето PHP да си запише резултата. Първото нещо, което ви хрумва сигурно е „По-сложно не можеше ли?“. Сигурно може, не сме се постарали достатъчно. А и важното е за потребителя да става лесно.

Ако потърсите примери за качване на файлове с PHP и cURL, ще намерите много, и кодът между тях не се различава. Общо взето изглежда така:

<?php
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_VERBOSE, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
    curl_setopt($ch, CURLOPT_URL, _VIRUS_SCAN_URL);
    curl_setopt($ch, CURLOPT_POST, true);
    $post = array(
        "file_box"=>"@/path/to/myfile.jpg",
    );
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 
    $response = curl_exec($ch);
?>

Този пример е от първия резултат при търсене в Google по въпроса. Обаче при мен той не сработи. Отсрещната страна непрекъснато връщаше 417 Expectation Failed. И кво не ти харесва сега? Кои точно очаквания останаха неизпълнени?

Пробвах какво ли не – разни допълнителни параметри към cUPL, добавях променливи към POST данните, опитах допълнително да подам Content type… Не става!

Значи проблема не е в заявката, а в отсрещната страна. Потърсих дали някой друг не е срещал подобен проблем, и се оказа, че да, проблемът е в отсрещния уеб сървър, който ползва Lighttpd. Значи, cURL праща заглавка Expect: 100-Continue към отсрещния сървър и очаква от него или да отговори със 100 Continue, или нищо да не отговори, при което cURL да продължи с изпращането на данните. Да де, ама разработчиците на Lighttpd са сметнали, че е най-добре да отговорят с 417 Expectation Failed. Проблемът има две решения. Едното е да накарате cURL да не изпраща заглавката, като добавите празна такава:

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

Другата възможност е да накарате Lighttpd да се държи прилично. След настоятелите молби на потребители на тоз уеб сървър е добавена конфигурационна променлива, която да промени поведението при получаване на заглавка Expect: 100-Continue. Просто в конфигурацията трябва да добавите този ред:

server.reject-expect-100-with-417 = "disable"

Аз използвах второто решение и смятам от сега нататък да добавям този ред на всички сървъри с Lighttpd, до чиято конфигурация имам достъп. Това ще спести доста време на други като мен да се чудят защо пращането на файлове с cURL или Flash не работи.

И двете решения на проблема са описани в системата за следене на бъгове на Lighttpd:

http://redmine.lighttpd.net/issues/1017

Етикети: , , ,

Comments (2)

Габрово

Благодаря за споделеният опит, полезна информация!
Лично аз си забранявам „curl“ през php.ini от съображения за сигурност.
Затова и аз бих избрал вторият вариант. :)

Stefan

Благодаря за споделения опит! Макар и след доста време , помага на доста хора.

Leave a comment

XHTML: Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>