2010-06-21 12 views
34

Me preguntaba si es posible publicar un archivo, junto con otros datos del formulario, cuando el archivo es solo una cadena.¿POST una cadena de archivo usando cURL en PHP?

Sé que puede publicar un archivo que ya está en el sistema de archivos colocando el prefijo "file" en la ruta del archivo.

Sin embargo, me gustaría omitir la creación de un archivo temporal y enviar solo el archivo como una cadena, pero no estoy seguro de cómo construir la solicitud utilizando cURL en PHP.

Saludos

$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 Definitivamente no es un duplicado. Esta es una buena pregunta. No conozco ninguna forma de agregar encabezados de parte, como se requeriría aquí, salvo crear manualmente todos los datos POST. – Artefacto

+0

@Artefacto: Correcto, no entendí la pregunta correctamente –

+1

por datos sin procesar ¿se refiere a file_get_contents ($ path_to_file); ? – Walter

Respuesta

25

debería ser posible: aquí hay un formulario, publicado a través de un navegador (campos irrelevantes omitidas):

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-- 

Por lo tanto, si construimos el cuerpo de POST nosotros mismos y establecer un extra Encabezado o dos, deberíamos ser capaces de simular esto:

// 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); 

De esta manera, estamos haciendo todo lo que Nos levantamos y confiamos en que el cURL no lo arruine.

+1

Originalmente malinterpreté la pregunta y recibí una respuesta negativa por ello. Reescribí en algo que podría funcionar. – Piskvor

+2

He creado la solicitud como sugirió Piskvor y sí, puedes construir el cuerpo tú mismo y funcionará. Aunque debe ser 100% preciso con los EOL. Al final de "Content-Length" y "Content-Disposition" se requiere una devolución doble. Para el archivo después de "Content-Type: text/plain" también se requiere un retorno doble. El delimitador también es ligeramente diferente para los valores del cuerpo que el que se indica en el "Límite". Cada línea límite tiene dos guiones adicionales antes del comienzo. El último delimitador tiene dos hypens adicionales al principio y al final. – gawpertron

+0

Usted sabe, también puede publicar un archivo anteponiendo el símbolo @ a la ruta completa del archivo. http://www.php.net/manual/en/function.curl-setopt.php revisa la sección 'CURLOPT_POSTFIELDS'. –

15

php tiene acceso a una ubicación temporal "php: // memory", lo que realmente hace que lo que estás intentando hacer sea bastante fácil.

$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

¿Permitirá esto el resto de los campos posteriores que se envían con el archivo? –

+4

Definitivamente crea un manejador de archivos y lo probé, pero creo que CURLOPT_INFILE y CURLOPT_INFILESIZE se usan para PUT archivos. No se encontraron archivos en la matriz $ _FILES. – gawpertron

+0

El código en la pregunta puede cargar varios archivos a la vez. ¿Puede 'PUT' con' INFILE' subir también múltiples archivos? – DanFromGermany

Cuestiones relacionadas