0

I'm new to php and I'm trying to get the current date and time and the available space on disk and update it every second on a web page.

For the date and time I use: date("d-m-Y H:i:s").

For getting the free space I know I can use the diskfreespace() function that takes the path as argument. In my case I'm trying with diskfreespace("C:").

It returns the number of bytes and since I have Gigabytes of space I divide the number of bytes in order to get the number of Gigabytes.

diskfreespace("C:") / pow(1024, 3)

It works though it's executed only once and I'd like the function to execute every second and display the value through the echo function.

Then I tried using an infinite loop with a sleep() of 1 second but it seems there is a problem because the values aren't updated every second and it seems like if the page doesn't load properly.

<?php
while(1)
{
    echo "Current date and time: " . date("d-m-Y H:i:s");
    echo "</br></br>Free space on C: disk " . (diskfreespace("C:") / pow(1024, 3)) . " Gb";
    sleep(1);
}
?>
Fabio
  • 2,074
  • 2
  • 24
  • 38
  • I imagine it's running too high cpu through the loop and never getting to output the buffer. – William Isted Aug 25 '16 at 14:40
  • add a `flush()` to (hopefully) flush output buffers and send the data to the client. – Marc B Aug 25 '16 at 14:41
  • 1. "and it seems like if the page doesn't load properly" <-- What does this mean? 2. Try either flush() or ob_flush() http://php.net/manual/en/function.ob-flush.php – WillardSolutions Aug 25 '16 at 14:42
  • I'm testing this on my own computer and not on a shared host with limited resources anyway it could be. – Fabio Aug 25 '16 at 14:43
  • @EatPeanutButter well, I'm using Chrome and there is a circle spinning like when a page is being loaded but it takes a lot of time and never loads. It doesn't display anything. – Fabio Aug 25 '16 at 14:44
  • use something like `server sent events` to do the php stuff and javascript to update the display on your page. – Professor Abronsius Aug 25 '16 at 14:48
  • @EatPeanutButter actually I tried again and I waited more to see what happens..after many seconds, I have like 80 values displayed then the program doesn't update (like if it's sleeping or resources for execution aren't available) and then it echoes like 80 more values and so on. Instead I'd like it to update every second. – Fabio Aug 25 '16 at 14:51
  • @Fabio This is clearly a buffer issue. Read up on how to control the way PHP sends output to the browser: http://php.net/manual/en/book.outcontrol.php – WillardSolutions Aug 25 '16 at 14:53
  • `$i = 0;` `while(1 && $i<10) { $i++;` Try that, then if you can see after ~10 seconds anything outputs or if the script has completely crashed. – William Isted Aug 25 '16 at 14:57
  • @WilliamIsted I tried your code without sleep(1); and it echoes 10 times immediately without any wait. If I add sleep(1); at the end of the loop it will still echo 10 times not immediately but after many seconds. (all 10 together, not one by one, so yes it seems like it could be a buffer issue). I'd like to have it updated every second. – Fabio Aug 25 '16 at 15:05
  • @Fabio check out http://stackoverflow.com/a/3133284/1089331 – William Isted Aug 25 '16 at 15:10

3 Answers3

1

If you use Server Sent Events you can have a connection to a PHP script that runs in an infinite loop that pushes out the data to a javascript listener.

