0

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

我有这个来自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 / )

索引.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>

发送_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";
}

但是,当我添加任何新内容时,它只是 echo 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>

更新:尝试使用委托()

    <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>
4

3 回答 3

2

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

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

我之前已经发布了另一个带有示例的答案

我列出了几种运输方式。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";
?>

所以你只需要那 2 页。

更新:

我只看到你的评论而不是更新..对不起;)

如果你使用.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
        });
    }
  };
于 2012-09-17T13:54:17.313 回答
0

您可以计算表中的行数,然后检查行数是否更改。

于 2012-09-17T13:56:14.257 回答
0

在没有深入研究您的代码的情况下,我回答了标题中的问题:

将最后修改的列添加到您的表中,这有一个内置的 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 占位符)

于 2012-09-19T10:49:52.187 回答