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
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
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. –
Sí, no sé nada de Automator, solo estaba tratando de sacar una idea. Ojalá pudiera ser más ayuda. – MetalFrog