Dans PHP, la fonction fpassthru () est utilisée pour sortir directement le contenu de fichier pointé par le pointeur de fichier, et est généralement utilisé avec le code lié aux opérations de fichiers. Lorsque nous utilisons cette fonction, nous pouvons rencontrer des problèmes de débordement de mémoire, en particulier lorsque le fichier est grand ou que le système n'est pas configuré à l'époque, le programme peut s'écraser car il ne peut pas gérer trop de mémoire. Cet article présentera comment dépanner et résoudre efficacement les problèmes de débordement de la mémoire.
La fonction de la fonction fpassthru () consiste à lire la position actuelle pointant vers le pointeur de fichier et à sortir le contenu du fichier vers le navigateur ou le terminal. Généralement, fpassthru () convient aux scénarios où le contenu de fichier grand est sorti via PHP, tels que les flux vidéo, les images, les journaux, etc. Son utilisation de base est la suivante:
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$file</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fopen</span></span><span>(</span><span><span class="hljs-string">'example.txt'</span></span><span>, </span><span><span class="hljs-string">'rb'</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$file</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">fpassthru</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>);
}
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
Le code ci-dessus ouvre un fichier et publie le contenu du fichier via fpassthru () . Si le fichier est grand ou si le système est mal configuré, il peut provoquer un débordement de mémoire en raison du contenu de sortie occupe trop de mémoire.
Lorsque vous utilisez la fonction fpassthru () , le débordement de la mémoire est généralement dû aux raisons suivantes:
Si le fichier est grand, PHP doit lire et sortir le contenu de l'ensemble du fichier. Pour les fichiers volumineux (tels que les fichiers supérieurs à 1 Go), la sortie directe prendra beaucoup de mémoire. Si la limite de mémoire ( Memory_limit ) configurée par PHP est faible, la lecture et la sortie du fichier dépasseront la plage de mémoire autorisée, provoquant un débordement de mémoire.
PHP a un tampon de sortie par défaut. Si le contenu du fichier est trop grand, le système peut essayer de charger l'intégralité du contenu dans le tampon, puis de le sortir. Si le tampon ne peut pas gérer une telle quantité de données au cours de ce processus, il peut entraîner un débordement de mémoire.
PHP n'est pas conçu spécifiquement pour le traitement des fichiers volumineux, en particulier lorsque le fichier est directement sorti via fpassthru () , PHP essaiera de lire le contenu du fichier et de le remettre dans le tampon de sortie. Si les ressources système ou la configuration ne peuvent pas prendre en charge des opérations de chargement élevées, il est facile de causer des problèmes de mémoire.
Vérifiez d'abord si la limite de mémoire de PHP est suffisante pour gérer la sortie des fichiers volumineux. Vous pouvez augmenter la limite de mémoire en modifiant le fichier php.ini :
<span><span><span class="hljs-attr">memory_limit</span></span><span> = </span><span><span class="hljs-number">512</span></span><span>M
</span></span>
Si php.ini ne peut pas être modifié directement, vous pouvez le définir dynamiquement dans le script:
<span><span><span class="hljs-title function_ invoke__">ini_set</span></span><span>(</span><span><span class="hljs-string">'memory_limit'</span></span><span>, </span><span><span class="hljs-string">'512M'</span></span><span>);
</span></span>
En augmentant les limites de mémoire, il peut être possible d'éviter les problèmes de débordement causés par une mémoire insuffisante.
Pour éviter de charger le fichier entier en mémoire à la fois, vous pouvez utiliser une alternative à la fonction fpassthru () pour lire le fichier en morceaux et sortir il bloque par blocs, réduisant l'utilisation de la mémoire. Vous pouvez utiliser Fread () pour lire le contenu du fichier étape par étape, puis utiliser la sortie Echo . Les exemples sont les suivants:
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$file</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fopen</span></span><span>(</span><span><span class="hljs-string">'example.txt'</span></span><span>, </span><span><span class="hljs-string">'rb'</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$file</span></span><span>) {
</span><span><span class="hljs-keyword">while</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">feof</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>)) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>, </span><span><span class="hljs-number">8192</span></span><span>); </span><span><span class="hljs-comment">// Chaque lecture 8KB</span></span><span>
}
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>);
}
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
Cette méthode évite de charger le contenu de l'ensemble du fichier à la fois, il peut donc réduire considérablement l'utilisation de la mémoire lors du traitement des fichiers volumineux.
Le tampon de sortie de PHP peut également être l'une des causes de débordement de mémoire. Lors de la sortie d'une grande quantité de données, le tampon peut être contrôlé via ob_clean () et flush () . Par exemple:
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-title function_ invoke__">ob_clean</span></span><span>();
</span><span><span class="hljs-title function_ invoke__">flush</span></span><span>();
</span><span><span class="hljs-variable">$file</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fopen</span></span><span>(</span><span><span class="hljs-string">'largefile.txt'</span></span><span>, </span><span><span class="hljs-string">'rb'</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$file</span></span><span>) {
</span><span><span class="hljs-keyword">while</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">feof</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>)) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>, </span><span><span class="hljs-number">8192</span></span><span>); </span><span><span class="hljs-comment">// Chaque lecture 8KB</span></span><span>
</span><span><span class="hljs-title function_ invoke__">flush</span></span><span>(); </span><span><span class="hljs-comment">// Effacer le tampon de sortie</span></span><span>
}
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$file</span></span><span>);
}
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
L'utilisation de Flush () garantit que les données sont envoyées immédiatement au navigateur et évitent que le contenu excessif soit accumulé dans le tampon.
Pour certains fichiers extrêmement volumineux, vous pouvez vérifier la taille du fichier et déterminer si le traitement de la chasse est requis avant le chargement. Par exemple, vous pouvez utiliser la fonction FileSize () pour obtenir la taille du fichier et décider de le traiter en morceaux.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$file_path</span></span><span> = </span><span><span class="hljs-string">'largefile.txt'</span></span><span>;
</span><span><span class="hljs-variable">$file_size</span></span><span> = </span><span><span class="hljs-title function_ invoke__">filesize</span></span><span>(</span><span><span class="hljs-variable">$file_path</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$file_size</span></span><span> > </span><span><span class="hljs-number">1000000000</span></span><span>) { </span><span><span class="hljs-comment">// Si le fichier est plus grand que 1GB</span></span><span>
</span><span><span class="hljs-comment">// Effectuer le traitement de la chasse</span></span><span>
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-comment">// Utiliser directement fpassthru()</span></span><span>
}
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
Pour les fichiers très volumineux, des techniques de streaming sont recommandées, telles que le transfert de fichiers directement via des en-têtes HTTP, plutôt que de lire et de sortir le fichier entier sur PHP. L'en-tête HTTP approprié peut être défini en utilisant le code suivant:
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-title function_ invoke__">header</span></span><span>(</span><span><span class="hljs-string">'Content-Type: application/octet-stream'</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">header</span></span><span>(</span><span><span class="hljs-string">'Content-Disposition: attachment; filename="largefile.txt"'</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">header</span></span><span>(</span><span><span class="hljs-string">'Content-Length: '</span></span><span> . </span><span><span class="hljs-title function_ invoke__">filesize</span></span><span>(</span><span><span class="hljs-string">'largefile.txt'</span></span><span>));
</span><span><span class="hljs-title function_ invoke__">readfile</span></span><span>(</span><span><span class="hljs-string">'largefile.txt'</span></span><span>);
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
Cette méthode ne nécessite pas de charger le contenu du fichier dans la mémoire PHP, mais en difficulté directement à partir du disque dur, réduisant considérablement la consommation de mémoire.
Pour le traitement grand fichier, en plus de PHP, vous pouvez également envisager d'utiliser certains outils ou bibliothèques spécialisés dans le traitement des fichiers volumineux, tels que FFMPEG (pour le traitement des fichiers vidéo) ou ImageMagick (pour le traitement des fichiers d'image). Ces outils peuvent être diffusés en arrière-plan pour éviter un débordement de mémoire.
Bien que la fonction fpassthru () soit pratique, elle peut facilement provoquer un débordement de mémoire lors du traitement des fichiers volumineux. Pour éviter ce problème, le code peut être optimisé en ajustant les limites de mémoire, en lisant les fichiers blocs par bloc, en contrôlant les tampons de sortie, etc. Si le fichier est très grand, vous pouvez également envisager de streaming des fichiers ou utiliser des outils spéciaux pour le traitement. Grâce à ces méthodes, les problèmes de débordement de mémoire peuvent être effectivement évités et la stabilité et les performances de l'application peuvent être améliorées.