Solved

How to display result of a PHP script one by one?

Posted on 2013-12-31
15
1,143 Views
Last Modified: 2014-01-01
Hi,

I have a created a script which pings the devices and show the result. But there are around 100+ devices in the list and once I start the script it pings all devices and then show the result, which approximately takes 15 to 20 min.

I would be thankful if someone could tell me a way to display the output of the script one by one i.e. ping a device then show its result and then move to the next device and so on. But the result of all devices should be there on the page.

I have already tried ob_flush(); ob_start(); and flush(); but I could not get the expected result.

Thanks in advance.
0
Comment
Question by:Vipin Kumar
  • 5
  • 4
  • 3
  • +1
15 Comments
 
LVL 11

Expert Comment

by:Technodweeb
ID: 39749416
You are on the right track... Output buffering is the way to get it done. Can you share your code that was not working?
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 39749418
You might want to read Ray_Paseur's article:  Understanding Client/Server Protocols and Web Applications. This will give you an understanding of why what you want to do isn't necessarily straight-forward.

That said, you can achieve what you want with web sockets, but as I understand they are not yet supported by all browsers and webservers. The only other option would be to set up some AJAX code in your pages that polls the server for updates on the status of the long-running task. You could store the results of your pings in the user's session, and then return what's in session on each AJAX request. I'll have to defer to the others for an example as I don't have immediate access to a PHP machine at the moment.
0
 
LVL 1

Author Comment

by:Vipin Kumar
ID: 39749419
I have attached two files which contains the script to ping the devices. Would be thankful if you could let me know where to put the output buffering.
ping.inc.php
ping.php
0
 
LVL 11

Expert Comment

by:Technodweeb
ID: 39749436
Ping.php
<?php 
ob_start();
require_once('header.inc.php');
ini_set('max_execution_time', 300);
$time_start = microtime(true)."<br>";
function pingDomain($domain){
	exec("ping -n 4 -a $domain", $output, $status);
	/*if (strpos($output[2],'Reply from') !== false) {
    	$status='Alive';
	} else {
		$status='Dead';
	}*/
	$searchword = 'Reply from';
	$matches = array_filter($output, function($var) use ($searchword) { return preg_match("/\b$searchword\b/i", $var); });
	//print_r($matches);
	if(!empty($matches)){
		$status='Alive';
	} else {
		$status='Dead';
	}
	return $status;
}
$link = mysql_connect('localhost','root','P@ssw0rd');
$select = mysql_select_db('deviceping');
$result = mysql_query("SELECT * FROM devicelist ORDER BY name");
require_once('ping.inc.php');
require_once('footer.inc.php');
ob_end_flush();
?>

Open in new window


ping.inc.php
<h1>Device Status</h1>
<br>
<a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>"><img src="refresh.png">Refresh</a>
<table id="ticketTable" width="800" border="0" cellspacing="0" cellpadding="0">
    <caption>Showing All Devices</caption>
    <thead>
        <tr>
            <th class="centered"width="70" nowrap>Sl No.</th>
            <th width="250" nowrap>Device Name</th>
            <th width="100" nowrap>IP Address</th>
            <th width="100" nowrap>Type</th>
            <th width="150" nowrap>Location</th>
            <th width="100" nowrap>Status</th>
        </tr>
    </thead>
    <tbody>
            <?php
			$i=1;
			while($row = mysql_fetch_array($result))
			{
				echo "<tr>";
				echo "<td class='centered'>" . $i . "</td>";
				echo "<td>" . $row['name'] . "</td>";
				echo "<td>" . $row['ip_address'] . "</td>";
				echo "<td>" . $row['type'] . "</td>";
				echo "<td>" . $row['location'] . "</td>";
				$status = pingDomain($row['ip_address']);
        		/*if ($status != "Dead"){
        			echo "<p style='color:green;'>Alive</p>";
        		} else {
        			echo "<p style='color:red;'>Dead</p>";
        		}*/
        		if ($status != "Dead"){
        			echo "<td><input size='4' style='background-color:green;'></td>";
        		} else {
        			echo "<td><input size='4' style='background-color:red;'></td>";
        		}
				echo "</tr>";
				$i++;
			}
			$time_end = microtime(true);

			//dividing with 60 will give the execution time in minutes other wise seconds
			$execution_time = ($time_end - $time_start)/60;
			//execution time of the script
			echo '<b>Total Execution Time:</b> '.$execution_time.' Mins <br>';
			echo "<b>The Ping Test was last run at:</b>  ". date("j F l, Y G:i:s");
