2009-05-20 71 views
5

Mi aplicación web PHP tiene una API que puede recibir archivos razonablemente grandes (hasta 32 MB) codificados en base64. El objetivo es escribir estos archivos en algún lugar de mi sistema de archivos. Descifrado por supuesto. ¿Cuál sería la manera menos intensiva en recursos de hacer esto?Cómo base64 decodificar archivos grandes en PHP

Editar: Recibir los archivos a través de una API significa que tengo una cadena de 32MB en mi aplicación PHP, no un archivo fuente de 32 MB en algún lugar del disco. Necesito decodificar esa cadena en el sistema de archivos.

Usando propia base64_decode() de PHP no es así enfriamiento, ya que utiliza una gran cantidad de la memoria, así que seguir funcionando en límite de memoria de PHP (lo sé, podría aumentar este límite, pero no me siento bien acerca de lo que permite PHP para usar 256MB más o menos por proceso).

¿Alguna otra opción? ¿Podría hacerlo manualmente? ¿O escribir el archivo en el disco codificado y llamar a algún comando externo? ¿Cualquier pensamiento?

Respuesta

20

A pesar de que esto ha aceptado una respuesta, tengo una sugerencia diferente.

Si está extrayendo los datos de una API, no debe almacenar toda la carga en una variable. Usando Curl u otras búsquedas de HTTP puedes almacenar automáticamente tus datos en un archivo.

Suponiendo que esté recogiendo los datos a través de un simple URL GET:

$url = 'http://www.example.com/myfile.base64'; 
$target = 'localfile.data'; 

$rhandle = fopen($url,'r'); 
stream_filter_append($rhandle, 'convert.base64-decode'); 

$whandle = fopen($target,'w'); 

stream_copy_to_stream($rhandle,$whandle); 
fclose($rhandle); 
fclose($whandle); 

Beneficios:

  • debe ser más rápido (menos de copia de variables enormes)
  • muy poca sobrecarga de memoria

Si debe tomar los datos de una variable temporal, puedo sugerir t este enfoque:

$data = 'your base64 data'; 
$target = 'localfile.data'; 

$whandle = fopen($target,'w'); 
stream_filter_append($whandle, 'convert.base64-decode',STREAM_FILTER_WRITE); 

fwrite($whandle,$data); 

fclose($whandle); 
+0

Una buena idea, pero no es lo que estoy buscando. En mi caso, las aplicaciones cliente están enviando archivos grandes sobre XML-RPC (HTTP POST) a mi servidor (junto con un par de otros parámetros). Los clientes pueden estar detrás de NAT y firewalls, por lo que no es posible obtener los datos del cliente utilizando GET. –

+0

Si la estructura de la respuesta xml rpc es algo estática, puede recorrer manualmente el cuerpo de la respuesta, por lo que aún puede evitar por completo el uso de la memoria. Si debe colocar los datos en una variable temporal, puede cambiar la configuración un poco. (Estoy actualizando el ejemplo justo después del ejemplo;)) – Evert

+0

Gracias por la actualización. Lo encuentro superior a la respuesta que originalmente acepté. –

11

Decodifica los datos en trozos más pequeños. Cuatro caracteres de los datos de Base64 equivalen a tres bytes de datos de "Base256".

por lo que podría grupo cada 1024 caracteres y decodificarlos a 768 octetos de datos binarios:

$chunkSize = 1024; 
$src = fopen('base64.data', 'rb'); 
$dst = fopen('binary.data', 'wb'); 
while (!feof($src)) { 
    fwrite($dst, base64_decode(fread($src, $chunkSize))); 
} 
fclose($dst); 
fclose($src); 
+0

Gracias. Una cosa antes de que marque esto como aceptado: en mi pregunta original, menciono que el archivo fuente proviene de una API. Entonces, es una variable (una cadena de 32 MB) en PHP y no un archivo del que se lee. ¿Hay algo que pueda usar en lugar de su fread() que me devuelva fragmentos de una cadena de manera eficiente? Es decir. sin hacer demasiadas copias duplicadas que se tragan la memoria? –

+0

Puede leer desde la entrada a través de 'php: // input'. Ver http://docs.php.net/manual/en/wrappers.php.php – Gumbo

Cuestiones relacionadas