2

I need to read a file that is changing all the time. the file only and will only ever have one line that changes all the time.

I found the following code that should do what I want here: PHP: How to read a file live that is constantly being written to

But the code does not work, the page just keeps loading, I tried to add a "flush" like one user suggested, but I still cant make it work.

Here's the code

$file='/home/user/youfile.txt';
$lastpos = 0;
while (true) {
    usleep(300000); //0.3 s
    clearstatcache(false, $file);
    $len = filesize($file);
    if ($len < $lastpos) {
        //file deleted or reset
        $lastpos = $len;
    }
    elseif ($len > $lastpos) {
        $f = fopen($file, "rb");
        if ($f === false)
            die();
        fseek($f, $lastpos);
        while (!feof($f)) {
            $buffer = fread($f, 4096);
            echo $buffer;
            flush();
        }
        $lastpos = ftell($f);
        fclose($f);
    }
}

Please could someone have a look and let me know how to fix it. Thanks in advance.

Community
  • 1
  • 1
Coenster
  • 125
  • 1
  • 2
  • 8

2 Answers2

2

If your file have only one string, and you need to read it on change, use this code:

$file = '/path/to/test.txt';
$last_modify_time = 0;
while (true) {
    sleep(1); // 1 s
    clearstatcache(true, $file);
    $curr_modify_time = filemtime($file);
    if ($last_modify_time < $curr_modify_time) {
        echo file_get_contents($file);
    }

    $last_modify_time = $curr_modify_time;
}

Note:

filemtime() returns last file modification time in seconds, so if you need to check modification more than one time per second, probably you'll need to find other solutions.

Also, you may need to add set_time_limit(0); it depends on your requirements.

Update:

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
            type="text/javascript">
    </script>
</head>
<body>
    <div id="file_content"></div>
    <script>
        var time = 0;
        setInterval(function() {
            $.ajax({
                type: "POST",
                data: {time : time},
                url: "fileupdate.php",
                success: function (data) {
                    var result = $.parseJSON(data)
                    if (result.content) {
                        $('#file_content').append('<br>' + result.content);
                    }
                    time = result.time;
                }
            });
        }, 1000);
    </script>
</body>

fileupdate.php

<?php
$file = 'test.txt';
$result = array();
clearstatcache(true, $file);

$data['time']    = filemtime($file);
$data['content'] = $_POST['time'] < $data['time']
    ? file_get_contents($file)
    : false;

echo json_encode($data);
Alexander Yancharuk
  • 13,817
  • 5
  • 55
  • 55
  • Hey Alexander. Your solution looks good, but my page still keeps loading. I tried your code without the "while (true) {" and the page loaded displaying the contents of $file, but obviously it didn't update. Any idea why my page would hang with this "while (true) {"? – Coenster Mar 21 '14 at 08:47
  • @Coenster `while(true)` is an endless cycle. This script will run until error happens or process will be killed or http-server closes connection by timeout. When page keeps loading - it's normal behavior for script with endless cycle. If you need to update info on your page without "page hang", you need to remove `while(true)` cycle and create javascript ajax-requests. – Alexander Yancharuk Mar 21 '14 at 10:42
  • Thanks. Its a little disappointing about the while(true) not going to work. I unfortunately have no idea how to go about the javascript ajax-requests(I have never even seen ajax code) If there are some tutorials to follow about javascript ajax-requests to help me accomplish my goal or if you could help with a sample/demo code I would really appreciate it. – Coenster Mar 21 '14 at 13:46
  • @Coenster Answer updated. Look at the simple example of file content update by ajax requests. Place 2 files (index.html, fileupdate.php) in your document root folder. – Alexander Yancharuk Mar 24 '14 at 07:01
  • This is worth gold for me at the moment. It is awesome! just one last question if you don't mind. how can I edit this line so that the new content will replace the old instead of adding it to the bottom? $('#file_content').append('
    ' + result.content);
    – Coenster Mar 24 '14 at 07:56
  • don't worry i replaced $('#file_content').append('
    ' + result.content); with this: $('#file_content').html('
    ' + result.content); Now its All good. Thanks for your help.
    – Coenster Mar 24 '14 at 09:13
0

You might be dealing with 3 drawbacks:

  • First, the code you already have is holding a $lastpos. Meaning, it will always look for what is added at the end of the file. You are not clear in the OP, but I think this is not what you want. I think your one and only line is continuously changing, but not necessarily changing size. So you might want to remove the line $lastpos = ftell($f);.
  • Secondly, in regards to the same, you are check the file size to know if the file has changed. But as I explained, the file might have changed, while the file size stayed equal. Try changing the check of the file size to checking the file last-edit date.
  • Third, and probably most importantly: your web browser might be buffering your output until the php script is done running, before it releases the buffered output to the browser. Disable output buffering in both PHP and your web server. Things like gzip/compression by the web server can also be forcing output-buffering effects.
nl-x
  • 11,762
  • 7
  • 33
  • 61