I was wondering how to make progress bar like gmail.
I tried
<script src="jquery.js"></script>
<script>
$(function (){
$.ajax({
url: 'index.php',
success: function(data) {
$('#bar').html(data);
}
});
})
</script>
<div id="bar"></div>
And on index.php
[EDIT]: by sleep() i just meant to simulate continuous stream of output like multithreaded programs which is not supported in php.
<?php
for($i=0; $i<=10; $i++)
{
sleep(1);
echo "$i";
}
it seems that output is echoed out at once so i get result 012345678910 at once.
also i tried
setInterval(function (){
$.ajax({
url: 'index.php',
success: function(data) {
$('#bar').html(data);
}
});
}, 1000);
Instead, i had trouble maintaining value of 'progress', so i did
<?php
session_start();
if(isset($_SESSION['value'])){
if($_SESSION['value'] >= 10)
{
unset($_SESSION['value']);
}
else
{
$_SESSION['value']++;
}
}
else
{
$_SESSION['value'] = 0;
}
echo $_SESSION['value'];
as part of my php. But it seems that, i am calling ajax function on continuous interval.
My Question is,
How does google use progress bar, while loginng in gmail. Do they get continuos 'stream' of data like i tried on my first example or send (regularly) request on some url (though not through ajax .. through JSONP or whatever) and upadate the page like second ?
Can I do same with php , even if not with php, can I do it using javascript and other server side scripting language where multithreading is supported?
I'm not sure what exactly Gmail does for the progressbar, but you can achieve something similar in PHP, although it may be a bit tricky.
First, to explain why your examples don't work:
If you echo and sleep, like your first example, it will never work. Ajax performs a full request - that is, if the response does not finish, it will wait. When you loop and sleep, the request is not "closed" until the PHP script has finished executing.
If you use session, like in the other example, the problem becomes the session store. The store is typically locked during script execution, and it will not update itself to allow for the type of progress check you want.
What you could do is write progress to a file (or to a database) manually. For example:
file_put_contents('progress.txt', 1);
Then, have another script read the file and output the contents.
This should work, because file_put_contents opens, writes and closes the file.
Using some other language than PHP would make it easier. Being multithreaded would possibly make it easier, but is not a requirement. However, having a continuously running process would make it simpler (PHP only runs a process for the duration of your request and then exits)
run your jquery code at an interval, and use PHP to print the progress percenage and draw the bar then.
so it will be something like
<script>
function bar()
{
var v=getProgress(...);
setTimeout("bar()",1000);
drawBar();
}
function drawBar(l)
{
//set div's length to l
}
</script>
EDIT 2
<?php
/* get the request and calculate the job completion percentage and echo it ! */
?>
I think Gmail shows progress when it loads all resources, like JS files. There are different ways to do this: you could dynamically include all resources with JS, or you could make all included JS files report that they've been loaded.
To make PHP output partial output, use this:
ob.php
<?php
ob_start();
for ($i = 0; $i < 100; $i++) {
echo "{$i}<br />";
ob_flush();
flush();
usleep(100000);
}
.htaccess
php_value output_buffering "0"
this thread and this link helped me to find out solution for the same problem, so i am providing it for the record:
test.php:
<?php
for($i=0; $i<100; $i++)
{ usleep(100000); //100ms
echo 'A'; ob_flush(); flush();
}
?>
test.html:
<body>
<button onclick='call()'>call</button>
<div id='progress'>...</div>
<script>
function fprogress(e)
{ document.getElementById('progress').innerHTML ='progress: '+e.loaded +'%'; }
function call()
{ var req = new XMLHttpRequest();
req.addEventListener("progress", fprogress, false);
req.open('GET', 'test.php', true); req.send(null);
}
</script>
</body>
... so test.php can be any JOB which doing some stuff... and while doing it ECHOes 100 characters (bytes) with flashing buffer.
As per my opinion, you can divide your login process in several parts and checks.
Every part check completed send response to your progress bar and progress bar width will increase such patterns. After that progress bar will send next request to your login process for step untill you will not get upto 100% login and redirect.
Related
I have two scripts
I want to send via jQUERY a form to a PHP file, and see in a DIV the process, but it waits until if finish to show all, and sometimes it can take a few seconds making the user thinks its not doing anything
Here is what I have
I have a form like this
<button type="button" id="agregarfotos"> Load</button>
<div id="respuesta" style="width: 100%"></div>
<script>
$(document).ready(function() {
$('#agregarfotos').click(function() {
$.ajax({
type: 'post',
url: '../clases/class-album-procesar.php',
data: $('#mainforma').serialize(),
success: function (response) {
$('#respuesta').html(response);
});
});
});
</script>
And a PHP file named class-album-procesar.php with this:
<?php
ob_implicit_flush(1);
for($i=0; $i<15; $i++){
echo $i;
//this is for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
?>
If I run the class-album-procesar.php file by it self, I can see the numbers 1 to 14 one by one, like it should, but if I run it via the jquery file, it waits until the page is completed loaded to show the result
Is there a way to do this without having to wait until it finish?
Instead of doing the loop in php do it on jQuery.
for(var i = 0; i < 15; i++) {
$.ajax({..});
}
This way you will be splitting the processing on multiple php processes, so instead of one long php script you have multiple short php scripts
I think you need to use third party jQuery library, but not sure that work fine.
Because, During ajax call PHP server busy with process. At that time server can't send any data to client. Server wait for finish that process and send data or information to client with request status 200.
I'm trying to display the results while PHP script is running, as example.. a really long loop, i want it to echo the results while the page is loading, I searched really a lot through this and i couldn't find the good answer, After googling i found people saying use ob_flush from this question .. but it didn't work, as well as enabling the implicit_flush from php.ini , still didn't work
it only loads when the process is finished, i tried to run a for loop like this
ob_start();
for($i=0; $i<500; $i++){
echo "hm\n";
ob_flush();
}
ob_end_flush();
and still, didn't work.. it shows them all at once
My last guess now is that it needs more PHP configurations to enable/disable some stuff,
or.. it could also be apache2 configurations ?
What are the config settings that are related to this ? settings that needs to be disabled/enabled through Apache or PHP configurations ..
P.S. : I'm sure its possible to be done using PHP alone, I saw it done on GoDaddy hosting and saw it on several websites, of them http://www.checker.freeproxy.ru/checker/index.php .. if you try to submit it will show the results normally without using ajax, the website uses PHP and Apache, there's a mystery secret behind this
I used this way from this answer
while(1) {
echo "should display these lines on browser while in infinite loop.<br>";
flush();
}
or using the for loop, they both work fine, and it to make it more accurate i use ob_flush() with flush()
for($i=0; $i<5000; $i++) {
echo "should display these lines on browser while in infinite loop.<br>";
usleep(30000);
ob_flush();
flush();
}
they both work fine without ajax
Check my post here: Show progress bar in php while loop
It has some sample code as well, and covers pretty much everything you need.
PS: It can't be done with PHP alone, you need to do this with AJAX + PHP (client + server side coding). This is because the response is sent to the browser only after the file is fully interpreted.
You can't do this with PHP. PHP is run server side so it executes before the HTTP response is sent back to the browser.
You would need to use AJAX to achieve this.
You may also look at websockets to achieve this kind of thing.
You could also cheat and load all the data into a hidden list, and then use javascript to show the list items one by one after the page has loaded. :)
As mentioned above, Ajax would be the best method.
You'll need 3 files, a html file or php file that heads the job, a javascript file with your ajax in it and the php file running your script, here's an example of how you could do this. The rest is up to you if you need it tweaking for whatever you are trying to do, but it should give a sequential redout if you break up your php accordingly.
go.hml:
<html>
<head>
<title>Insert Title Here</title>
<script src="ajax_example.js" language="javascript"></script>
</head>
<body>
<form action="javascript:insert()" method="post">
<input type="text" name="limit" value="" id="limit"/>
<input type="submit" name="Submit" value="Go"/>
</form>
<div id="text_response"></div>
</body>
</html>
ajax_example.js:
// make script work for internet explorer too
function createObject(){
var request_type;
var browser = navigator.appName;
if(browser == 'Microsoft Internet Explorer'){
request_type = new ActiveXObject('Microsoft.XMLHTTP');
}else{
request_type = new XMLHttpRequest();
}
return request_type;
}
var http = createObject();
var response = '';
var current = 0;
var limit = 0;
function insert(){
current = 0;
// write to the document
response = 'Hang on...';
document.getElementById('text_response').innerHTML = response;
// set the limit and run the loop script
limit = encodeURI(document.getElementById('limit').value);
limit++;
loop_file(current);
}
function loop_file(i) {
// open the php file you wish to run, the 'hm' and 'rand' are optional, obviously
http.open('get', 'file.php?hm='+i+'&rand='+Math.random());
// run the insertReply function
http.onreadystatechange = insertReply;
http.send(null);
}
function insertReply(){
if(http.readyState == 4){
response = response+'<br />'+http.responseText;
document.getElementById('text_response').innerHTML = response;
current++;
// this runs like a pseudo for loop and will loop until it reaches the 'limit'
if(current < limit){
loop_file(current);
}else if(current == limit){
//create end script here
}
}
}
file.php
<?php
echo isset($_GET['hm']) ? $_GET['hm'] . " - hm\n" : "hm\n";
?>
I would like to know if it's possible without javascript to update an echo ?
For example
<?php
for ($i = 1; $i < 100; $i++){
echo $i;
}
?>
But it will only update the number without adding another line, and another until 100. Is this possible or only with javascript you can achieve this.
I need to output a counter to know how much files is being processed at the moment like
45 of 100 pages
No. client side (JavaScript for example) only. Because if you want to achieve this without page reload, then how PHP could be involved if PHP starts when request from browser comes?
PHP is a server-side language. The script is requested, executed and then sent to the client.
JavaScript executes client-side only. Which means that it can send a request to a PHP script, but will always return the result of the script.
The only option is AJAX requests. Basically, you write a PHP script that moves one file at a time. JavaScript handles the loop from 1 to 100 and send 100 synchronous requests to the PHP script with different parameters. Then you can track the progress and update DOM elements on your HTML page.
jQuery has a nice .ajax() function that can get you started. Below is a quick example. It won't work right off the bat but you can build on it to make it work.
PHP
<?php
$file = $_POST['file'];
$destination = $_POST['destination'];
// Move the stuff!
?>
JavaScript
var files = ['test.txt', 'test2.txt' /* ... */], /* Your list of files... */
destination = '/path/to/send/to/the/php/script/';
for(var i = 0; i < files.length; i ++){
$.ajax({
async: false,
url: 'script_to_move_files.php',
data: { file: files[i], destination: destination },
success: function(){
/* File moved! Update a progress bar or something... */
},
error: function(){
/* File wasn't moved successfully... */
}
});
}
for($x=0;$x<100000;$x++) {
echo "hello $x";
}
So, normally, it will finish processing everything first and then print everything at once. Is there a way to just keep printing the message as the command is sent, so that I'll see a new hello $x appended one by one or do I have to use jQuery/JavaScript?
Update:
I ask because I'm trying to run a long test script and have it show all the results 1 by 1 on the browser so I don't have to go check the logs and could just visually see the color coded results. I'm trying to make a similar effect to this: http://tools.css3.info/selectors-test/test.html If anyone could provide a short sample of the jQuery (if it has to be done this way), I would appreciate it.
Although it's possible by controlling the output buffer, I wouldn't do that, mainly because it will delay the JavaScript DOMReady event.
If you're looking for a visual effect, you should use JavaScript (but I don't see any reason for Ajax based on what your question says). It can be accomplished with a simple setInterval. Considering an initially empty <div id="hello">:
var i = 0;
var timer = setInterval(function(){
if(i == 10000) {
clearInterval(timer);
return;
}
var div = document.getElementById('hello');
div.innerHTML += 'hello ' + i + '<br>';
i++;
}, 250);
I just saw your edit, and now I think you actually should use Ajax! The example you linked to does. Basically, you have to setup a test queue in JavaScript, where each test has an unique URL. Then it's just a matter of firing one request at a time with Ajax (jQuery and $.get would be the easiest way to go). The following assumes an <ul> instead of the div from my previous example, and that the server will respond with a success or failure message for each test:
var tests = [
'http://example.com/test1',
'http://example.com/test2',
'http://example.com/test3',
];
function processQueue() {
if(tests.length > 0) {
var test = tests.shift();
$.get(test, function(response) {
$('#some_ul').append('<li>' + response + '</li>');
processQueue();
});
}
}
processQueue();
Yes, if you disable output buffering: http://php.net/manual/en/book.outcontrol.php
But as #Blender suggests you'd probably be better off doing this with AJAX (commonly done using jQuery).
I've got a web page that allows to start a certain process and then redirects to another page that displays log file of that process. Since execution takes up to 10 minutes, I want log page to autoupdate itself or load data from the file periodically.
Right now I added
<meta http-equiv="refresh" content="5;url=log.php#bottom" />
to html/head but wondering if there may be a better solution. Can someone give any advice on aproaching this problem?
I do it this way:
var current_length = 0;
function update() {
setTimeout(update, 3000);
$.post("/update_url", { 'current_length': current_length }, function(data) {
if (data.current_length != current_length) return; //it's too old answer
$("#log").html($("#log").html() + data.text);
current_length += data.text.length;
}, "json");
}
update();
The server must skip several bytes at beginning and send json with current_length and the rest of file.
I prefer using memcached to store process output.
You could:
Periodically poll the server to see if there are more messages, basically you would call a PHP script with javascript and would pass the length of the log file in the last poll and then insert into the document the new data. The server would return all the data after that offset and also the new length.
(simpler) Make a long lived PHP script that keeps reading the file and echo and flush it as soon as there's new data. See PHP: How to read a file live that is constantly being written to.
Use AJAX to do this. Easy in jQuery:
<script type="text/javascript">
$(function(){
window.setInterval('updateLog()', 5000);
});
function updateLog() {
$.get('log.php');
}
</script>
Why not use javascript?
Use setInterval and run an AJAX call to log.php periodically.
You could also use an iframe, but the AJAX perdiodical call is a better way of doing it in my opinion.