Maison  >  Article  >  développement back-end  >  Comment puis-je obtenir la taille du fichier en temps réel d'un téléchargement lié au serveur ?

Comment puis-je obtenir la taille du fichier en temps réel d'un téléchargement lié au serveur ?

Susan Sarandon
Susan Sarandonoriginal
2024-10-20 22:02:02208parcourir

How Can I Get the Real-Time File Size of a Server-Bound Upload?

Question :

Obtenir la taille en temps réel d'un fichier téléchargé pendant son écriture sur le serveur sans bloquer à la fois le serveur et client.

Contexte :

Progression du téléchargement du fichier dans le navigateur d'un client lors de l'écriture sur le serveur à l'aide de la requête POST de fetch() avec un corps de fichier ou de blob.

Exigence :

Afficher la taille du fichier sous forme de texte/flux d'événements pendant son écriture sur le système de fichiers du serveur. Arrêtez-vous lorsque tous les octets fournis en tant que paramètre de chaîne de requête lors du téléchargement du fichier ont été écrits. La taille du fichier est actuellement récupérée à partir d'un script distinct, qui est appelé après que le fichier a été écrit sur le serveur.

Implémentation :

Initialement tenté d'utiliser PHP mais rencontré erreurs dues à un HTTP_LAST_EVENT_ID non défini et à une taille de fichier incorrecte signalée. J'ai également expérimenté différentes approches et langages comme bash, c, nodejs et python.

Solution :

  1. Effacer le cache des statistiques de fichiers pour obtenir un fichier en temps réel size :
<code class="php">clearstatcache(true, $upload);
$data = filesize($upload);</code>
  1. stream.php modifié avec gestion des erreurs et utilisation de usleep pour de meilleures performances :
<code class="php">// Check if the header's been sent to avoid `PHP Notice:  Undefined index: HTTP_LAST_EVENT_ID in stream.php on line `
// php 7+
//$lastId = $_SERVER["HTTP_LAST_EVENT_ID"] ?? 0;
// php < 7
$lastId = isset($_SERVER["HTTP_LAST_EVENT_ID"]) ? intval($_SERVER["HTTP_LAST_EVENT_ID"]) : 0;

$upload = $_GET["filename"];
$data = 0;
// if file already exists, its initial size can be bigger than the new one, so we need to ignore it
$wasLess = $lastId != 0;
while ($data < $_GET["filesize"] || !$wasLess) {
    // system calls are expensive and are being cached with assumption that in most cases file stats do not change often
    // so we clear cache to get most up to date data
    clearstatcache(true, $upload);
    $data = filesize($upload);
    $wasLess |= $data < $_GET["filesize"];
    // don't send stale filesize
    if ($wasLess) {
        sendMessage($lastId, $data);
        $lastId++;
    }
    // not necessary here, though without thousands of `message` events will be dispatched
    //sleep(1);
    // millions on poor connection and large files. 1 second might be too much, but 50 messages a second must be okay
    usleep(20000);
}</code>
  1. Inclure fileId et fileSize dans le cadre de la requête POST et ajoutez un stockage en mémoire à l'aide de Redis ou Memcache pour stocker les métadonnées des fichiers.
  2. Utilisez EventSource dans le JavaScript côté client :
<code class="javascript">const [fileId, request, source] = [
    Math.random().toString(36).substr(2),
    new Request(`${url}?fileId=${fileId}&amp;size=${filesize}`, {
        method: "POST",
        headers: headers,
        body: file
    }),
    new EventSource(`${stream}?fileId=${fileId}`)
];</code>
  1. Personnalisez les fonctions setUnique et updateProgress en fonction du mécanisme de stockage choisi :
<code class="php">function setUnique(string $id, int $size) {
    // implement with your storage of choice
}

function updateProgress(string $id, int $processed) {
    // implement with your storage of choice
}</code>
  1. Obtenez la progression du stockage :
<code class="php">list($progress, $size) = getProgress($_GET["fileId"]);</code>

Remarques importantes :

  • La solution fournie donne la priorité à la fonctionnalité plutôt qu'à la sécurité et n'est pas recommandée pour une utilisation en production sans mettre en œuvre des mesures de sécurité supplémentaires.
  • Le nombre de connexions ouvertes peut devoir être ajusté en fonction de la configuration du serveur et de l'utilisation des ressources.
  • Au lieu d'EventSource, l'utilisation de l'interrogation peut être envisagée pour réduire le nombre de connexions ouvertes, mais cela peut avoir un impact sur la réactivité.
  • Le temps de sommeil optimal en veille () peut varier en fonction de la fréquence de mise à jour souhaitée et des compromis en termes de performances.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn