Progress meter
Hiermee kan je van een langdurend script de voortgang monitoren. jQuery is vereist, ik ben niet zo goed in javascript. EDIT: Nu ook een percentage en mooie bar EDIT 2: Bijna alle JS staat nu in een JS bestand en kan dus gecached worden. Let wel op om Progress::script() vóór het JS bestand uit te voeren. De werking is als volgt: De hoofdpagina roept de action aan, deze slaat zijn voortgang op in de sessie. Ook roept de hoofdpagina om de zo veel tijd (in te stellen) de leespagina op die de voortgang uit de sessie leest en json encoded weergeeft. De hoofdpagina geeft dat dan weer. Op de action pagina kan je het volgende aanroepen: De read pagina is standaard, zie daarvoor de code. De index pagina In script.js kan je de acties van update, done en error instellen. Bij error heb je beschikking over data.error.text voor de errortext en data.error.code voor de errorcode, als deze bij Progress::error() is opgegeven. Alle commentaar is van harte welkom.
index.php
[code]
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'on');
include 'lib.php';
$progress = new Progress('namespace');
$progress->setOutputContainer('content')
->setActionUrl('action.php')
->setActionPostData(array('key'=>'value'))
->setReadUrl('read.php')
->setInterval(0.5);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Title</title>
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css" />
<?php echo $progress->script(); ?>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
$(function() {
$("#progressbar").progressbar({
value: 0
});
});
</script>
</head>
<body>
<div id="progressbar" style="width:400px; height:20px;"></div>
<div id="content"></div>
</body>
</html>[/code]
script.js
[code]
$(function(){$.ajax({
type: "POST",
data: actionData,
url: actionUrl,
timeout: 120*1000,
error: function(XMLHttpRequest, textStatus, errorThrown) { console.log(textStatus); }
});
});
var interval = setInterval(function(){
$.ajax({
url: readUrl,
success: function(data) {
if(data.done != undefined) {
/*
* Action complete handling
*/
$("#content").html("done");
clearInterval(interval);
$("#progressbar").progressbar("option", "value", 100);
/*
* End action complete handling
*/
} else if(data.error != undefined) {
/*
* Error handler. data.error.text is the errortext, data.error.code is the optional errorcode
*/
$("#content").html(data.error.text);
clearInterval(interval);
/*
* End error handler
*/
} else {
if(previousProgress >= data.progress){return;}
/*
* Update handler
*/
var percentage = Math.round(data.progress/data.max*100);
$("#progressbar").progressbar("option", "value", percentage);
$("#content").html(percentage+"%<br />"+data.progress+"/"+data.max);
/*
* End update handler
*/
var previousProgress = data.progress;
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {console.log(textStatus);},
dataType: "json",
type: "GET"
});
}, readInterval
);
[/code]
read.php
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'on');
session_start();
require_once 'lib.php';
$progress = new Progress('namespace');
echo $progress->read();
?>
action.php
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'on');
session_start();
set_time_limit(120);
require_once 'lib.php';
$progress = new Progress('namespace');
$progress->reset()->setMax(80);
// Dummy actie, slaapt 100x 0.05 sec
try {
for($i = 1; $i <= 80; $i++) {
usleep(0.05E6);
$progress->update($i);
}
$progress->done();
echo 'done';
} catch(Exception $e) {
$progress->error('An error has occured');
echo 'error';
}
?>
lib.php
<?php
/*
* Progress meter
* @author Pim de Haan
* @version 1.1
*
* @package Progress
*/
/*
* The class
* Three files use it:
* - The main page
* - The action page
* - The read page
*
* The main page first calls action through AJAX, which stores the progress in the session.
* Then it calls the read page through AJAX on a specified interval.
* The read page reads the session and echoes it json encoded.
* The main page then translates and displays the json code.
*
* @package Progress
*/
class Progress {
/*
* The action options, including the URL and the optional POST vars
* @access private
* @var array
*/
private $_action = array();
/*
* The URL of the read page
* @access private
* @var string
*/
private $_readUrl;
/*
* The id of the element containing the output
* @access private
* @var string
*/
private $_outputContainer;
/*
* The namespace of the session data, for using multiple progress meters simultaneously
* @access private
* @var string
*/
private $_namespace;
/*
* The interval for the AJAX calls to the read page
* @access private
* @var int
*/
private $_interval = 1;
/*
* The constructor, sets {@link $_namespace}
* @param $namespace string
*/
public function __construct($namespace = 'default') {
if(!session_id()) {
session_start();
}
$this->_namespace = $namespace;
}
/*
* Sets {@link $_outputContainer}
* @param $namespace string
* @return Progress
*/
public function setOutputContainer($container) {
$this->_outputContainer = $container;
return $this;
}
/*
* Sets {@link $_action}
* @param $url string
* @return Progress
*/
public function setActionUrl($url) {
$this->_action['url'] = $url;
return $this;
}
/*
* Sets {@link $_action} ['postdata'], if it is a associative array, it is converted to a string
* @param $data string|array
* @return Progress
*/
public function setActionPostData($data) {
if(is_string($data)) {
$query = $data;
} else {
$query = '';
foreach($data as $key => $value) {
$query .= '&'.urlencode($key).'='.urlencode($value);
}
$query = substr($query, 1);
}
$this->_action['postData'] = $query;
return $this;
}
/*
* Sets {@link $_readUrl}
* @param $url string
* @return Progress
*/
public function setReadUrl($url) {
$this->_readUrl = $url;
return $this;
}
/*
* Sets {@link $_max}
* And resets the session
* @param $max int
* @return Progress
*/
public function setMax($max) {
$this->_write('max', $max);
return $this;
}
/*
* Sets {@link $_interval}
* @param $time int
* @return Progress
*/
public function setInterval($time) {
$this->_interval = $time;
return $this;
}
/*
* Sets current progress from the session using {@link Progress::_write()}
* @param $progress int
* @return Progress
*/
public function update($progress) {
$this->_write('progress', $progress);
return $this;
}
/*
* Sets a error
* @param $text string
* @param $code int
* @return Progress
*/
public function error($text, $code = null) {
$array['text'] = $text;
if(!is_null($code)) {
$array['code'] = $code;
}
$this->_write('error', $array);
return $this;
}
/*
* Sets the action is done
* @return Progress
*/
public function done() {
$this->_write('done', true);
return $this;
}
/*
* Reads current progress and max from the session using {@link Progress::_read()} and encodes it with JSON
* @return string
*/
public function read() {
$obj = new StdClass;
foreach($this->_readAll() as $key => $val) {
$obj->$key = $val;
}
$sessionData = $_SESSION;
@session_start();
$_SESSION = $sessionData;
$data = $_SESSION['progress'][$this->_namespace];
session_write_close();
return json_encode($data);
}
/*
* Writes a value to the session
* Keeps the data while reopening the session
* session_write_close() is used to prevent session locking
*
* @param $key string
* @param $value string|int|array
* @return Progress
*/
private function _write($key, $value) {
$sessionData = $_SESSION;
@session_start();
$_SESSION = $sessionData;
if(!is_null($key)) {
$_SESSION['progress'][$this->_namespace][$key] = $value;
} else {
$_SESSION['progress'][$this->_namespace] = $value;
}
session_write_close();
return $this;
}
/*
* Reads a value from the session
* @param $key string
* @return string|int
*/
private function _read($key) {
return $_SESSION['progress'][$this->_namespace][$key];
}
/*
* Resets the session
* @return Progress
*/
public function reset() {
$this->_write(null, null);
return $this;
}
/*
* Reads all session values
* @return array
*/
private function _readAll() {
return $_SESSION['progress'][$this->_namespace];
}
/*
* Returns the javascript
*
* @return string
*/
public function script() {
$return = '<script type="text/javascript">';
$return .= 'var actionData = "'.(isset($this->_action['postData'])?$this->_action['postData']:'').'";';
$return .= 'var actionUrl = "'.$this->_action['url'].'?'.session_name().'='.session_id().'";';
$return .= 'var readUrl = "'.$this->_readUrl.'?'.session_name().'='.session_id().'";';
$return .= 'var readInterval = '.$this->_interval*1000 .';';
$return .= '</script>';
return $return;
}
}
?>
Reacties
0