2010-06-21 3 views
34

Мне было интересно, если можно отправить файл - вместе с другими данными формы - когда файл является просто строкой?POST файловая строка с использованием cURL в PHP?

Я знаю, что вы можете опубликовать файл, который уже находится в файловой системе, путем префикса пути к файлу с помощью «@».

Однако я хотел бы обойти создание временного файла и отправить только файл в виде строки, но я не уверен, как построить запрос с использованием cURL в PHP.

Приветствия

$postFields = array(
     'otherFields' => 'Yes' 
     ,'filename'  => 'my_file.csv' 
     ,'data'   => 'comma seperated content' 
    ); 

    $options = array(
     CURLOPT_RETURNTRANSFER => true 
     ,CURLOPT_SSL_VERIFYPEER => false 
     ,CURLOPT_SSL_VERIFYHOST => 1 
     ,CURLOPT_POSTFIELDS  => $postFields 
     ,CURLOPT_HTTPHEADER  => array(
      'Content-type: multipart/form-data' 
     ) 
    ); 
+1

@Vin Определенно не дубликат. Это хороший вопрос. Я не знаю, как добавить заголовки деталей, как это требуется здесь, за исключением ручной обработки всех данных POST. – Artefacto

+0

@Artefacto: Правильно, я не понял вопрос правильно –

+1

по необработанным данным, вы имеете в виду file_get_contents ($ path_to_file); ? – Walter

ответ

25

Должно быть возможно: вот форма, отправил через браузер (нерелевантные поля опущены):

POST http://host.example.com/somewhere HTTP/1.1 
Content-Type: multipart/form-data; boundary=---------------------------7da16b2e4026c 
Content-Length: 105732 

-----------------------------7da16b2e4026c 
Content-Disposition: form-data; name="NewFile"; filename="test.jpg" 
Content-Type: image/jpeg 

(...raw JPEG data here...) 
-----------------------------7da16b2e4026c 
Content-Disposition: form-data; name="otherformfield" 

content of otherformfield is this text 
-----------------------------7da16b2e4026c-- 

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

// form field separator 
$delimiter = '-------------' . uniqid(); 
// file upload fields: name => array(type=>'mime/type',content=>'raw data') 
$fileFields = array(
    'file1' => array(
     'type' => 'text/plain', 
     'content' => '...your raw file content goes here...' 
    ), /* ... */ 
); 
// all other fields (not file upload): name => value 
$postFields = array(
    'otherformfield' => 'content of otherformfield is this text', 
    /* ... */ 
); 

$data = ''; 

// populate normal fields first (simpler) 
foreach ($postFields as $name => $content) { 
    $data .= "--" . $delimiter . "\r\n"; 
    $data .= 'Content-Disposition: form-data; name="' . $name . '"'; 
    // note: double endline 
    $data .= "\r\n\r\n"; 
} 
// populate file fields 
foreach ($fileFields as $name => $file) { 
    $data .= "--" . $delimiter . "\r\n"; 
    // "filename" attribute is not essential; server-side scripts may use it 
    $data .= 'Content-Disposition: form-data; name="' . $name . '";' . 
      ' filename="' . $name . '"' . "\r\n"; 
    // this is, again, informative only; good practice to include though 
    $data .= 'Content-Type: ' . $file['type'] . "\r\n"; 
    // this endline must be here to indicate end of headers 
    $data .= "\r\n"; 
    // the file itself (note: there's no encoding of any kind) 
    $data .= $file['content'] . "\r\n"; 
} 
// last delimiter 
$data .= "--" . $delimiter . "--\r\n"; 

$handle = curl_init($url); 
curl_setopt($handle, CURLOPT_POST, true); 
curl_setopt($handle, CURLOPT_HTTPHEADER , array(
    'Content-Type: multipart/form-data; boundary=' . $delimiter, 
    'Content-Length: ' . strlen($data))); 
curl_setopt($handle, CURLOPT_POSTFIELDS, $data); 
curl_exec($handle); 

Таким образом, мы делаем все, что он авы поднимать себя и доверять cURL, чтобы не калечить его.

+1

Первоначально неверно разобрал вопрос и получил право на это. Переписано во что-то, что может сработать. – Piskvor

+2

Я построил запрос, как предложил Писквор, и да, вы можете сами построить тело, и оно будет работать. Хотя вы должны быть на 100% точнее с EOL. В конце «Content-Length» и «Content-Disposition» требуется двойной возврат. Для файла после «Content-Type: text/plain» требуется двойной возврат. Разделитель также немного отличается от значений тела, чем это уклоняется в «Границе». Каждая граничная линия имеет два дополнительных дефиса, предшествующих началу. Последний разделитель имеет два дополнительных гипса в начале и в конце. – gawpertron

+0

Вы знаете, вы также можете опубликовать файл, добавив символ @ в полный путь к файлу. http://www.php.net/manual/en/function.curl-setopt.php проверьте раздел 'CURLOPT_POSTFIELDS'. –

15

У php есть доступ ко временному адресу "php: // memory", что фактически делает то, что вы пытаетесь сделать довольно легко.

$fh = fopen('php://memory','rw'); 
fwrite($fh, $content); 
rewind($fh); 

$options = array(
    CURLOPT_RETURNTRANSFER => true 
    ,CURLOPT_SSL_VERIFYPEER => false 
    ,CURLOPT_SSL_VERIFYHOST => 1 
    ,CURLOPT_HTTPHEADER  => array(
     'Content-type: multipart/form-data' 
    ) 
    ,CURLOPT_INFILE   => $fh 
    ,CURLOPT_INFILESIZE  => strlen($content) 
); 
+0

Будет ли это использоваться для остальных почтовых полей, которые отправляются вместе с файлом? –

+4

Он определенно создает обработчик файлов, и я дал ему попробовать, но я думаю, что CURLOPT_INFILE и CURLOPT_INFILESIZE используются для PUT-файлов, в массиве $ _FILES файлов не обнаружено. – gawpertron

+0

Код в вопросе может загружать сразу несколько файлов. Может 'PUT' с' INFILE' загружать несколько файлов тоже? – DanFromGermany

Смежные вопросы