ob_flush();
			?>
    </tbody>
</table>
<p style="padding-left:400px;"><input type="button" value="Back" onClick='window.location.href="index.php"'></p>

Open in new window

0
 
LVL 1

Author Comment

by:Vipin Kumar
ID: 39749508
Output buffering as suggested is not working. If there is any other way using AJAX for ex. can you guide me how it can be done or a link which has the code and requires little bit of modification.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39749777
Output buffering is intended to cause the server to buffer (collect and store) the script output from the time it is started until (usually) the end of the script, so it may not be your friend here.  What you really want is output flush() but that by itself may not be enough to accomplish the task of getting output before the script ends.  You want to read the man page about flush() carefully to understand what else may be involved in trying to get a script to send output from intermediate operations.

This may also be somewhat useful:
http://www.php.net/manual/en/function.ob-implicit-flush.php

See also this script.  By padding the output string to a length that is long enough to overrun the server and browser buffers, I am able (on my system) to get the intermediate outputs.
http://www.laprbass.com/RAY_force_flush.php

<?php // RAY_force_flush.php
error_reporting(E_ALL);
date_default_timezone_set('America/New_York');


// SIMULATE A LONG-RUNNING JOB WITH INTERMITTENT BROWSER OUTPUT
// FORCE FLUSH THE BROWSER OUTPUT BEFORE THE END OF THE PAGE
// PAD THE OUTPUT STRING TO MAKE IT LONG SO THE SERVER SENDS IT


function my_echo($str, $len=512, $pad=' ')
{
    // PAD THE STRING WITH INVISIBLE WHITESPACE OR SIMILAR
    $str = str_pad($str, strlen($str) + $len, $pad);
    echo $str;
    echo PHP_EOL;
    flush();
}


// TEST THE URL ARGUMENT FOR "b=y" AND OPTIONALLY START THE OUTPUT BUFFER
$b = (!empty($_GET["b"])) ? $_GET["b"] : NULL;
if ($b == 'y') ob_start();


// RUN THE TEST MESSAGES, WAITING BETWEEN THE MESSAGES
my_echo("<br/>Hello #1 " . date('c'));
sleep(1);
my_echo("<br/>Hello #2 " . date('c'));
sleep(2);
my_echo("<br/>Hello #3 " . date('c'));
sleep(3);
my_echo("<br/>Hello #4 " . date('c'));
sleep(4);
my_echo("<br/>Hello #5 " . date('c'));
sleep(1);
my_echo("<br/>Hello #6 " . date('c'));

Open in new window

HTH, ~Ray
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39749792
Afterthought... This may or may not be helpful; it shows how a site monitor works.
http://www.laprbass.com/RAY_monitor_websites.php

<?php // RAY_monitor_websites.php
error_reporting(E_ALL);


// DEMONSTRATE HOW WEB SITE MONITORS WORK


// COMMONLY USED PORT NUMBERS
// SEE: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml (SLOW TO LOAD)
// SEE: http://browntips.com/cpanel-and-whm-port-numbers/
$ports["HTTP"]     =    80;
$ports["FTP"]      =    21;
$ports["SSH"]      =    22;
$ports["DNS"]      =    53;
$ports["MYSQL"]    =  3306;
$ports["CPANEL"]   =  2082;
$ports["CPANEL-S"] =  2083;
$ports["WHM"]      =  2086;
$ports["WHM-S"]    =  2087;
$ports["POP3"]     =   110;
$ports["SMTP"]     =    25;
$ports["BOGUS"]    = 11111; // THIS IS EXPECTED TO FAIL


