2012-04-26 14 views
5

Soy consciente de que el título de esto es un poco extraño, pero voy a llegar allí.Evitar archivos parcialmente cargados (a través de FTP) al obtener el archivo más reciente con ajax y PHP

Tengo una cámara conectada a una computadora portátil. Con el Disparo remoto, cuando el fotógrafo toma una foto, se guarda en una carpeta en el disco duro de la computadora portátil. Hay una acción de Automator (Mac OS X) configurada en la carpeta que cada vez que aparece un nuevo archivo, lo cambia de tamaño y lo sube a un FTP usando Transmitir.

Aquí es donde el código entra en acción.

Tengo una página web que muestra la foto más reciente tomada. Utiliza ajax para verificar repetidamente si se ha subido o no un archivo nuevo y, en caso afirmativo, cargue la nueva foto y realice un fundido cruzado con la foto anterior. Aquí está el Javascript ejecutándose en la página.

(function() { 
    var delay, refreshLoop; 

    // Alias to setTimeout that reverses the parameters, making it much cleaner in code (for CoffeeScript) 
    delay = function(time, callback) { 
    return setTimeout(callback, time); 
    }; 

    // Function that drives the loop of refreshing photos 
    refreshLoop = function(currentFolderState, refreshRate) { 
    // Get the new folder state 
    $.get("ajax/getFolderState.php", function(newFolderState) { 
     // If the new folder state is different 
     if (newFolderState !== currentFolderState) { 
     // Get the newest photo 
     $.get("ajax/getNewestPhoto.php", function(photoFilename) { 
      var img; 
      // Create the new image element 
      img = $('<img class="new-photo"/>') 
      // Append the src attribute to it after so it can BG load 
      .attr('src', "/events/mindsmack/booth/cinco-de-mindsmack-2012/" + photoFilename) 
      // When the image is loaded 
      .load(function() { 
       // Append the image to the photos container 
       $('#photos').append(img); 
       // Crossfade it with the old photo 
       $('#photos .current-photo').fadeOut(); 
       $('#photos .new-photo').fadeIn().removeClass("new-photo").addClass("current-photo"); 
      }); 
     }); 
     } 
     // Wait for the refresh rate and then repeat 
     delay(refreshRate, function() { 
     refreshLoop(newFolderState, refreshRate); 
     }); 
    }); 
    }; 

    // Document Ready 
    $(function() { 
    var refreshRate; 

    // Load the first photo 
    $.get("ajax/getNewestPhoto.php", function(photoFilename) { 
     $('#photos').append("<img src='/events/mindsmack/booth/cinco-de-mindsmack-2012/" + photoFilename + "' class='current-photo' />"); 
    }); 
    refreshRate = 2000; 
    // After the timeout 
    delay(refreshRate, function() { 
     // Get the initial folder state and kick off the loop 
     $.get("ajax/getFolderState.php", function(initialFolderState) { 
     refreshLoop(initialFolderState, refreshRate); 
     }); 
    }); 
    }); 

}).call(this); 

Y aquí están los dos archivos PHP que se llaman en ese Javascript

getFolderState.php

<?php 

    $path = $_SERVER['DOCUMENT_ROOT'] . "/events/mindsmack/booth/cinco-de-mindsmack-2012/"; 

    // Get a directory listing of the path where the photos are stored 
    $dirListing = scandir($path); 

    // Echo an md5 hash of the directory listing 
    echo md5(serialize($dirListing)); 

getNewestPhoto.php

<?php 

    $path = $_SERVER['DOCUMENT_ROOT'] . "/events/mindsmack/booth/cinco-de-mindsmack-2012/"; 

    // Get a directory listing of the path where the photos are stored 
    $listing = scandir($path); 

    $modTime = 0; 
    $mostRecent = ""; 

    // Find the most recent file 
    foreach ($listing as $file) { 
     if (is_file($path.$file) && $file !== ".DS_Store" && filectime($path.$file) > $modTime) { 
      $modTime = filectime($path.$file); 
      $mostRecent = $file; 
     } 
    } 

    // Echo the most recent filename 
    echo $mostRecent; 

