使用PHP实现HTML5通知

28

我注意到Facebook开始在桌面上使用HTML5通知,于是我想为我的博客尝试玩一下。我的想法很简单:新的博客文章发布后,Apache cronjob每X分钟运行一次并调用一个文件,做一些PHP魔法然后进行通知发送。

我在网上找到了使用node.js和angular的示例,但我不太熟悉这两种技术,所以我宁愿使用PHP。

我的流程如下:用户进入我的博客并点击一个按钮来允许通知。为了简洁起见,下面的代码会在用户点击“通知”按钮时向他们发送通知。这个过程非常完美,理论上应该订阅他们以接收未来的通知。

if ('Notification' in window) {

function notifyUser() {
    var title = 'example title';
    var options = {
        body: 'example body',
        icon: 'example icon'
    };

    if (Notification.permission === "granted") {
        var notification = new Notification(title, options);
    } else if (Notification.permission !== 'denied') {
        Notification.requestPermission(function (permission) {
            if (permission === "granted") {
                var notification = new Notification(title, options);
            }
        });
    }

}

$('#notify').click(function() {
    notifyUser();
    return false;
});

} else {
    //not happening
}

您可以查看上述的示例代码

已经授予对用户的访问权限,现在我应该能够随时发送通知给他们。太棒了!然后我撰写了一篇博客文章,它的ID是XYZ。我的cronjob随后调用以下PHP脚本,使用上述node.js示例作为模板。

(在此示例中,我只是从手机手动调用脚本并观看桌面屏幕。由于我的桌面已经“订阅”了相同的域名,我认为以下内容会/应该起作用。)

$num = $_GET['num'];

$db = mysql_connect(DB_HOST, DB_USER, DB_PASS);
if($db) {
    mysql_select_db('mydb', $db);
    $select = "SELECT alert FROM blog WHERE id = ".$num." && alert = 0 LIMIT 1";
    $results = mysql_query($select) or die(mysql_error());
    $output = '';
    while($row = mysql_fetch_object($results)) { 

        $output .= "<script>

        var title = 'new blog!';
        var options = {
            body: 'come read my new blog!',
            icon: 'same icon as before or maybe a new one!'
        };

        var notification = new Notification(title, options);

        </script>";

      $update = "UPDATE blog SET alert = 1 WHERE id = ".$num." && alert = 0 LIMIT 1";
      mysql_query($update) or die(mysql_error());

    }

    echo $output;

}
我检查了数据库和博客条目XYZ的“alert”现在设置为“1”,但我的桌面浏览器从未收到通知。由于我的浏览器订阅了推送通知的相同URL,所以我想我应该会收到消息。
要么我做错了什么(也许PHP不是这个的正确语言?),要么我误解了规范。能否有人帮忙指点一下方向?我想我漏掉了什么。
非常感谢。
更新1
根据评论,如果我只是调用一个包含此内容的脚本:
 var title = 'new blog!';
 var options = {
    body: 'come read my new blog!',
    icon: 'same icon as before or maybe a new one!'
 };

  var notification = new Notification(title, options);

它应该触发所有已订阅我的通知的设备。我在手机上尝试过,但我的桌面仍未收到通知。我认为我还是缺少了某些东西,因为我的通知似乎只停留在一个设备上,并且只能在页面加载或单击时调用,而不像 Facebook 那样即使页面没有在浏览器中打开也会向您发送通知。


你需要通过JS重复获取提供的URL以捕获变化。你可以保持连接打开并进行长轮询或Comet,但对于低频更新(如新博客文章),这是过度的。 - dandavis
我不明白。如果我获取URL并发送通知,它会触达所有订阅用户吗?它似乎只发送有关设备的信息,而不是其他任何信息。 - Kenton de Jong
它会在他们重新加载页面或ajax php时生效。PHP没有内置的“订阅”功能,但有几种“推送”的方法。简单的RSS文件是低保真的方式,如果用户已订阅,通常会收到通知。 - dandavis
我尝试编写一个简单的脚本并通过手机调用它,但我的桌面仍然没有收到通知。我已经更新了我的问题。我认为我错过了什么,因为通知似乎只能通过点击或页面加载发送,而且似乎仅限于调用脚本的设备。 - Kenton de Jong
1个回答

17

你的问题在于缺少用于连接JavaScript和PHP的AJAX。你的PHP脚本是手动运行的,因此只有访问该脚本的设备才能看到通知。现在没有任何东西实际上将该信息发送到其他设备。

为了更好地解释这个问题,你的桌面可能已经允许访问通知,但它不会自动拉取这些通知。你提供的代码需要使用AJAX来访问脚本URL,而不是将其用作cron作业。

首先,你需要启动一个重复的请求来查看PHP脚本是否有更新的通知。如果有新的通知,则需要使用返回的响应创建一个新的通知对象。

其次,你需要修改PHP脚本,以输出JSON字符串而不是通知脚本。

JSON输出示例:

{
  {
    title: 'new blog!',
    options: {
      body: 'come read my new blog!',
      icon: 'same icon as before or maybe a new one!'
    }
  },
  {
    title: 'another blog item!',
    options: {
      body: 'come read my second blog!',
      icon: 'hooray for icons!'
    }
  }
}

你的notifyUsers()函数应该将titleoption作为参数传递,而不是硬编码它们:

你的notifyUsers()应该以titleoption作为参数,而不是在函数内直接写死它们:

function notifyUser(title, options) { ... }
使用jQuery获取PHP响应并创建通知:
function checkNotifications(){
  $.get( "/path/to/script.php", function( data ) {
    // data is the returned response, let's parse the JSON string
    json = JSON.parse(data);

    // check if any items were returned
    if(!$.isEmptyObject(json)){
      // send each item to the notify function
      for(var i in json){
        notifyUser(json[i].title, json[i].options);
      }
    }
  });

  setTimeout(checkNotifications, 60000); // call once per minute
}

现在,你只需要启动 AJAX 轮询,所以将以下内容添加到你的网页中:

$(document).ready(checkNotifications);

就是这样了!你只是漏掉了桌面需要拉取通知的这一部分。不过要注意,这没有经过测试,你可能需要调整一些东西。


有一个JS Push API可以设置浏览器Service Worker,但它仅在Chrome 42.0(包括移动版)和Firefox 44.0(不包括移动版)中受支持,并且尚不可能实现跨浏览器支持。这将通过允许浏览器处理工作来消除重复的AJAX请求。请查看:http://w3c.github.io/push-api/ - Siphon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接