2011-05-30 52 views
5

¿Cómo puedo usar Curl para descargar un archivo en PHP si los encabezados están establecidos en verdadero? ¿Puedo obtener también el nombre de archivo y la extensión del archivo? código¿Cómo descargar un archivo usando curl en php?

Ejemplo de PHP:

curl_setopt ($ch, CURLOPT_HEADER, 1); 
$fp = fopen($strFilePath, 'w'); 
curl_setopt($ch, CURLOPT_FILE, $fp); 
+0

¿La respuesta es correcta para usted? Si es así, por favor, el más útil, ya que es correcto para la ayuda de los demás. –

Respuesta

4

Descargar archivo o página web con PHP Curl y guardarla en un archivo

<?php 
/** 
* Initialize the cURL session 
*/ 
$ch = curl_init(); 
/** 
* Set the URL of the page or file to download. 
*/ 
curl_setopt($ch, CURLOPT_URL, 
'http://news.google.com/news?hl=en&topic=t&output=rss'); 
/** 
* Create a new file 
*/ 
$fp = fopen('rss.xml', 'w'); 
/** 
* Ask cURL to write the contents to a file 
*/ 
curl_setopt($ch, CURLOPT_FILE, $fp); 
/** 
* Execute the cURL session 
*/ 
curl_exec ($ch); 
/** 
* Close cURL session and file 
*/ 
curl_close ($ch); 
fclose($fp); 
?> 
0

Para llegar tanto a la cabecera y los datos, por separado, normalmente se utiliza tanto una devolución de llamada del encabezado y una devolución de llamada del cuerpo. Como en este ejemplo: http://curl.haxx.se/libcurl/php/examples/callbacks.html

Para obtener el nombre del archivo de los encabezados, debe buscar un encabezado Content-Disposition: extraer el nombre del archivo de allí (si está presente) o simplemente usar la parte del nombre del archivo del URL o similar. Tu elección.

2

A continuación se muestra un ejemplo completo que utiliza una clase. El análisis de encabezado es más elaborado de lo que puede ser, porque estaba sentando la base para el almacenamiento completo de encabezado jerárquico.

Acabo de notar que init() debería restablecer muchas más variables si quiere reutilizar la instancia para más URL, pero al menos debería proporcionarle una base de cómo descargar un archivo a un nombre de archivo enviado por el servidor.

<?php 
/* 
* vim: ts=4 sw=4 fdm=marker noet tw=78 
*/ 
class curlDownloader 
{ 
    private $remoteFileName = NULL; 
    private $ch = NULL; 
    private $headers = array(); 
    private $response = NULL; 
    private $fp = NULL; 
    private $debug = FALSE; 
    private $fileSize = 0; 

    const DEFAULT_FNAME = 'remote.out'; 

    public function __construct($url) 
    { 
     $this->init($url); 
    } 

    public function toggleDebug() 
    { 
     $this->debug = !$this->debug; 
    } 

    public function init($url) 
    { 
     if(!$url) 
      throw new InvalidArgumentException("Need a URL"); 

     $this->ch = curl_init(); 
     curl_setopt($this->ch, CURLOPT_URL, $url); 
     curl_setopt($this->ch, CURLOPT_HEADERFUNCTION, 
      array($this, 'headerCallback')); 
     curl_setopt($this->ch, CURLOPT_WRITEFUNCTION, 
      array($this, 'bodyCallback')); 
    } 

