【问题标题】:filemtime alternative for MySQLMySQL的filemtime替代品
【发布时间】:2012-09-09 18:03:55
【问题描述】:

我正在玩一些推送通知,并且想在数据库发生变化时更新页面。

我有这个来自http://www.screenr.com/SNH

<?php
$filename = dirname(__FILE__).'/data.php';

$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);

while ($currentmodif <= $lastmodif) {
  usleep(10000);
  clearstatcache();
  $currentmodif = filemtime($filename);
}

$response = array();
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
?>

我的 data.php 是一个从 JSON 文件中获取数据的脚本:

<script>function itnews_overview() {
    $.getJSON('/ajax.php?type=itnews_overview', function(data) {
        $.each(data.data, function(option, type) {
            $('.bjqs').append('<li><span class="date">'+ type.submitted +'<br />'+     type.time +'</span><h2>' + type.title + '</h2><p>' + type.content + '</p></li>');
        });

    });

}
</script>

<script>
  itnews_overview();
</script>
<div id="news">
  <ul class="bjqs"></ul>
</div>

更新:来自 index.php 的代码:

<script type="text/javascript">

  var timestamp = null;

  function waitForMsg() {
$.ajax({
  type: "GET",
  url: "getData.php?timestamp=" + timestamp,
  async: true,
  cache: false,

  success: function(data) {
    var json = eval('(' + data + ')');
    if(json['msg'] != "") {
      $(".news").html(json['msg']);

    }


    timestamp = json['timestamp'];
    setTimeout('waitForMsg()',1000);        
  },

  error: function(XMLHttpRequest, textStatus, errorThrown){
    setTimeout('waitForMsg()',15000);
  }

});
  }

  $(document).ready(function(){
  waitForMsg();
});

</script>

由于当我向数据库添加内容时此文件未保存,所以 filemtime 将不起作用 — 是否有其他方法可以检查新行是否已添加到表中?

更新: 尝试使用 SSE 解决此问题。 我有两个文件,index.php 和 send_sse.php(灵感来自http://www.developerdrive.com/2012/03/pushing-updates-to-the-web-page-with-html5-server-sent-events/

index.php:

<div id="serverData">Content</div>
<script type="text/javascript">
//check for browser support
if(typeof(EventSource)!=="undefined") {
    //create an object, passing it the name and location of the server side script
    var eSource = new EventSource("send_sse.php");
    //detect message receipt
    eSource.onmessage = function(event) {
        //write the received data to the page
        document.getElementById("serverData").innerHTML = event.data;
    };
}
else {
    document.getElementById("serverData").innerHTML="Whoops! Your browser doesn't receive server-sent events.";
}
</script>

send_sse.php:

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$url = "content.json";
$str = file_get_contents($url);
$data = json_decode($str, TRUE);
//generate random number for demonstration
//echo the new number
echo "data: " . json_encode($data);


ob_flush();
?>

但是,这似乎不起作用,这可能是因为 SSE 需要纯文本数据。我只是不知道如何做到这一点,然后将该内容包装在几个 HTML 标记中。

更新:好的,现在它可以与 SSE 合作了,这要感谢 VDP。我有以下内容:

$sql= "SELECT title, content, submitted FROM `flex_itnews` where valid = 1 order by submitted desc";
$query= mysql_query($sql);
setlocale(LC_ALL, 'da_DK');
while($result = mysql_fetch_array($query)){
    echo "data: <li><span class='date'>". strftime('%e. %B', strtotime($result['submitted'])) ."<br />kl. ". strftime('%H.%M', strtotime($result['submitted'])) ."</span><h2>" . $result['title']. "</h2><p>" . $result['content'] ."</p></li>\n";
}

但是,当我添加任何新内容时,它只会回显data: data: data。如果我刷新页面,它会正确显示。

更新:使用 livequery 插件:

    <script>
      var source = new EventSource('data2.php');
      source.onmessage = function (event) {
        $('.bjqs').html(event.data);
      };

      $('#news').livequery(function(){
        $(this).bjqs({
          'animation' : 'slide',
          'showMarkers' : false,
          'showControls' : false,
          'rotationSpeed': 100,
          'width' : 1800,
          'height' : 160
        });
      });

  </script>

更新:尝试使用delegate()

    <script>
      $("body").delegate(".news", "click", function(){
        $("#news").bjqs({
          'animation' : 'slide',
          'showMarkers' : false,
          'showControls' : false,
          'rotationSpeed': 100,
          'width' : 1800,
          'height' : 160
        });
                var source = new EventSource('data2.php');
      source.onmessage = function (event) {
        $('.bjqs').append(event.data);
      };
      });
  </script>

【问题讨论】:

标签: php mysql push-notification


【解决方案1】:

是的!有多种(更好的)方法:

  1. websocket(最好的解决方案,但不支持旧版或移动浏览器)
  2. 服务器发送事件 (SSE)(类似于轮询,但仅针对您要求的任务进行了优化)
  3. 长轮询(就像你正在做的那样)
  4. 闪光灯插座
  5. 其他基于插件的套接字内容
  6. ajax 轮询

我之前在another answer 上发布过相关示例

我列出了几种运输方式。 websockets 是理想的(因为它是服务器和客户端之间唯一的双向通信),SSE 是我的第二选择。您将不需要 $.getJSON 方法。总体思路是一样的。

在服务器端(在您的情况下为 php)您查询数据库以进行更改。您将数据作为 JSON 返回(json_encode(data) 可以做到这一点)。在客户端,您解码 JSON(JSON.parse(data) 可以做到这一点)。使用您收到的数据更新您的页面。

只是像你这样的轮询会导致更多开销,因为你正在向服务器发出大量请求。

SSE 更多的是“我想订阅流”和“我想停止收听”。 => 更少的开销

Websockets 更多:“我建立了一个连接。我谈服务器监听。服务器谈客户端监听”全双工连接。 => 最少的开销

SSE 代码示例

客户端访问的页面(例如 index.html 或 index.php)

这只是一个包含此 javascript 的普通 html 页面:

<html>
<head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <script>
        //javascript:
        var source = new EventSource('data.php');
        source.onmessage = function (event) {
            //here you do the stuff with the received messages.
            //like log it to the console
            console.log(event.data);
            //or append it to div
            $('#response').append(event.data);
        };
    </script>
</head>
<body>
    <div id="response"></div>
</body>
</html>

“data.php”页面:

<?php
/* set the header first, don't echo/print anything before this header is set! Else the default headers will be set first then this line tries to set the headers and results in an error because the header is already set. */
header("Content-Type: text/event-stream\n\n");

//query the database
$sql= "SELECT COUNT(*) FROM `messages`";
$query= mysql_query($sql);
$result = mysql_fetch_array($query);
$count = $result[0];

//return the data
echo "data: " . $count. "\n";
?>

所以你只需要这两页。

更新:

我只看到了你的 cmets 而不是更新.. 抱歉 ;)

