草庐IT

debugging - PHP Redis session 不保存

coder 2023-07-18 原文

编辑 我尝试用 xdebug 和 netbeans 调试它。如果我放置一些断点,导出将在调试 session 期间工作,这很奇怪。但是,在没有断点的情况下,更现实的环境中,导出不起作用。

我已经尝试将 sleep 添加到代码的某些部分。

我认为也许 PHP 在 Redis 提交完成之前就结束了。也许 Redis 连接是异步完成的,但我检查了 PRedis,默认是同步连接。


我正在开发一个报告工具。

这是基本问题。

我们将报告存储到 session 对象中,但在稍后的请求中,当我们尝试获取 session 对象中的报告时,它已经消失了。

这里有一个更详细的版本。

我像这样将“报告”对象存储到 session 中

  $_SESSION['report_name_unixtimestamp'] = gzcompress( serialize( $reportObject ) );

用户以某种表格形式查看报告,然后如果他们愿意,可以将其导出。报告可能会发生变化,因此将其存储在 session 中的想法是,当用户将其导出为 PDF、Excel 等格式时,他们将获得与他们正在查看的报告相同的报告。

用户单击导出按钮,在 PHP 端它将进入 session ,通过作为 get 参数提供的 key 获取报告(解压缩和反序列化),创建导出并将其发送给用户以供下载。

在我们尝试引入 Redis 缓存服务器作为更好的 session 管理工具之前,它一直运行良好。

现在发生的事情如下:

我们第一次运行报告时,它会被存储到缓存中并且导出会成功。

我们将在同一 session 中使用同一用户帐户再次运行报告。这会更改 unixtimestamp,因此 $_SESSION 中应该有两个条目。 ($_SESSION['report_name_oldertimetamp']$_SESSION['report_name_newertimestamp'])。当我们再次点击导出按钮时,我们收到一条错误消息,提示该文件不存在(因为服务器尚未发送)。

如果我们检查 redis 服务器是否有更新版本的报告,它不存在,但旧的时间戳仍然存在。

现在,这适用于文件 session 管理,但不适用于 Redis。我们已经尝试过 php 的 redis 模块以及纯 php 客户端 Predis。

有没有人有什么想法?

这里有一些更多的细节:

  1. Redis 没有耗尽内存。我们已经检查过很多次了。
  2. 我们已经知道要在 session 中反序列化报告对象,必须已经包含报告类。 (请记住,第一次导出工作正常,但之后的任何操作都失败了)
  3. 如果我们在运行报告的请求期间检查 php session 对象,它将包含较新的报告,但它永远不会到达 Redis。

下面是与 Predis 一起使用的保存处理程序。 redis_session_init 是我在 session_start() 之前调用的函数,以便它被注册。我不确定 redis_session_write 函数是如何工作的,所以也许有人可以帮助我。

    <?php
    namespace RedisSession
    {

        $redisTargetPrefix = "PHPREDIS_SESSION:";
        $unpackItems = array( );
        $redisServer = "tcp://cache.emcweb.com";

        function redis_session_init( $unpack = null, $server = null, $prefix = null )
        {
            global $unpackItems, $redisServer, $redisTargetPrefix;

            if( $unpack !== null )
            {
                $unpackItems = $unpack;
            }

            if( $server !== null )
            {
                $redisServer = $server;
            }

            if( $prefix !== null )
            {
                $redisTargetPrefix = $prefix;
            }

            session_set_save_handler( 'RedisSession\redis_session_open', 'RedisSession\redis_session_close', 'RedisSession\redis_session_read', 'RedisSession\redis_session_write', 'RedisSession\redis_session_destroy', 'RedisSession\redis_session_gc' );
        }

        function redis_session_read( $id )
        {
            global $redisServer, $redisTargetPrefix;

            $redisConnection = new \Predis\Client( $redisServer );
            return base64_decode( $redisConnection->get( $redisTargetPrefix . $id ) );
        }

        function redis_session_write( $id, $data )
        {
            global $unpackItems, $redisServer, $redisTargetPrefix;

            $redisConnection = new \Predis\Client( $redisServer );
            $ttl = ini_get( "session.gc_maxlifetime" );

            $redisConnection->pipeline( function ($r) use (&$id, &$data, &$redisTargetPrefix, &$ttl, &$unpackItems)
        {
            $r->setex( $redisTargetPrefix . $id, $ttl, base64_encode( $data ) );

            foreach( $unpackItems as $item )
            {
                $keyname = $redisTargetPrefix . $id . ":" . $item;

                if( isset( $_SESSION[ $item ] ) )
                {
                    $r->setex( $keyname, $ttl, $_SESSION[ $item ] );
                }
                else
                {
                    $r->del( $keyname );
                }
            }
        } );
        }

        function redis_session_destroy( $id )
        {
            global $redisServer, $redisTargetPrefix;

            $redisConnection = new \Predis\Client( $redisServer );
            $redisConnection->del( $redisTargetPrefix . $id );

            $unpacked = $redisConnection->keys( $redisTargetPrefix . $id . ":*" );

            foreach( $unpacked as $unp )
            {
                $redisConnection->del( $unp );
            }
        }

        // These functions are all noops for various reasons... opening has no practical meaning in
        // terms of non-shared Redis connections, the same for closing. Garbage collection is handled by
        // Redis anyway.
        function redis_session_open( $path, $name )
        {

        }

        function redis_session_close()
        {

        }

        function redis_session_gc( $age )
        {



        }
    }

最佳答案

问题解决了,比我想象的要笨得多。

