24

このページの冒頭で使用する長いポーリングを行うページが1つあります。

session_start();
session_write_close();

なぜなら :

同時書き込みを防ぐために、セッションで操作できるスクリプトは常に1つだけです。

したがって、私がそうせず、長いポーリングが実行されている場合、ユーザーは別のページをロードできません。

したがって、このポーリングページからセッション中のデータにアクセスすることは可能ですが、スクリプトのある時点で、セッションに変更を加えたため、セッションをサーバーに保存する必要があります。

それを行う方法は何ですか?

それはとてもいいでしょうそれは次のようなことをする方法になるでしょう

session_write_open();
//do stuff
session_write_close();

しかし、session_write_open()は存在しません!

ありがとう

4

5 に答える 5

22

セッションに何らかの変更を加えるsession_startに、もう一度呼び出してください。変更を加えても、通話を終了したくない場合は、session_write_closeもう一度呼び出します。これは何度でも行うことができます。

于 2012-04-06T16:57:51.503 に答える
12

前のソリューションでは、セッション ID と Cookie が作成されます。そのままでは使用しません。

session_start() を呼び出すたびにセッションが作成されます。複数の Cookie を回避したい場合は、より適切なコードを記述してください。特に同じスクリプト内の同じ名前に対して複数の session_start() は、本当に悪い考えのようです。

ここを参照してください: https://bugs.php.net/bug.php?id=38104

私も今解決策を探していますが、見つかりません。これは「バグ」だと言う人に同意します。PHPセッションを再開できるはずですが、あなたが言ったようにsession_write_open()存在しません...

上記のスレッドで回避策を見つけました。リクエストを処理した後、セッション ID の Cookie を手動で指定するヘッダーを送信する必要があります。幸いなことに、サブコントローラーが単独でデータを送信しないように機能する自作のフロント コントローラーを使用しています。一言で言えば、私の場合は完璧に機能します。ob_start()これを使用するには、 andを使用する必要があるかもしれませんob_get_clean()。魔法のラインは次のとおりです。

if (SID) header('Set-Cookie: '.SID.'; path=/', true);

編集:以下のCMCDragonkaiの回答を参照してください。

于 2012-12-05T14:56:23.213 に答える
8

ここでのすべての回答は、明らかに使用することを意図していない方法でセッションメソッドを使用するように言っているようです...つまり、session_start()複数回呼び出します。

PHP の Web サイトには、既存のセッションと同じように機能するがファイルをロックしない、SessionHandlerInterface の実装例が用意されています。サンプルインターフェイスを実装するだけで、ロックの問題が修正され、変数をセッションに追加する機能を制限することなく、同じセッションで同時接続が可能になりました。アプリのセッションは完全にステートレスではないため、いくつかの競合状態を防ぐために、リクエストの途中でセッションを閉じずに保存する方法を作成する必要がありました。これにより、重要な変更は変更直後に保存され、重要でないセッション変数は保存されます。リクエストの最後に。使用法については、以下の例を参照してください。

Session::start();
echo("<pre>Vars Stored in Session Were:\n");print_r($_SESSION);echo("</pre>");

$_SESSION['one']    = 'one';
$_SESSION['two']    = 'two';
//save won't close session and subsequent request will show 'three'
Session::save(); 
$_SESSION['three']  = 'three';

Session::start()これをとに置き換えるとsession_start()、後続のリクエストで 3 番目の変数が出力されないことがわかります... 失われます。ただし、SessionHandler (以下) を使用すると、データが失われることはありません。Session::save()session_write_close()

OOP の実装には、PHP 5.4+ が必要です。ただし、古いバージョンの PHP では個別のコールバック メソッドを提供できます。ドキュメントを参照してください

namespace {
    class Session implements SessionHandlerInterface {
        /** @var Session */
        private static $_instance;
        private $savePath;

        public static function start() {
            if( empty(self::$_instance) ) {
                self::$_instance = new self();
                session_set_save_handler(self::$_instance,true);
                session_start();
            }
        }
        public static function save() {
            if( empty(self::$_instance) ) {
                throw new \Exception("You cannot save a session before starting the session");
            }
            self::$_instance->write(session_id(),session_encode());
        }
        public function open($savePath, $sessionName) {
            $this->savePath = $savePath;
            if (!is_dir($this->savePath)) {
                mkdir($this->savePath, 0777);
            }

            return true;
        }
        public function close() {
            return true;
        }
        public function read($id) {
            return (string)@file_get_contents("$this->savePath/sess_$id");
        }
        public function write($id, $data) {
            return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
        }
        public function destroy($id) {
            $file = "$this->savePath/sess_$id";
            if (file_exists($file)) {
                unlink($file);
            }

            return true;
        }
        public function gc($maxlifetime) {
            foreach (glob("$this->savePath/sess_*") as $file) {
                if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
                    unlink($file);
                }
            }

            return true;
        }
    }
于 2015-01-16T22:22:42.953 に答える
8

ここでの他の回答は、かなり良い解決策を示しています。@Jon が述べたように、秘訣は、変更を加える前に session_start() を再度呼び出すことです。次に、変更が完了したら、session_write_close() を再度呼び出します。

@Armel Larcier が述べたように、これに関する問題は、PHP が新しいヘッダーを生成しようとし、警告を生成する可能性があることです (たとえば、ヘッダー以外のデータを既にクライアントに書き込んでいる場合)。もちろん、session_start() の前に「@」を付けることもできますが (@session_start())、もっと良い方法があります。

@VolkerK によって提供された別のスタック オーバーフローの質問は、最良の答えを明らかにします。

session_start(); // first session_start
...
session_write_close();
...

ini_set('session.use_only_cookies', false);
ini_set('session.use_cookies', false);
//ini_set('session.use_trans_sid', false); //May be necessary in some situations
ini_set('session.cache_limiter', null);
session_start(); // second session_start

これにより、PHP がヘッダーを再度送信しようとするのを防ぎます。これをもう少し便利にするために、ini_set() 関数をラップするヘルパー関数を作成することもできます。

function session_reopen() {
    ini_set('session.use_only_cookies', false);
    ini_set('session.use_cookies', false);
    //ini_set('session.use_trans_sid', false); //May be necessary in some situations
    ini_set('session.cache_limiter', null);
    session_start(); //Reopen the (previously closed) session for writing.
}

元の関連 SO 質問/回答: https://stackoverflow.com/a/12315542/114558

于 2013-06-18T20:11:52.237 に答える
4

Armel Larcier の回避策をテストした後。この問題に対する私の提案された解決策は次のとおりです。

    ob_start();

    session_start();
    session_write_close();

    session_start();
    session_write_close();

    session_start();
    session_write_close();

    session_start();
    session_write_close();

    if(SID){

        $headers =  array_unique(headers_list());   

        $cookie_strings = array();

        foreach($headers as $header){
            if(preg_match('/^Set-Cookie: (.+)/', $header, $matches)){
                $cookie_strings[] = $matches[1];
            }
        }

        header_remove('Set-Cookie');

        foreach($cookie_strings as $cookie){
            header('Set-Cookie: ' . $cookie, false);
        }

    }

    ob_flush();

これにより、セッションを操作する前に作成されたすべての Cookie が保持されます。

ところで、上記のコードを register_shutdown_function の関数として登録したい場合があります。関数の前に ob_start() を実行し、関数内で ob_flush() を実行してください。

于 2013-05-15T23:23:30.303 に答える