将所有用户活动存储为会话值并在会话结束时保存会话值

时间:2011-11-26 08:35:26

标签: php events session event-handling

通常,我会通过在php中对每个页面加载执行查询来保存所有用户活动,页面视图和所有值。

  • 现在我正考虑将所有这些存储为会话值和 在会话结束时执行查询 。但是,我不知道如何在php中处理这个“会话结束”事件。

我考虑过一个后台进程,它会在会话超时之前存储所有会话值,但我对php中的多线程方法一无所知,尽管我听说过可能会有一些规避。

  • 我想确定用户是否在没有用户的情况下处于非活动状态 触发(如页面加载)并保存所有会话值 会话结束,超时之前。

这会在数据库引擎上节省一些工作量,方式如下: 用户查看许多页面,我增加会话中的值,而不是执行像

这样的查询
update pageviews set numberofviews=numberofviews+1
每页加载

  • 问题是:“如何在php中处理会话结束事件 没有用户活动?“

对实际问题的解决方案也表示赞赏。无论与粗体问题的相关性如何。 (我还没有开始编写代码,我的问题不是修复错误。)

可能的解决方案:

我找到了php session handler functioon但是文档没有说明它是否可以为回调参数设置空参数?

如果我为$ callback参数输入null参数,是否会丢失标准功能?

我只想更改session $ destroy事件。我现在需要这方面的帮助。

相关帖子: RP1

8 个答案:

答案 0 :(得分:3)

您无法真正使用session_destroy处理程序,因为只有在显式调用session_destroy时才会调用它,如果用户只是关闭浏览器并结束会话,则不会发生这种情况。由于在该场景中无法捕获会话“事件”的结束,因此您必须进行某种定期检查,以查看会话是否在给定的时间段内处于空闲状态。最简单的方法是在会话中创建一个保存最后访问时间的字段,然后定期创建一个脚本(通过cron或触发PHP脚本中的其他功能)检查所有活动会话的字段,以及对于时间戳大于xx秒的任何内容,请运行更新查询。

请注意,为了使用存储在文件系统上的标准PHP会话来执行此操作,您必须实际打开文件并直接解析它们。另一种方法是将会话存储在数据库中,但这可能不是您想要做的事情,因为您正在尝试减少数据库的负载。

另一种不太像开发密集型的可能性是:

  1. 向会话添加上次访问的时间戳
  2. 每次更新会话时检查时间戳
  3. 如果时间戳早于xx秒,则在数据库上运行更新查询,并将时间戳设置为当前时间。
  4. 这样你只是经常更新数据库而不是每次加载页面。当然,这种方法的缺点是,除非会话中的最后一个活动与调用更新函数的时间间隔完全对应,否则您可能无法在数据库中存储最新的会话信息。

答案 1 :(得分:2)

这不是创建会话的内容,因此单独使用会话机制无法实现您想要实现的目标。

使用标准PHP会话,您的选项有些限制,并且取决于会话存储:

  1. 默认情况下,会话存储在文件中。如果禁用会话垃圾回收,则可以运行一个cron作业,该作业将解析比您定义的时间早的会话文件。它并不完美,但到目前为止最简单。文件会话也很糟糕 - 写下每个请求。
  2. Memcached中的会话。没有很好的方法来获取早于x的记录,以及Memcached在过期时只丢弃数据这一事实可以在这里完成。
  3. 数据库中的会话 - 您已经对每个请求进行了更新。
  4. 因此,您对标准会话的选择最多也是有限的。我的建议:用您自己的标准会话替换标准会话,但这意味着您将不再通过$ _SESSION访问会话,并且需要您重写大量代码。

    我已将常规会话替换为在APC / Memcached和DB中存储会话数据的单例。会话数据仅在我请求它(Session::persistentStore($key,$value))时保存在DB中,或者如果在处理请求期间APC / Memcached存储的会话数据表明它没有写入足够长的时间。这极大地限制了写入次数。 通过这种替换,你只需要从数据库端强制进行会话保存:获取未从db更新x分钟的会话的会话ID,从APC / Memcached获取每个会话的信息以及如果没有更新信息那里要么(表示会话将很快结束)将其保存到db。

答案 2 :(得分:1)

这里只是一个疯狂的想法,你可以发起一个http请求来保存你的会话数据从javascript窗口卸载。问题是浏览器通常会在页面关闭后停止请求,因此此请求可能甚至无法访问服务器,但我认为值得进行测试。

答案 3 :(得分:1)

虽然有一些解决方法,但是您可以找到解决此问题的每个解决方案都比记录每个请求中的每个用户活动效率低。

答案 4 :(得分:1)

你想解决什么问题?我不明白为什么不会每次请求都会向数据库发出更新查询。它不应该花费比0,0001更长的时间。

我绝对会更新每个请求。它是一行代码,不会对数据库造成任何过多的负载,而且效率更高。

您提出的方法难以测试,会产生不必要的负载,甚至可能会创建全局状态。你可以通过传统的解决方案来防止这一切。在确定何时“结束”时,会话是(...)。

答案 5 :(得分:1)

  

我考虑过存储所有会话值的后台进程   就在会话超时之前,但我什么都不知道   php中的多线程方法,即使我听过一些   规避是可能的。

如果您非常轻松地使用基于数据库的会话,则可以执行此操作。

  1. 不需要多线程
  2. 写一个每分钟/ 5分钟运行一次的cron作业
    • 选择即将过期的所有记录
    • 将它们保存到其他表中
  3. 密钥是使用cron作业而不是尝试在http请求中途处理到期事件

答案 6 :(得分:1)

您正在谈论延迟统计信息写入和会话管理。我想,你真正的问题是避免每个http请求在数据库上写入查询。

可能对此类问题有用的一些提示:

  1. 请注意会话并行访问。我们通常认为会话只能由一个进程访问,但这是错误的,例如,您正在执行多文件上载,其中一些j向服务器打开几个ajax请求,每个进程使用相同的会话。使用浏览器在同一网站上打开10个标签时也是如此。
  2. 为每个请求添加更新查询重要的事情。选择查询很快,通常在SQL端使用某种缓存。更新查询很慢,可能正在重建索引,并且通常意味着在SQL服务器上进行一些缓存清理。如果您在数据库上使用不同的用户进行只读或读写访问,它们也可能意味着不同的SQL会话。
  3. 会话大小不应该太大,因为必须为每个请求加载会话,并且每次在会话中锁定机制(因为1)已设置,数据被推送到物理会话存储(默认情况下为文件)。因此,会话写入会减慢您的流程。
  4. NoSQl后端(如 MongoDb Reddit )可能是存储每个请求统计信息的好地方,它们拥有正确的工具来确保原子更新,锁定和可能比Relationnal数据库执行得更快(但您也可以检查关系数据库中的内存表性能)。因此,您可以使用这些工具来跟踪活动并通过将这些后端用作实时统计信息的主要目标来避免SQL更新。您可以异步从数据库的后端收集一些统计信息。现在会话是临时对象,而NoSQl后端也可能是好的会话存储(如果您编写自己的会话存储处理程序)。
  5. 编辑:并行使用的原子更新问题示例:执行查询请求增量 counter = counter +1 与读取计数器相同,递增计数器并执行更新查询 counter = mynewvalue 。当多个进程使用相同的数据时,第二个错误。

答案 7 :(得分:0)

有点偏离轨道,但你可以做自己的垃圾收集。

  • 使用PHP将会话保存在目录中,最好是tmpfs,禁用垃圾回收。

  • 编写一个定期的PHP脚本来查找超过20分钟的所有会话文件,打开它们,将它们写入数据库并删除它们。