保存处理程序不以任何方式实现锁定。在报告页面上,有多个请求通过 ajax 等方式向服务器发出。 ajax 请求之一在报告保存到 session 空间之前启动。因此,它读取 session ,然后在最后写入 session 。

由于报告每次都执行得更快,报告将被缓存到 Redis 中的 session 中,但随后会被具有旧版本 sessien 的其他脚本覆盖。

我得到了一位同事的帮助。啊!这是一个令人头疼的问题,我很高兴结束了。

关于debugging - PHP Redis session 不保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8619648/

有关debugging - PHP Redis session 不保存的更多相关文章

  1. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  2. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

  3. ruby-on-rails - Rails 3.2 防止使用错误保存对象 - 2

    我有一个ActiveRecord对象,我想在不对模型进行永久验证的情况下阻止它被保存。您过去可以使用errors.add执行类似的操作,但它看起来不再有效了。user=User.lastuser.errors.add:name,"namedoesn'trhymewithorange"user.valid?#=>trueuser.save#=>true或user=User.lastuser.errors.add:base,"myuniqueerror"user.valid?#=>trueuser.save#=>true如何在不修改用户对象模型的情况下防止将用户对象保存在Rails3.2中

  4. ruby-on-rails - 将保存回调添加到单个 ActiveRecord 实例,可以吗? - 2

    是否可以为单个ActiveRecord实例添加回调?作为进一步的限制,这是继续使用库,所以我无法控制该类(除了对其进行猴子修补)。这或多或少是我想做的:defdo_something_creazymessage=Message.newmessage.on_save_call:do_even_more_crazy_stuffenddefdo_even_more_crazy_stuff(message)puts"Message#{message}hasbeensaved!Hallelujah!"end 最佳答案 你可以通过在创建对象后立

  5. ruby - 正则表达式 - 保存重复捕获的组 - 2

    这就是我做的a="%span.rockets#diamonds.ribbons.forever"a=a.match(/(^\%\w+)([\.|\#]\w+)+/)putsa.inspect这是我得到的#这就是我想要的#帮助?我尝试过但失败了:( 最佳答案 通常,您不能获得任意数量的捕获组,但如果您使用扫描,您可以为您想要捕获的每个标记获得一个匹配:a="%span.rockets#diamonds.ribbons.forever"a=a.scan(/^%\w+|\G[.|#]\w+/)putsa.inspect["%span","

  6. ruby-on-rails - ActiveRecord:除非另有说明,否则在保存之前使所有文本字段都调用 strip - 2

    多年来,我在各种网站上遇到过各种问题,用户在字符串和文本字段的开头/结尾放置空格。有时这些会导致格式/布局问题,有时会导致搜索问题(即搜索顺序看起来不对,但实际上并非如此),有时它们实际上会使应用程序崩溃。我认为这会很有用,而不是像我过去所做的那样放入一堆before_save回调,向ActiveRecord添加一些功能以在保存之前自动调用任何字符串/文本字段上的.strip,除非我告诉它不是,例如do_not_strip:field_x,:field_y或类定义顶部的类似内容。在我去弄清楚如何做到这一点之前,有没有人看到更好的解决方案?明确一点,我已经知道我可以做到这一点:befor

  7. ruby-on-rails - 如何用 has_many 保存数据 :through - 2

    我在游戏和帐户模型之间存在多对多关系,如下所示:classAccount:destroyhas_many:games,:through=>:account_gamesendclassGame:destroyhas_many:accounts,:through=>:account_gamesendclassAccountGame现在我知道让我们说我想创建一个类似这样的记录:@account=Account.new(params[:user])@account.games但是我应该如何在执行此操作时更新AccountGame中的某些属性?假设AccountGame有一些名为score的字段

  8. ruby - 无法加载此类文件——脚本/rails : Getting this error while remote debugging through RubyMine - 2

    我在通过RubyMineIDE进行远程调试时遇到以下错误。$bundleexecrdebug-ide--port1234--script/railsserverFastDebugger(ruby-debug-ide0.4.9)listenson:1234/home/amit/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-ide19-0.4.12/lib/ruby-debug-ide.rb:123:in`debug_load'/home/amit/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-ide19-0.4.

  9. ruby - 在 tensorflow.rb 上运行保存的模型 - 2

    我使用高级EstimatorAPI(DNNClassifier)在Python中构建并保存了一个非常简单的模型。它需要2个float并输出两个类之一。我正在尝试使用tensorflow.rbgem在Ruby中加载它,并用它做出预测。这应该很相似totheCAPTCHAexampleprovidedbytensorflow.rb.我使用export_saved_model保存了它。这是训练模型的Python代码。它可以正确地预测类别。将numpy导入为np将Pandas导入为pd将tensorflow导入为tfdataframe=pd.read_csv("remediations_imp

  10. css - 检测到 Sass 更改但 style.css 仅在我保存时每 5 到 7 次被覆盖 - 2

    我在一台Windows764位机器上使用Sass和Ruby(最新版本),我正在我的家庭服务器上处理一个共享文件夹。(但是,我不得不承认问题本身也出现在服务器上,因为我试图安装Ruby并直接-watch服务器上的文件)。问题如下:如果我第一次保存,检测到变化,我的style.css被直接覆盖。之后,我总是需要保存多达7次才能覆盖style.css。每次都会检测到更改,但不会编译任何内容。这是一个屏幕:>>>Sassiswatchingforchanges.PressCtrl-Ctostop.overwritestyle.css>>>Changedetectedto:E:/Websites

随机推荐