如果您使用.delegate(),则不应使用body,而是尝试使用尽可能高的选择器(在您的情况下为.bjqs)。

在您的情况下,您甚至不需要直播、代理或所有这些!只需在内容更新后再次应用 bjqs。

  var source = new EventSource('data2.php');
  source.onmessage = function (event) {
    $('.bjqs').html(event.data);
    $("#news").bjqs({
      'animation' : 'slide',
      'showMarkers' : false,
      'showControls' : false,
      'rotationSpeed': 100,
      'width' : 1800,
      'height' : 160
    });
  };

这也会给您带来问题,因为您不断地重新初始化 bjqs,并且它不是为处理动态更新内容而编写的。 如果有新数据,您可以只发送数据(使用 php)。检查调用是否返回空,如果没有更新:

  var source = new EventSource('data2.php');
  source.onmessage = function (event) {
    if(event.data !=""){
        $('.bjqs').html(event.data);
        $("#news").bjqs({
          'animation' : 'slide',
          'showMarkers' : false,
          'showControls' : false,
          'rotationSpeed': 100,
          'width' : 1800,
          'height' : 160
        });
    }
  };

【讨论】:

  • 好的,所以我实际上根本不需要上面的第一个代码?我不确定我是否理解您其他评论中的示例。我还需要让我的 data.php 文件获取 JSON 吗?
  • 现在我有四个文件:index.php,我在其中显示了实际数据(添加了上面的一些代码)。 getData.php,上面的代码块 #2,我在其中检查 data.php 是否有更改。 data.php,上面的代码块 #1,我从 ajax.php 获取 JSON 输出,ajax.php 是从数据库获取内容的动态文件。我什至需要所有这些文件吗?
  • 我猜这 4 个文件让事情变得有点复杂,但对于长轮询工作来说是必要的。另一个值得关注的好库是:github.com/flowersinthesand/jquery-socket 通过简单的实现为您利用正确的传输方法
  • 我尝试查看 SSE,但使用 MySQL 数据库中的 JSON 数据实现它似乎有点困难。我已经用我的新代码更新了帖子。
  • 我将在我的答案中添加 SSE 的代码示例。我会尽量说清楚;)
【解决方案2】:

我没有过多地研究你的代码,我回答了标题中的问题:

将最后修改的列添加到您的表中,这有一个内置的 mysql 触发器,该触发器会在添加或更改行时更新:

ALTER TABLE `yourTable`
    ADD COLUMN `last_modified` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ADD INDEX (`last_modified`);

然后像这样查询它,

SELECT * FROM yourTable where last_modified > ?

("?" 是你用上次查询的时间戳替换的 pdo 占位符)

【讨论】:

  • 啊,这是个好主意。如何获取上次查询的时间戳?
  • 这是您在 ajax 中作为参数 getData.php?timestamp=" + timestamp 提供的内容,并在获取数据时更新时间戳
【解决方案3】:

您可以统计表格中的行数,然后检查行数是否发生变化。

【讨论】:

  • 是的,但我怎样才能不断地做到这一点并推动它?
猜你喜欢
  • 2010-09-24
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
相关资源
最近更新 更多