Todo esto funciona mayormente sin problemas . El problema, creo, es cuando el ciclo se dispara mientras un archivo está en el medio de ser cargado. Ocasionalmente se tomará una foto y solo aparecerá en la página parcialmente. No se arroja ningún error, la secuencia de comandos continúa funcionando correctamente y el archivo de imagen se almacena en caché en ese estado, lo que me hace creer que mi código está capturando una carga de archivo en progreso y solo muestra la parte del archivo que ha sido cargado en ese momento.

No me importa cambiar mi solución si es necesario para superar este problema, simplemente no estoy seguro de qué hacer exactamente.

EDITAR

De acuerdo con una de las siguientes sugerencias, que añade código a mi getNewestPhoto.php que comprueba el tamaño de archivo de la foto, espera un poco, y lo comprueba de nuevo. Si son diferentes, retrocede y comprueba nuevamente hasta que los tamaños de los archivos sean los mismos. Esperaba que esto captara los archivos que están en la mitad de la carga porque el tamaño del archivo cambiaría entre los bucles, pero incluso cuando las fotos aparecen parcialmente renderizadas, la verificación del tamaño del archivo no lo captó.

Aquí está el código añadí

$currFilesize = filesize($path . $mostRecent); 
$newFilesize; 

while (true) { 
    sleep(.5); 
    $newFilesize = filesize($path . $mostRecent); 

    if ($newFilesize == $currFilesize) { 
     break; 
    } 
    else { 
     $currFilesize = $newFilesize; 
    } 
} 

estoy pensando (a través de otra sugerencia) que tengo que añadir algún tipo de archivo de bloqueo de carga que se detiene el código de la actualización de la foto y se retira cuando el La carga está completa, pero al ver que no estoy ejecutando ningún tipo de servidor web en la computadora atada a la cámara, no estoy seguro de cómo lograrlo. Me encantaría las sugerencias

+1

A menos que pueda almacenar un archivo de "bloqueo" o algo mientras carga, ¿cómo sabrá PHP que está en medio de una transferencia? Probablemente la solución más fácil. Suba un 'filename.lck' y verifíquelo antes de incluirlo. Luego borre el bloqueo cuando termine de transferir. – MetalFrog

+0

Eso suena como una gran solución, pero no estoy seguro de cómo hacer eso, ya que no hay un código real involucrado en la carga del archivo. –

+0

Sí, no sé nada de Automator, solo estaba tratando de sacar una idea. Ojalá pudiera ser más ayuda. – MetalFrog

Respuesta

3

Hay muchas rutas para resolver esto, la mayoría mejor de lo que estoy a punto de sugerir. Creo que la solución más sencilla y rápida, sin embargo, es enviar un FTP a un directorio tmp y, cuando la transferencia se complete, desencadenar un movimiento del archivo al directorio de producción. ¿Su trabajo de automatizador local tiene ese mecanismo en sus relaciones con la transmisión?

+0

¿No podría potencialmente encontrarse con el mismo problema, simplemente al mover la foto entre carpetas en el servidor en lugar de cargarlas en primer lugar? –

+0

No lo creo. El movimiento sería casi instantáneo. – JAAulde

+0

No creo que tenga un mecanismo para mover archivos en el servidor remoto con Automator, solo cárguelos. ¿Puedes pensar en otra forma de lograr eso? Tal vez si montara el servidor como una unidad, en lugar de cargarlo a través de FTP, ¿podría mover archivos en él? –

1

Haría que el script PHP verificara el tamaño del archivo en un bucle con una demora (pequeña), y si coincide, luego se emite el archivo. De lo contrario, bucle hasta que lo haga.

+0

El código PHP realmente no sabe cuán grande se supone que sea la imagen _incoming_ ... – JAAulde

+1

Puede hacer que el script del automatizador compruebe primero el nombre del archivo, luego suba ESO como pequeño archivo de texto, y haga que el script PHP verifique eso y haga coincidirlo. O, simplemente verifique si el tamaño de archivo DIFERENCIAS entre dos iteraciones del ciclo. – gcochard

+0

Es cierto, esa es una opción. – JAAulde

Cuestiones relacionadas