// AN ARRAY OF WEB SITES TO MONITOR (SELF-MONITORING OR CHOOSE OTHER URLS)
$urls[] = $_SERVER["HTTP_HOST"];
$urls[] = 'www.twitter.com';
$urls[] = 'www.example.com';
$urls[] = 'www.knownBogusUrlNumber427.org';


// GET THE RESULTS AS SOON AS POSSIBLE
ob_implicit_flush();


// ITERATE OVER THE LIST OF URLs
foreach ($urls as $url)
{
    // THE RESULTS SET
    $errno = $errstr = array();

    // THE TIME TO ALLOW FOR CONNECTION
    $timex = 1;

    // TEST EACH OF THE PORTS - SEE http://php.net/manual/en/function.fsockopen.php
    foreach ($ports as $port_name => $port_number)
    {
        $fp
        = @fsockopen // @MAKE ERRORS SILENT
        ( $url
        , $port_number
        , $errno[$port_name]
        , $errstr[$port_name]
        , $timex
        )
        ;
        // COMPLETE FAILURE SIGNAL IS FALSE + errno=0
        if ( (!$fp) && ($errno[$port_name] == 0) )
        {
            $errno[$port_name] = 'FAIL';
        }
    }

    // REPORT WHAT HAPPENED
    echo "<pre>"  . PHP_EOL;
    echo "URL: $url TIME: $timex";
    foreach ($errno as $port_name => $error_number)
    {
        if (!$error_number)
        {
            echo PHP_EOL . "OK: $port_name $ports[$port_name]";
        }
        else
        {
            echo PHP_EOL . "ERROR $error_number: $port_name $errstr[$port_name] ON PORT $ports[$port_name]";
        }
    }
}

Open in new window

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 11

Accepted Solution

by:
Technodweeb earned 500 total points
ID: 39749797
I figured out the issue with the output buffering support. ob will not work with the exec() command. I can get it to work with the system() command as seen here:
http://www.gwloans.com/Testing/PingTest/NewPing.php

This function does some things to disable some of apaches efforts to buffer as well. Play with this function and see if you cannot use it in your project.
Code is kinda sloppy, sorry...
<?php
	disable_ob();	
		$i=1;
		while($i<=5)
		{
			echo "$i <BR>";
			system("ping -c 4 4.2.2.$i");
			echo "<br><br>";
			$i++;
		}
	
function disable_ob()
{
	// Turn off output buffering
    ini_set('output_buffering', 'off');
    // Turn off PHP output compression
    ini_set('zlib.output_compression', false);
    // Implicitly flush the buffer(s)
    ini_set('implicit_flush', true);
    ob_implicit_flush(true);
    // Clear, and turn off output buffering
    while (ob_get_level() > 0) {
        // Get the curent level
        $level = ob_get_level();
        // End the buffering
        ob_end_clean();
        // If the current level has not changed, abort
        if (ob_get_level() == $level) break;
    }
    // Disable apache output buffering/compression
    if (function_exists('apache_setenv')) {
        apache_setenv('no-gzip', '1');
        apache_setenv('dont-vary', '1');
    }
}
?>

Open in new window

0
 
LVL 1

Author Comment

by:Vipin Kumar
ID: 39749860
Hi Technoweed,

Your solution works, but there is small issue. All the formatting and everything is gone. The output is being displayed but with out formatting. If you could help me how to get the formatting as well.

Thanks in advance.
0
 
LVL 11

Expert Comment

by:Technodweeb
ID: 39749867
can that be a separate question?
0
 
LVL 1

Author Comment

by:Vipin Kumar
ID: 39749871
i misplaced the function call. the issue has been solved now. thanks for your support.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 39750038
For my own edification, using the selected solution if I were to call this function from another script--one that generates a page--then the whole of my page will not be rendered until this function finishes, correct? I mean, I'll get back everything before the function call, then my function results, one at a time, and then the remainder of my page, yes?
0
 
LVL 11

Expert Comment

by:Technodweeb
ID: 39750059
Yes, that is exactly how it seems to work. Alternatively, you could use the output buffering ob_start(), etc. to do much of the same. I wound up going this direction quite a ways before it became a reality that the issue I was chasing was the exec() function not liking to be run within the buffering. I switched to the system() function and left the other work as is.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39750084
@kaufmed®:

