w3schools - PHP-Flushing While Loop Data con Ajax
while php mysql (4)
Usando PHP , me gustaría hacer un bucle while que lea un archivo grande y envíe el número de línea actual cuando se solicite. Usando Ajax , me gustaría obtener el recuento de líneas actual e imprimirlo en una página. Usando los botones html , me gustaría poder hacer clic y activar o terminar un hilo de javascript que se ejecuta solo UNA VEZ y llama al método ajax .
Le he dado una oportunidad, pero por alguna razón, no se imprime nada a menos que comente echo str_repeat('' '',1024*64);
función y cuando se comenta, muestra el resultado del bucle completo:
1 fila (s) procesadas.2 fila (s) procesadas.3 fila (s) procesadas.4 fila (s) procesadas.5 fila (s) procesadas.6 fila (s) procesadas.7 fila (s) procesadas.8 fila (s) procesada.9 fila (s) procesada.10 fila (s) procesada (s).
En una sola línea en lugar de mostrarlos en líneas separadas como:
1 row(s) processed.
2 row(s) processed.
3 row(s) processed.
4 row(s) processed.
5 row(s) processed.
6 row(s) processed.
7 row(s) processed.
8 row(s) processed.
9 row(s) processed.
10 row(s) processed.
Además, no estoy seguro de cómo terminar el hilo de JavaScript. Así que 2 problemas en total:
1. It''s returning the entire While loop object at once instead of each time it loops.
2. I''m not sure how to terminate the JQuery thread.
¿Algunas ideas? A continuación es mi código hasta ahora.
msgserv.php
<?php
//Initiate Line Count
$lineCount = 0;
// Set current filename
$file = "test.txt";
// Open the file for reading
$handle = fopen($file, "r");
//Change Execution Time to 8 Hours
ini_set(''max_execution_time'', 28800);
// Loop through the file until you reach the last line
while (!feof($handle)) {
// Read a line
$line = fgets($handle);
// Increment the counter
$lineCount++;
// Javascript for updating the progress bar and information
echo $lineCount . " row(s) processed.";
// This is for the buffer achieve the minimum size in order to flush data
//echo str_repeat('' '',1024*64);
// Send output to browser immediately
flush();
// Sleep one second so we can see the delay
//usleep(100);
}
// Release the file for access
fclose($handle);
?>
asd.html
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css" media="screen">
.msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
.new{ background-color:#3B9957;}
.error{ background-color:#992E36;}
</style>
</head>
<body>
<center>
<fieldset>
<legend>Count lines in a file</legend>
<input type="button" value="Start Counting" id="startCounting" />
<input type="button" value="Stop Counting!" onclick="clearInterval(not-Sure-How-To-Reference-Jquery-Thread);" />
</fieldset>
</center>
<div id="messages">
<div class="msg old"></div>
</div>
<script type="text/javascript" charset="utf-8">
function addmsg(type, msg){
/* Simple helper to add a div.
type is the name of a CSS class (old/new/error).
msg is the contents of the div */
$("#messages").append(
"<div class=''msg "+ type +"''>"+ msg +"</div>"
);
}
function waitForMsg(){
/* This requests the url "msgsrv.php"
When it complete (or errors)*/
$.ajax({
type: "GET",
url: "msgsrv.php",
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:2880000, /* Timeout in ms set to 8 hours */
success: function(data){ /* called when request to barge.php completes */
addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
setTimeout(
''waitForMsg()'', /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
''waitForMsg()'', /* Try again after.. */
"15000"); /* milliseconds (15seconds) */
},
});
};
$(''#startCounting'').click(function() {
waitForMsg();
});
</script>
</body>
</html>
test.txt
1
2
3
4
5
6
7
8
9
10
El truco es crear un archivo (actualizado a través de Ajax) y usar un setInterval
para obtener su valor, luego actualizar la setInterval
de progreso.
Estás confundido en cuanto a cómo interactúan PHP y AJAX.
Cuando solicita la página PHP a través de AJAX, obliga a la secuencia de comandos PHP a comenzar la ejecución. Aunque podría estar usando flush()
para borrar cualquier búfer interno de PHP, la llamada AJAX no terminará (es decir, no se llamará a los controladores de respuesta) hasta que se cierre la conexión, lo que ocurre cuando se lee el archivo completo.
Para lograr lo que está buscando, creo que necesitaría un proceso paralelo como este:
- La primera publicación de AJAX envía una solicitud para comenzar a leer el archivo. Esta secuencia de comandos genera un ID único, lo envía de vuelta al navegador, genera un hilo que realmente lee el archivo y termina.
- Todas las solicitudes subsiguientes de AJAX van a un script PHP diferente que verifica el estado de la lectura del archivo. Este nuevo script PHP envía el estado actual de la lectura del archivo, en función de la ID única generada en el # 1, y luego sale.
Podría lograr esta comunicación entre procesos a través $_SESSION
variables $_SESSION
, o almacenando datos en una base de datos. De cualquier manera, necesita una implementación paralela en lugar de su secuencia actual, de lo contrario, continuará obteniendo el estado completo de una vez.
Una solución más simple debería ser usar el objeto XHR nativo (vanila js).
Hay soluciones muy sofisticadas por ahí, sobre encuestas largas
El PHP:
<?php
header(''Content-Type: text/html; charset=UTF-8'');
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('''',4096)."/n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
El JS:
var xhr = new XMLHttpRequest();
xhr.open(''GET'', ''/api/some_service.php'', true);
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.status == 200) {
if (xhr.readyState == XMLHttpRequest.LOADING){
console.log(''response'',xhr.response);
// this can be also binary or your own content type
// (Blob and other stuff)
}
if (xhr.readyState == XMLHttpRequest.DONE){
console.log(''response'',xhr.response);
}
}
}
Utilizando:
debe hacer todo lo que necesita en un hilo php
EDITAR
Eche un vistazo a la respuesta de Nickb, si está buscando una forma de hacerlo, simplemente sería el siguiente algoritmo:
- javascript abre
process.php
través de ajax (que hará todo el trabajo Y se imprimirán los informes de estado), debe buscar si jQuery ajax admite la carga continua - Si el usuario decide detener las actualizaciones, matará la carga como se muestra en el enlace provisto
En process.php
:
ignore_user_abort(); // Script will finish in background
while(...){
echo "Page: $i/n";
ob_flush();
}
Ejemplo de EDIT 2 solicitado (poco diferente y feo, pero simple) . test_process.php
// This script will write numbers from 1 to 100 into file (whatever happens)
// And sends continuously info to user
$fp = fopen( ''/tmp/output.txt'', ''w'') or die(''Failed to open'');
set_time_limit( 120);
ignore_user_abort(true);
for( $i = 0; $i < 100; $i++){
echo "<script type=/"text/javascript/">parent.document.getElementById( ''foo'').innerHTML += ''Line $i<br />'';</script>";
echo str_repeat( '' '', 2048);
flush();
ob_flush();
sleep(1);
fwrite( $fp, "$i/n");
}
fclose( $fp);
Y la página html principal:
<iframe id="loadarea"></iframe><br />
<script>
function helper() {
document.getElementById(''loadarea'').src = ''test_process.php'';
}
function kill() {
document.getElementById(''loadarea'').src = '''';
}
</script>
<input type="button" onclick="helper()" value="Start">
<input type="button" onclick="kill()" value="Stop">
<div id="foo"></div>
Después de golpear las líneas de inicio como:
Line 1
Line 2
Apareció en el div #foo
. Cuando presioné Stop
, dejaron de aparecer pero el script terminó en segundo plano y escribieron los 100 números en el archivo.
Si presiona Start
secuencia de comandos comienza a ejecutarse desde el inicio (reescribir archivo), así lo haría la solicitud paralela.
Para más información sobre http streaming vea este enlace.