<?php
    /*
        diskspace_sse.php
    */

    set_time_limit( 0 );

    ini_set('auto_detect_line_endings', 1);
    ini_set('max_execution_time', '0');

    /* -- Edit to suit your location -- */
    date_default_timezone_set( 'Europe/London' );
    ob_end_clean();



    /* -- set headers -- */
    header('Content-Type: text/event-stream'); /* !important! */
    header('Cache-Control: no-cache');
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Allow-Methods: GET');
    header('Access-Control-Expose-Headers: X-Events');  



    /* -- utility function to send formatted sse message -- */
    if( !function_exists('sse_message') ){
        function sse_message( $evtname='gas', $data=null, $retry=1000 ){
            if( !is_null( $data ) ){
                echo "event:".$evtname."\r\n";
                echo "retry:".$retry."\r\n";
                echo "data:" . json_encode( $data, JSON_FORCE_OBJECT|JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS );
                echo "\r\n\r\n";
            }
        }
    }



    /* -- How often to send messages -- */
    $sleep=1;
    $disk='c:';

    while( true ){
        if( connection_status() != CONNECTION_NORMAL or connection_aborted() ) {
            break;
        }
        /* Infinite loop is running - perform actions you need */
        $payload=array(
            'date'      =>  date(DATE_COOKIE),
            'diskspace' =>  disk_free_space($disk),
            'totalspace'=>  disk_total_space($disk),
            'formatted_diskspace'   =>  round( disk_free_space($disk) / pow( 1024,3 ), 2 ).'Gb',
            'formatted_total'       =>  round( disk_total_space($disk) / pow( 1024,3 ), 2 ).'Gb'
        );

        /* -- prepare sse message -- */
        sse_message( 'diskspace', $payload );

        /* -- Send output -- */
        if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @flush();

        /* wait */
        sleep( $sleep );
    }

    if( @ob_get_level() > 0 ) {
        for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @ob_end_clean();
    }
?>

In your html page

<div id='diskspace'></div>
<script type='text/javascript'>

    function bindEvtSource(){

        var url='http://localhost/diskspace_sse.php';

        if ( !!window.EventSource ) {

            var evtSource = new EventSource( url );

            evtSource.addEventListener( 'open', function(e){
                console.log(e.type);
            },false);

            evtSource.addEventListener( 'error', function(e){
                console.error('%o %s',e,e.type);
            },false);

            evtSource.addEventListener( 'diskspace', function(e){
                var json=JSON.parse(e.data);
                /* you could work with the json data here */
                getobject('diskspace').innerHTML=e.data;
            },false);

        } else {
            alert('Server Sent Events are not supported in this browser');
        }
    }
    document.addEventListener( 'DOMContentLoaded', bindEvtSource, false );
</script>

You should get feedback about the diskspace usage every second with no ( very little ) slowdown in page load times.

Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • I'm new to PHP and although I used JavaScript before I haven't used Ajax yet. From what I read SSE is similar to Ajax in a way, but better because it doesn't have overhead due to polling in a given interval no matter if there is new data from the server or not. I lack some basics, but I kind of understand. I'll have to read more about it and try it. Thanks for your answer. – Fabio Aug 25 '16 at 15:20
  • 1
    Ajax is a little different - in that you send a request which in turn sends the response. This is a one time thing so to get constant feedback it was common to use ajax with `setTimeout` so a new request would be sent/answered every X seconds. With SSE you make a connection to the php script ( in this case ) and it pushes messages back to the javascript listener in the form of `text/event-stream` with no further interaction / function calls needed at the client side. – Professor Abronsius Aug 25 '16 at 15:27
  • errr - I meant `setInterval` rather than `setTimeout` - my mistook – Professor Abronsius Aug 25 '16 at 16:19
  • I created the html and php pages making sure to link them together..I see there is a var url in the html. If I open the html page I don't see anything. If I open the php page I see the values echoed every second in a JSON format. Sample output: http://pastebin.com/JbQUKLLZ . So it seems it isn't working from the html page. – Fabio Aug 25 '16 at 16:25
0

Echo shows result after code finishs the job. In your case, it may work in console application, not in web. To get your goal you have to look at ajax. In front side you need to call your php code, and render result. After a second do it again.

0

Check this answer.

Also, instead of the infinite loop in PHP, you may want to implement a simple polling mechanism with AJAX requests. Otherwise, depending on your server settings, your infinite loop may be stopped after a period of time. See max_execution_time.

Community
  • 1
  • 1
Zoli Szabó
  • 4,366
  • 1
  • 13
  • 19