2010-10-23 6 views
28

Mi rendo conto di poterlo fare molto facilmente con CURL, ma mi chiedevo se fosse possibile utilizzare file_get_contents() con il contesto del flusso http per caricare un file su un server Web remoto e, in tal caso, come ?Carica un file utilizzando file_get_contents

+1

Non intendi file_put_contents()? – mellowsoon

+0

No. Prova a fare file_put_contents con un URL e otterrai "HTTP wrapper non supporta connessioni scrivibili" – Shabbyrobe

+1

Ma con * file_get_contents() * puoi scaricare file, non caricare !? – KingCrunch

risposta

69

Prima di tutto, la prima regola di multipart Content-Type è di definire un contorno che verrà utilizzato come delimitatore tra ogni parte (perché, come dice il nome, si può avere più parti). Il limite può essere qualsiasi stringa che non è contenuta nel corpo del contenuto. Io di solito uso un timestamp:

define('MULTIPART_BOUNDARY', '--------------------------'.microtime(true)); 

Una volta che il confine è definito, è necessario inviare con l'intestazione Content-Type per dire al server web che cosa delimitatore aspettarsi:

$header = 'Content-Type: multipart/form-data; boundary='.MULTIPART_BOUNDARY; 

Una volta fatto ciò, si deve creare un corpo di contenuto adeguato che corrisponda alle specifiche HTTP e all'intestazione che hai inviato. Come sapete, quando si invia un file da un modulo, di solito si ha un nome di campo modulo. Ci definiamo:

// equivalent to <input type="file" name="uploaded_file"/> 
define('FORM_FIELD', 'uploaded_file'); 

Poi costruire il corpo contenuto:

$filename = "/path/to/uploaded/file.zip"; 
$file_contents = file_get_contents($filename);  

$content = "--".MULTIPART_BOUNDARY."\r\n". 
      "Content-Disposition: form-data; name=\"".FORM_FIELD."\"; filename=\"".basename($filename)."\"\r\n". 
      "Content-Type: application/zip\r\n\r\n". 
      $file_contents."\r\n"; 

// add some POST fields to the request too: $_POST['foo'] = 'bar' 
$content .= "--".MULTIPART_BOUNDARY."\r\n". 
      "Content-Disposition: form-data; name=\"foo\"\r\n\r\n". 
      "bar\r\n"; 

// signal end of request (note the trailing "--") 
$content .= "--".MULTIPART_BOUNDARY."--\r\n"; 

Come potete vedere, stiamo inviando il Content-Disposition intestazione con il form-data disposizione, insieme con il parametro name (il nome del campo modulo) e il parametro filename (il nome file originale). È inoltre importante inviare l'intestazione Content-Type con il tipo MIME corretto, se si desidera compilare correttamente il numero $_FILES[]['type'].

Se avevi più file da caricare, basta ripetere il processo con il contenuto $ bit, con ovviamente un diverso FORM_FIELD per ogni file.

Ora, costruire il contesto:

$context = stream_context_create(array(
    'http' => array(
      'method' => 'POST', 
      'header' => $header, 
      'content' => $content, 
    ) 
)); 

ed eseguire:

file_get_contents('http://url/to/upload/handler', false, $context); 

NOTA: Non v'è alcuna necessità di codificare il file binario prima di inviarlo. HTTP può gestire il binario bene.

+0

Wow, bella risposta. Ci proveremo stasera. – Shabbyrobe

+1

Questo ha funzionato magnificamente. C'è qualche possibilità che tu possa aggiungere alla tua risposta come aggiungere campi addizionali con il caricamento? Inoltre, è possibile fare multipli in questo modo semplicemente virando su un altro confine? – Shabbyrobe

+0

Sicuro. Per i campi POST, vedere la mia risposta aggiornata. Per quanto riguarda la tua seconda domanda, non sono sicuro di cosa intendi. – netcoder

0

È possibile inviare una richiesta POST con Content-Type: multipart/form-data e codificare manualmente il file come multipart/form-data.

file_get_contents(URL, false, stream_context_create(array(
    'http' => array(
     'method' => 'POST', 
     'headers' => 'Content-Type: multipart/form-data' 
     'content' => MULTIPART_ENCODED_FILE, 
    ), 
))); 
+0

come faccio a codificare il file? – Shabbyrobe

+0

@Shabbyrobe: Sì, questa è esattamente la domanda ... Non ho idea di come funzioni la codifica in più parti, quindi non posso aiutarti. – NikiC

+1

Prova 'base64_encode()', http://php.net/manual/en/function.base64-encode.php. –