javascript - 如何使用 PHP 和 Ajax 实时读取文件

标签 javascript php jquery ajax

<分区>

我想实时读取一个txt文件并更新我前端添加的新行。该文本文件包含两个用户的日志数据。我已经尝试了一些工作来找到一种工作方式,但是 php 脚本和 js 都没有按我想要的方式工作。

JS 脚本

  function ShowNewMessages(res, curr, end) {
    // build the front end
    var newdiv1 = "<div class=\"message\"> <div class=\"own-avatar-message\" style=\"background-image: url("+res[curr][4].replace(/\\\//g, "/")+");\"></div><div class=\"own-message2\"><div class=\"own-message\"><p>" +  res[curr][3]  +"</p></div><div class=\"message-timestamp\"> "+ res[curr][1] +" • "+res[curr][2] +"</div></div> </div>"; 

    $( newdiv1 ).insertAfter( $( ".message" ).last());
    var height = 0;
    $('.message').each(function(i, value){
        height += parseInt($(this).height());
    });

    height += '';

    $('div').animate({scrollTop: height});

    // check if there is another messsage or checkagain for new messages             
    curr++;
    if (curr <= end) ShowNewMessages(res, curr, end);
    else {setTimeout(function() {GetNewMesssages()}, 10000);}
}



function GetNewMesssages() {
    $.ajax({
        type:'POST',
        url: "../lib/GetMesssage.php",
        data: "friend=" + MsgFriend,
        dataType: 'json',
        async: false, 
        success:function(data){
            // check error state
            if (data[0] != "Error") {
                var start = 0;
                var end = data.length-1; // minus one for the new line
                if (end > 0 ) ShowNewMessages(data, start, end-1);
                else setTimeout(function() {GetNewMesssages()}, 10000);

            }
            else alert('some error message');
            }
        });   
} 

GetMesssage.php

<?php 

    session_start();

    // get the requirements for the file name
    $MyEmail = $_SESSION['login'];
    $FriendEmail = $_POST['friend'];

    if (strcmp($MyEmail, $FriendEmail) < 0) {
        $FileName = $MyEmail.'-'.$FriendEmail.'.txt';
    }
    else {
        $FileName = $FriendEmail.'-'.$MyEmail.'.txt';
    }


    $File = fopen('data/'.$FileName, "r") or die(json_encode(array_push($messages, "Error")));

    // count the lines exist in the file
    $count = 0;
    while(!feof($File)){
        $tmp = fgets($File);
        $count++;
    }

    // if the session var that holds the offset position is not set 
    // or has value more than the lines of text file
    if (!isset($_SESSION['pos']) || $_SESSION['pos'] >= $count) {
       $_SESSION['pos'] = 0; // back to the beginning
    } 

    // the array that holds the logs data
    $messages = array(); 

    // move the pointer to the current position
    fseek($File, $_SESSION['pos']);

    // read the file
    while(!feof($File)){
        $msg = fgets($File);
        $msg1 = explode("<!@#@>", $msg);
        array_push($messages, $msg1);
        $_SESSION['pos']++;
    }

    // get the current offset position
    //$_SESSION['pos'] = ftell($File);

    // return the array
    echo json_encode($messages);

    fclose($File)
?>

解释

假设当我们调用 GetNewMesssages() 函数时例程第一次启动。该函数将触发 php 并从文件中获取数据。

接下来,如果数据有内容,返回数组不为空,我们执行 ShowNewMessages() 函数并更新前端。

完成后,我们开始另一个 GetNewMesssages() 回调。

我想要什么

我想每 N 秒检查一次文件中是否有新添加的行并更新我的前端。

问题

我在 php 和 js 脚本中都遇到了问题。我不想添加两个问题。

在 PHP 中

我没有找到如何使用 ftell() 来只获取新添加的行。由于脚本按原样运行,每次更新时我都会不断地将所有文件放入我的数组中。

在 JS 中

在 JS 中,我在同步 ajax 调用时遇到了问题。这意味着在每次调用 GetNewMessages() 函数时,我都会再次调用该函数 2-3 次。它与 setTimeout() 有关,但我也找不到如何设置回调。

更新

我读取的文本文件示例:

line_id <BreakString> some data <BreakString> blah blah

another_line_id <BreakString> some_other data <BreakString> blah blah 2

注意:没有任何意义。它只是将内容分开到数组。

更新 2

在版主通知后,我会缩小我的问题,只是为了找到实时读取文件以保持我的结构的最佳方法。

最佳答案

PHP

在 PHP 中 fseek()将文件指针设置为文件中特定的字节 偏移量。您似乎在代码中所做的假设是 fseek() 会将指针设置为文件中的特定行。

假设您的消息不包含任何换行符(这段代码中没有这样的事实),您可以只使用 file()而不是将整个文件加载到 PHP 中的数组中,并确定您需要的行偏移量。

例如……

$file = file($fileName);
$mssages = array_slice($file, $_SESSION['pos']);

这将为您提供文件中从 $_SESSION['pos'] 行偏移量开始的所有行的数组。


重构现有的 PHP 代码

要重构您现有的代码,您可以修改以下循环以在它命中 $_SESSION['pos'] 时停止读取,从而继续您从该点加载新消息的逻辑在...

$count = 0;
while(!feof($File)){
    $tmp = fgets($File);
    $count++;
}

相反,你这样做......

$count = 0;
while(!feof($File) || $count < $_SESSION['pos']){
    $tmp = fgets($File);
    $count++;
}

现在删除 fseek($File, $_SESSION['pos']) 部分,您的第二个循环应该在您期望的行开始。


文件格式

如果存储这些消息的文件旨在采用行分隔格式,文件中的每一行都代表一条消息(这似乎是您在代码中所做的假设)那么避免消息内容本身破坏您的文件的最安全方法是以不允许在消息有效负载中使用换行符的方式对消息内容进行编码。此类编码的示例包括 JSONBase64

后者会给您增加大约 33% 的存储成本,但对于行分隔的文件格式来说两者都是安全的。


Javascript

不清楚为什么您的 javascript 逻辑使用 currend 来确定它是否应该使用 setTimeout()。如果您希望全局循环每 10 秒不断检查新数据,您应该从全局范围调用一次 setInterval(GetNewMesssages, 10000) 而不是使用 setTimeout()有条件的。在您的代码中,如果当前消息是找到的最后一条消息的条件,您将不再从 js 再次调用 PHP 来检查新消息,这显然不是您想要的。 setTimeoutsetInterval 的区别在于 setTimeout 仅在定时器到达时触发 一次,而 setInterval 将在给定的时间间隔连续触发回调。

关于javascript - 如何使用 PHP 和 Ajax 实时读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34966932/

相关文章:

javascript - 访问没有命名元素的嵌套数组项

php - 检查从哪里访问页面

php - 数组获取下一个/上一个元素

Javascript jQuery 插件渲染问题

javascript - if else 语句可以生成变量吗?

javascript - 在 Eclipse 中,我在用私有(private)字段编写的类的 javascript 文件中出现错误

javascript - MVC 3 中带有 jQ​​uery 的低调 JavaScript

javascript - AngularJS 嵌套 ng-repeat 过滤多个参数

php - 从 mongo shell 获取 MongoBinData 值

javascript - 如何在鼠标移出或悬停停止时停止图像切换