[PHP-users 11348] Re: セッションについて

WADA Masashi php-users@php.gr.jp
Thu, 07 Nov 2002 18:53:06 +0900


 和田です。

>hoge.phpが動作している間、cancel.phpは実行されません。
>hoge.phpの動作を中断させる方法を教えて頂けないでしょうか?

 matsu さんのスクリプトを次のように修正したら、中断が実現できま
した。

--- main.php ---------------------------------------------------------
<?php

    session_start();
    $id = session_id();
    $_SESSION["status"] = "";

    print <<<_END_OF_VALUE_
<html>
<head>
<script language="JavaScript">
<!--
function Exec() {
    window.open(
        "cancel.php",
        "cancel",
        'location=no, toolbar=no, menubar=no, status=no, '
            + 'directories=no, scrollbars=no, resizable=no, '
            + 'width=400, height=300'
    );
    setTimeout("document.a.submit()", 1000);
}
//-->
</script>
</head>
<body>
  <form name="a" action="hoge.php" method="post">
    <input type="button" value="exec" onclick="Exec()">
  </form>
  SESSION ID: $id<br>
</body>
</html>
_END_OF_VALUE_;

?>
----------------------------------------------------------------------

--- hoge.php ---------------------------------------------------------
<?php

    $msg = "";
    $timeoffset = time() + 20;
    while(time() < $timeoffset)
    {
        session_start();
        $id = session_id();

        if($_SESSION["status"] == "cancel") {
            $msg .= "canceled.<br>";
            break;
        }
        session_write_close();
        sleep(1);
    }
    $msg .= "end.<br>";

    print <<<_END_OF_VALUE_
<html>
<head></head>
<body>
    $msg<br>
    SESSION ID: $id<br>
</body>
</html>
_END_OF_VALUE_;

?>
----------------------------------------------------------------------

--- cancel.php -------------------------------------------------------
<?php

    session_start();
    $id = session_id();

    $msg = "";
    if ($_POST["cmd"] == "exec_cancel") {
        $_SESSION["status"] = "cancel";
        $msg .= "canceled.";
    }

    print <<<_END_OF_VALUE_
<html>
<head></head>
<body>
  <form name="a" action="cancel.php" method="post">
    <input type="submit" value="cancel">
    <input type="hidden" name="cmd" value="exec_cancel">
  </form>
  $msg<br>
  SESSION ID: $id<br>
</body>
</html>
_END_OF_VALUE_;

?>
----------------------------------------------------------------------

このスクリプトの動作内容は次のとおりです。

 (1).ブラウザで main.php にアクセス
 (2).exec ボタンを押す。
    → cancel 用のウィンドウが開く
    → 元のウィンドウは hoge.php にアクセスする
     (しかし hoge.php は 20 秒後にレスポンスを返す)
 (3).cancel 用のウィンドウで cancel ボタンを押す
    → セッション変数 status に"cancel"がセットされる
 (4).hoge.php でセッション変数 status を監視しており、"cancel"
   がセットされたら、20秒が経過していなくてもその時点でレス
   ポンスを返す。

今回の問題では(4)にポイントがあります。まず、PHPマニュアルの
session_write_close() を参照してください。

 >セッションデータは、同時書き込みを防ぐためにロックされるため、
 >ある時点であるセッションの処理ができるスクリプトは、1つだけです。

とあります。matsu さんのスクリプト hoge.php の

    >------- hoge.php---------
    >$timeoffset = time() + 20;
    >while(time() < $timeoffset)
    >{
    >   if($_SESSION["hoge"] == "1")
    >      break;
    >}

この 20 秒の while ループでは、セッションデータがロックされ続け
ているため、cancel.php では session_start() で、hoge.php 側のセッ
ションデータの解放を待ちつづけることになります。
 なので、hoge.php のループ内で、$_SESSION["hoge"] を監視しても
意味がありません。そこで次のように hoge.php を変更してみたわけで
す。

    >$timeoffset = time() + 20;
    >while(time() < $timeoffset)
    >{
    >   session_start();
    >   $id = session_id();
    >
    >   if($_SESSION["status"] == "cancel") {
    >       $msg .= "canceled.<br>";
    >       break;
    >   }
    >   session_write_close();
    >   sleep(1);
    >}
    >$msg .= "end.<br>";

ループの内部で、セッションを開始(session_start)し、セッション変
数 status の値が変化していないか確認した直後に、セッションを終了
(session_write_close)させています。これで、cancel.php 側でセッショ
ンを開始できる隙間を空けてあげるわけです。
(なお、システムに高負荷を与えないよう、1秒おきにチェックしてい
ます。)

 ・・・しかし、このようなセッション関数の利用方法を、私は今まで
に経験したことがありません。何かとんでもない問題が発生するかもし
れません。

----
和田雅志 (WADA Masashi)
wada@hh.iij4u.or.jp