    public function headerCallback($ch, $string) 
    { 
     $len = strlen($string); 
     if(!strstr($string, ':')) 
     { 
      $this->response = trim($string); 
      return $len; 
     } 
     list($name, $value) = explode(':', $string, 2); 
     if(strcasecmp($name, 'Content-Disposition') == 0) 
     { 
      $parts = explode(';', $value); 
      if(count($parts) > 1) 
      { 
       foreach($parts AS $crumb) 
       { 
        if(strstr($crumb, '=')) 
        { 
         list($pname, $pval) = explode('=', $crumb); 
         $pname = trim($pname); 
         if(strcasecmp($pname, 'filename') == 0) 
         { 
          // Using basename to prevent path injection 
          // in malicious headers. 
          $this->remoteFileName = basename(
           $this->unquote(trim($pval))); 
          $this->fp = fopen($this->remoteFileName, 'wb'); 
         } 
        } 
       } 
      } 
     } 

     $this->headers[$name] = trim($value); 
     return $len; 
    } 
    public function bodyCallback($ch, $string) 
    { 
     if(!$this->fp) 
     { 
      trigger_error("No remote filename received, trying default", 
       E_USER_WARNING); 
      $this->remoteFileName = self::DEFAULT_FNAME; 
      $this->fp = fopen($this->remoteFileName, 'wb'); 
      if(!$this->fp) 
       throw new RuntimeException("Can't open default filename"); 
     } 
     $len = fwrite($this->fp, $string); 
     $this->fileSize += $len; 
     return $len; 
    } 

    public function download() 
    { 
     $retval = curl_exec($this->ch); 
     if($this->debug) 
      var_dump($this->headers); 
     fclose($this->fp); 
     curl_close($this->ch); 
     return $this->fileSize; 
    } 

    public function getFileName() { return $this->remoteFileName; } 

    private function unquote($string) 
    { 
     return str_replace(array("'", '"'), '', $string); 
    } 
} 

$dl = new curlDownloader(
    'https://dl.example.org/torrent/cool-movie/4358-hash/download.torrent' 
); 
$size = $dl->download(); 
printf("Downloaded %u bytes to %s\n", $size, $dl->getFileName()); 
?> 
1

Creo que ya has encontrado tu respuesta. Sin embargo, me gustaría compartir mi script que funciona bien enviando una solicitud json a un servidor que devuelve el archivo en formato binario, luego se descarga sobre la marcha. El ahorro no es necesario. ¡Espero eso ayude!

NOTA: Puede evitar convertir los datos de la publicación en json.

<?php 

// Username or E-mail 
$login = 'username'; 
// Password 
$password = 'password'; 
// API Request 
$url = 'https://example.com/api'; 
// POST data 
$data = array('someTask', 24); 
// Convert POST data to json 
$data_string = json_encode($data); 
// initialize cURL 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL,$url); 
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 
curl_setopt($ch, CURLOPT_USERPWD, "$login:$password"); 
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); 
curl_setopt($ch, CURLOPT_HEADER, 1); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

// Execute cURL and store the response in a variable 
$file = curl_exec($ch); 

// Get the Header Size 
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 
// Get the Header from response 
$header = substr($file, 0, $header_size); 
// Get the Body from response 
$body = substr($file, $header_size); 
// Explode Header rows into an array 
$header_items = explode("\n", $header); 
// Close cURL handler 
curl_close($ch); 

// define new variable for the File name 
$file_name = null; 

// find the filname in the headers. 
if(!preg_match('/filename="(.*?)"/', $header, $matches)){ 
    // If filename not found do something... 
    echo "Unable to find filename.<br>Please check the Response Headers or Header parsing!"; 
    exit(); 
} else { 
    // If filename was found assign the name to the variable above 
    $file_name = $matches[1]; 
} 
// Check header response, if HTTP response is not 200, then display the error. 
if(!preg_match('/200/', $header_items[0])){ 
    echo '<pre>'.print_r($header_items[0], true).'</pre>'; 
    exit(); 
} else { 
    // Check header response, if HTTP response is 200, then proceed further. 

    // Set the header for PHP to tell it, we would like to download a file 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/octet-stream'); 
    header('Content-Transfer-Encoding: binary'); 
    header('Expires: 0'); 
    header('Cache-Control: must-revalidate'); 
    header('Pragma: public'); 
    header('Content-Disposition: attachment; filename='.$file_name); 

    // Echo out the file, which then should trigger the download 
    echo $file; 
    exit; 
} 

?> 
Cuestiones relacionadas