Нужно сформировать правильный POST запрос в CURL. Сначала я делаю обычный запрос через браузер и ловлю отправленные и полученные хедеры и содержимое запроса (с помощью аддона firebug на файрфоксе), потом воспроизвожу это в своем запросе с помощью curl. Так вот, firebug выдает мне среди прочих хедеров следующие: Content-Type:multipart/form-data; boundary=---------------------------14162188131998 Content-Length:118018 Другой перехватчик хедеров, HttpAnalyzer, их не видит 1. Важны ли эти заголовки при запросе, можно ли их опустить? 2. Как правильно сформировать запрос с телом (картинкой) и параметрами? 3. Как узнать Content-Length картинки перед отправкой? В гугле по этой теме есть очень много, но ничего по делу.
1. Длина контента не оч вроде как ( если скачивал файлы думаю видел что иногдауказываеться какого он размера а иногда нет вот от указания или неуказания заголовка этого и зависит ) 2. http://ru.php.net/manual/ru/function.curl-setopt.php тонко намекну ( http://curl.haxx.se/libcurl/php/examples/httpfileupload.html ) 3. Ты картинку все равно
1. нельзя опускать 2. Code: POST адрес HTTP/1.0 Content-Type: multipart/form-data; boundary=некоторое_достаточно_уникальное_значение [boundary] Host: хост Content-Length: длина_содержимого [boundary] Content-Disposition: form-data; name="file"; filename="имя_файла" Content-Type: image/jpeg (тип) [содержимое картинки] [boundary] 3. В content-length записывается длина всего отправляемого содержимого без заголовков. Определить можно strlen.
Вот-вот. Это то самое, что возвращает мне перехватчик при отправке моего сообщения. Я только не пойму, где это настраивается. Или достаточно просто указать вот эти хедеры Content-Type: multipart/form-data; boundary=некоторое_достаточно_уникальное_значение Host: хост Content-Length: длина_содержимого Content-Disposition: form-data; name="file"; filename="имя_файла" Content-Type: image/jpeg (тип) в CURLOPT_HTTPHEADER и параметры в CURLOPT_POSTFIELDS, а всё остальное курл сформирует сам? Content-length узнал с помощью strlen(file_get_contents('имя_файла')); Заинтересовался вот этим: 1. CURLOPT_INFILESIZE : при закачке файла на удаленный сервер, следует использовать этот параметр для указания ожидаемого размера файла. (указать вместо Content-Length хедера?) 2. CURLOPT_UPLOAD : Установка этого параметра в ненулевое значение означает, что будет производиться закачка файла на удаленный сервер.(похоже тоже надо указать, поскольку я отправляю файл) 3. CURLOPT_INFILE : Файл, содержащий данные для передачи. (может, надо использовать это вместо указания имени файла среди параметров CURLOPT_POSTFIELDS?) И еще, какая разница между указанием user-agent в хедерах CURLOPT_HTTPHEADER и в CURLOPT_USERAGENT?
Code: function post_file ($url, $avars) { $parsed_url = parse_url($url); $host = $parsed_url['host']; $path = $parsed_url['path']; if($avars['type'] == 'content'){ $file .= "filename=".$avars['filename']."&content=".$avars['value']; } if($avars['type'] == 'link'){ $filetemp = file_get_contents($avars['value']); $filetopost = base64_encode($filetemp); $file .= "filename=".$avars['filename']."&content=".$filetopost; } if(isset($parsed_url['query'])) { $query = $parsed_url['query']; } $socket = @fsockopen($host, 80, $errno, $errstr, $this->timeout) or die ("Не могу открыть сокет :".$errstr."(".$errno.")"); if ( isset($query) ) { $out = "POST ".$path."?".$query." HTTP/1.1\r\n"; } else { $out = "POST ".$path." HTTP/1.1\r\n"; } $out .= "Host: ".$host."\r\n"; $out .= "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "Content-Length: ".strlen($file)."\r\n"; if(!isset($headers['Connection'])) { $out .= "Connection: Close\r\n"; } $out .= "\r\n"; $out .= $file; fwrite($socket, $out); while (!feof($socket)) { $in .= fgets($socket, 128); } fclose($socket); return $in; } post_file ($url ( string ), $avars ( array ), $headers ( array )) - запрос типа POST который в себе еще передает файл, $avars - данные запроса ( без них функция не выполниться ) ( должны идти массивом следущего типа : $avars['type'] => 'link' ( тип - ссылка на локальный файл для загрузки ( так как реализованно посредством функции file_get_contents можно попробовать и удаленные файлы)) || 'content' ( тип - содержимое ) $avars['value'] => 'value' ( если тип - ссылка тогда здесь должна быть ссылка на файл, если же content то содержимое файла закодированое посредством функции base64_encode ) $avars['filename'] => 'filename' ( имя файла в запросе ) ), возвращает ответ сервера на запрос.
Самая известная статья для новичков. http://www.phpclub.ru/detail/article/http_request проще filesize('имя файла');
Ему кажется пример с курлом был нужен.. Простой POST передаётся строкой в CURLOPT_POSTFIELDS. POST с boundary передаётся туда же, только массивом. Всё, что в boundary передаётся с добавлением собачки @ а вы тут намутили )
Мне нужно абсолютно точно воспроизвести запрос из браузера в своей программе с помощью курла. Вот что надо отправить в хедерах: Code: (Request-Line) POST /site.php?par=1 HTTP/1.1 Host: www.anysite.ru User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-LanguageL: ru,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7 Keep-Alive: 43200 Connection: keep-alive Referer: http://www.anysite.ru/fol/ Cookie: PHPSESSID=2lpliicfgkjfnmjhbkm6dbn4t1 Content-Type: multipart/form-data; boundary=---------------------------21718375316139 Content-Length: 48176 В самом POST-запросе надо отправить следующее: Code: Content-Type: multipart/form-data; boundary=---------------------------21718375316139 Content-Length: 48176 -----------------------------21718375316139 Content-Disposition: form-data; name="param1" 123 -----------------------------21718375316139 Content-Disposition: form-data; name="param2" 123 -----------------------------21718375316139 Content-Disposition: form-data; name="email" -----------------------------21718375316139 Content-Disposition: form-data; name="imagefile"; filename="pic.jpeg" Content-Type: image/jpeg ÿØÿà�JFIF��H�H��ÿþ�;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 80 ÿÛ�C� (дальше пошло содержимое картинки) Для этого я пишу следующий запрос: PHP: $postdata = array( 'param1' => '123', 'param2' => '123', 'email' => '', 'imagefile' => "@".'c:\www\pic.jpg'); $ch = curl_init(); $headers[] = 'Host:www.anysite.ru'; $headers[] = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10'; $headers[] = 'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; $headers[] = 'Accept-Language:ru,en-us;q=0.7,en;q=0.3'; $headers[] = 'Accept-Encoding:gzip,deflate'; $headers[] = 'Accept-Charset:windows-1251,utf-8;q=0.7,*;q=0.7'; $headers[] = 'Keep-Alive:43200'; $headers[] = 'Connection:keep-alive'; $headers[] = 'Referer:http://www.anysite.ru/fol/'; $headers[] = 'Cookie:PHPSESSID=2lpliicfgkjfnmjhbkm6dbn4t1'; $headers[] = 'Content-Type:multipart/form-data; boundary=---------------------------21718375316139'; $headers[] = 'Content-Length:48176'; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_PROXY, $proxy); curl_setopt($ch, CURLOPT_URL, "http://www.anysite.ru/site.php?par=1"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); $result= curl_exec ($ch); curl_close ($ch); На сервере, куда я отправляю POST, стоит проверка на корректность запросов и не пропускает вот этот вот мой curl-запрос, значит что-то в нём не хватет или наоборот лишнее. Что?
Ну ты и намутил тут... PHP: $headers[] = "Cookie:PHPSESSID='2lpliicfgkjfnmjhbkm6dbn4t1'; Закрывающую кавычку не поставил... И вообще - это быдлокод, почитай гугл, php.net.
Ужос.. PHP: $postdata = array( 'param1' => '123', 'param2' => '123', 'email' => '', 'imagefile' => '@' . realpath('pic.jpg') ); $ch = curl_init('http://www.anysite.ru/site.php?par=1'); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); $result= curl_exec ($ch); curl_close ($ch); ВСЁ! Больше тебе не нужны никакие заголовки!
mailbrush, это я всё упростил. на самом деле я беру id php-сессии из пришедших ранее set-cookie заголовков. Если ты думаешь, что проблема в id сессии, это 100% не так, тут всё правильно. Это как же, они не рассматриваются при проверке правильности запросов на сервере?
Есть еще одна проблема, ошибка 417 Expectation Failed. Это баг сервера lighttpd, связанный с автоматической отправкой курлом хедера Expect: 100-continue. http://www.astahost.com/Help-Removing-Specific-Header-cURL-t14787.html Кто-нибудь сталкивался с этим?
Почему же, можно и сокетами, только я с ними никогда не работал. Искал, но так и не понял алгоритма передачи параметров. Вот это возвращает Bad request (и понятно, нагородил тут) PHP: $body = Array( '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param1"', '\r\n', '123', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param2"', '\r\n', '123', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="email"', '\r\n', '\r\n', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="imagefile"; filename="pic.jpg"', 'Content-Type: image/jpeg', '\r\n', file_get_contents(realpath('pic.jpg')), '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param3"', '\r\n', '123'); $clenght=strlen(implode("\r\n",$body)); $a = array("POST http://www.anysite.ru/site.php?par=1 HTTP/1.1", "Host: www.anysite.ru", "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10", "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language:ru,en-us;q=0.7,en;q=0.3", "Accept-Encoding:gzip,deflate", "Accept-Charset:windows-1251,utf-8;q=0.7,*;q=0.7", "Keep-Alive:43200", "Connection:keep-alive", "Referer:http://www.anysite.ru/site/", "Cookie:PHPSESSID=$sessid", "Content-Type:multipart/form-data; boundary=---------------------------23683118578968", "Content-Length:$clenght", "\r\n"); $post = array(); $post = $a + $body; $f = fsockopen('64.46.248.204','8080') or die('Can\'t connect'); fwrite($f,implode("\r\n",$post)); $in = fread($f, 1048576); if ($in) {list(,$result) = explode("\r\n\r\n", $in, 2);} else $result = NULL; fclose($f);
PHP: $post = $a + $body; Это какбэ операция сложения, а не конкатенации. Замени хотя бы на: PHP: $post = $a . "\r\n" . $body; ну и это: PHP: fwrite($f,implode("\r\n",$post)); на PHP: fwrite($f, $post);
Ну да, и затереть разделитель между хедерами и содержимым. Вообще я правильно мыслю? Или всё вот это PHP: $body = Array( '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param1"', '\r\n', '123', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param2"', '\r\n', '123', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="email"', '\r\n', '\r\n', '-----------------------------23683118578968', 'Content-Disposition: form-data; name="imagefile"; filename="pic.jpg"', 'Content-Type: image/jpeg', '\r\n', file_get_contents(realpath('pic.jpg')), '-----------------------------23683118578968', 'Content-Disposition: form-data; name="param3"', '\r\n', '123'); можно заменить на это? PHP: $body = "param1=123¶m2=123&email=&imagefile=pic.jpg¶m3=123";