Create a simple table as follows:
CREATE TABLE progress_data ( statusId int(4) NOT NULL AUTO_INCREMENT, progress float DEFAULT NULL COMMENT 'percentage', PRIMARY KEY (id_progress_data) );
JQuery code:
//this uses Jquery Timers http://plugins.jquery.com/project/timers $('#bUpdate').click(function() { //first obtain a unique ID of this operation - this has to by synchronized $.ajaxSetup({'async': false}); $.post('ajax.php', {'operation': 'beginOperation'}, function(data) { statusId = parseInt(data.statusId); }); //now run the long-running task with the operation ID and other params as necessary $.ajaxSetup({'async': true}); $.post('ajax.php', {'operation': 'updateSite', 'statusId': statusId, 'param': paramValue}, function(data) { $('#progress_bar').stopTime('statusLog'); //long operation is finished - stop the timer if (data.result) { //operation probably successful } else { //operation failed } }); //query for progress every 4s, 'statusLog' is just the name of the timer $('#progress_bar').everyTime('4s', 'statusLog', function() { var elm = $(this); $.post('ajax.php', {'operation': 'showLog', 'statusId': statusId}, function(data) { if (data) { //set bar percentage $('#progress').css('width', parseInt(data.progress) + '%'); } }); }); return false; }
Internal code (in PHP):
if (isset($_POST['operation'])) { ini_set("display_errors", false); session_write_close(); //otherwise requests would block each other switch ($_POST['operation']) { /** * Initialize progress operation, acquire ID (statusId) of that operation and pass it back to * JS frontend. The frontend then sends the statusId back to get current state of progress of * a given operation. */ case 'beginOperation': { $statusId = //insert into progress_data echo json_encode(array('statusId' => $statusId)); break; } /** * Return back current progress state. */ case 'showLog': { $result->progress = (float) //SELECT progress FROM progress_data WHERE statusId = $_POST['statusId'] echo json_encode($result); break; } case 'updateSite': { //start long running operation, return whatever you want to, during the operation ocassionally do: UPDATE progress_data SET progress=... WHERE statusId = $_POST['statusId'] } } } /* Terminate script, since this 'view' has no template, there si nothing to display. */ exit;
I have already used this approach in 3 applications, and I have to say that it is very reliable and fast enogh (the showLog operation is just a simple SELECT statement). You can also use the session to save progress, but this creates a lot of problems, since the session must be closed for writing (if it is stored in files), otherwise showLog AJAX requests will wait for the long operation to complete (and free sense).
Odin Dec 19 '10 at 23:00 2010-12-19 23:00
source share