I've plowed this field before.  If you want to see how it works with direct script access, click here.
http://www.laprbass.com/RAY_force_flush.php

The example in this response is what you'll be seeing.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28328557.html#a39749777

If you call the "force flush" script from another PHP script, your method of access may interact with server-side buffering to determine whether you will see the responses in a timely (piecemeal) manner.  PHP file_get_contents() will wait until the script ends, then return the responses all at once.  Using fopen() and fread() I am able to get the responses as each one is created.
http://www.laprbass.com/RAY_temp_kaufmed.php

<?php // RAY_temp_kaufmed.php


// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28328557.html#a39750038


// A SCRIPT THAT WILL EMIT DATA IN TIME-DELAY BURSTS
$url = 'http://www.laprbass.com/RAY_force_flush.php';
$fpr = fopen($url, 'r');

// READ AND ECHO THE DATA AS IT IS RETURNED
while (!feof($fpr))
{
    $dat = fread($fpr, 8192);
    echo $dat;
}

Open in new window

It's not clear to me that the system() command has anything to do with this.  The behavior I observe when I use Firefox to visit the link in the accepted solution is a very long pause, followed by a large burst of data, suggesting that there is some buffering going on.  The behavior I see in Chrome is more piecemeal and I think more in line with what the Author wanted.  So it may be as simple as changing browsers ;-)
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 39750148
OK, what I was thinking of was along the lines of:

Main Page
<?php
    session_start();            // Start the session so...
    $unique_id = session_id();  // ...we can get a unique id for this user
    session_write_close();      // Close the session file because we're not using it
    $status_filename = 'user/' . $unique_id . '_status';  // Create a distinct filename for this user

    exec('php pinger.php ' . $status_filename . ' > /dev/null &');  // Redirect to prevent hang
?>
<!DOCTYPE html>
<html>
    <head>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    </head>
    <div>This is some content before</div>
    <ul id="list-status"></ul>
    <div>This is some content before</div>
    <script>
        var interval = setInterval(function() {
            $.get("status.php", function (data) {
                var items = data.split('\n');
                var bound = items.length;
                
                if (items[bound - 1] == 'done') {
                    clearInterval(interval);
                }
                
                $('#list-status').empty();
                
                for (var i = 0; i < bound; i++) {
                    $('<li>' + items[i] + '</li>').appendTo('#list-status');
                }
            });
        }, 1000 * 2);  // Every 2 seconds
    </script>
</html>

Open in new window


Ping Script
<?php
    if (count($argv) > 1) {
        $status_filename = $argv[1];
        
        if (file_exists($status_filename)) {
            unlink($status_filename);
        }
        
        $fh = fopen($status_filename, 'a+');

        // Simulate pings
        for ($i = 0; $i < 5; $i++) {
            fwrite($fh, 'ping' . $i . ' completed' . "\n");
            fflush($fh);
            sleep(3);
        }
        
        fwrite($fh, 'done');
        fclose($fh);
    }

Open in new window


Status Script
<?php

    session_start();
    $unique_id = session_id();
    session_write_close();
    $status_filename = 'user/' . $unique_id . '_status';
    
    if (file_exists($status_filename)) {
        $response = file_get_contents($status_filename);
    }
    else {
        $response = 'done';
    }
    
    echo $response;

Open in new window


So once the page loads you see:

Before AJAX
...while it's running you see:

Mid-execution
...and when it's done you see:

Complete
All of the regular page content is visible during the entire process. It seems to me that doesn't happen in the other suggestions. But PHP is not my forte, so I'll gladly bow out if I am just missing the point  = )
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Popularity Can Be Measured Sometimes we deal with questions of popularity, and we need a way to collect opinions from our clients.  This article shows a simple teaching example of how we might elect a favorite color by letting our clients vote for …
Generating table dynamically is the most common issue faced by php developers.... So it seems there is a need of an article that explains the basic concept of generating tables dynamically. It just requires a basic knowledge of html and little maths…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now