2009-05-20 7 views
5

Mon application web PHP a une API qui peut recevoir des fichiers assez volumineux (jusqu'à 32 Mo) codés en base64. L'objectif est d'écrire ces fichiers quelque part sur mon système de fichiers. Décodé bien sûr. Quelle serait la façon la moins gourmande en ressources de faire cela? La réception des fichiers via une API signifie que j'ai une chaîne de 32 Mo dans mon application PHP, pas un fichier source de 32 Mo quelque part sur le disque. J'ai besoin de décoder cette chaîne sur le système de fichiers.Comment faire pour décoder de gros fichiers en base64 dans PHP

L'utilisation propre base64_decode() de PHP ne coupe pas parce qu'il utilise un si je garde beaucoup de mémoire en cours d'exécution dans la limite de mémoire de PHP (je sais, je pouvais lever cette limite, mais je ne me sens pas bien permettre PHP pour utiliser 256 Mo ou plus par processus).

D'autres options? Est-ce que je pourrais le faire manuellement? Ou écrire le fichier sur le disque codé et appeler une commande externe? Toute pensée?

Répondre

20

Même si cela a une réponse acceptée, j'ai une autre suggestion.

Si vous extrayez les données d'une API, vous ne devez pas stocker la totalité des données utiles dans une variable. En utilisant curl ou d'autres fetchers HTTP, vous pouvez stocker automatiquement vos données dans un fichier.

En supposant que vous récupérez les données par une 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); 

Avantages:

  • devrait être plus rapide (moins la copie des variables énormes)
  • Très peu de mémoire au-dessus

Si vous devez saisir les données d'une variable temporaire, je peux suggérer t cette approche:

$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

Une bonne idée, mais pas ce que je cherche. Dans mon cas, les applications clientes poussent de gros fichiers sur XML-RPC (HTTP POST) vers mon serveur (avec quelques autres paramètres). Les clients peuvent se trouver derrière le NAT et les pare-feu, il n'est donc pas possible d'extraire les données du client à l'aide de GET. –

+0

Si la structure de la réponse rpc xml est quelque peu statique, vous pouvez parcourir manuellement le corps de la réponse, ce qui vous permet d'éviter complètement toute utilisation de la mémoire. Si vous devez placer les données dans une variable temporaire, vous pouvez modifier un peu la configuration. (Je suis mise à jour l'exemple juste après l'exemple;)) – Evert

+0

Merci pour la mise à jour. Je le trouve supérieur à la réponse que j'ai acceptée à l'origine. –

11

Décode les données en plus petits morceaux. Quatre caractères de données Base64 égalent trois octets de données "Base256".

vous pouvez donc chaque groupe de 1024 caractères et les décoder à 768 octets de données binaires:

$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

Merci. Une chose avant de marquer cela comme accepté: Dans ma question initiale, je mentionne que le fichier source provient d'une API. Donc, c'est une variable (une chaîne de 32 Mo) en PHP et non un fichier que vous lisez. Y at-il quelque chose que je peux utiliser à la place de votre fread() qui me renvoie des morceaux de ficelle efficacement? C'est à dire. sans faire trop de copies dupliquées qui engloutissent la mémoire? –

+0

Vous pouvez lire depuis l'entrée via 'php: // input'. Voir http://docs.php.net/manual/en/wrappers.php.php – Gumbo

Questions connexes