web-dev-qa-db-ja.com

PHP-タブごとのセッション

ブラウザのタブごとにセッションを作成することは可能ですか?

例として、ユーザーがブラウザで2つのタブを開いた場合:Tab 1およびTab 2

Tab 1で彼はセッションを持っています:

$_SESSION['xxx'] = 'lorem';

そしてTab 2のセッションは:

$_SESSION['xxx'] = 'ipsum';

次に、更新時にアクティブなタブで現在のセッションを取得する必要があります。たとえば、ユーザーがタブ2を更新した場合、「ipsum」であるロード時にタブ2の$_SESSION['xxx']を取得する必要があります。ただし、$_SESSION['xxx']はタブ1で変更しないでください。

タブごとにセッションを保存するオプションはありますか?そうでない場合、この問題を処理する他のオプションは何ですか?

助けてくれてありがとう!

11
lhuber

PHPはセッションIDをCookieに保存し、Cookieはタブではなくクライアント(ブラウザ)ごとに存在します。したがって、これを行う簡単で簡単な方法はありません。独自のセッションハンドラーを作成してこれを行う方法はいくつかありますが、それらはソリューションよりもハックであり、そのため、独自のリスクと複雑さを伴います。これが必要になる理由が何であれ、セッション分割よりも優れたアーキテクチャソリューションがあると確信しています。

13
Auris

私はこの問題の答えをWebで調べてきましたが、満足のいく解決策はまだ見つかりませんでした。私はようやくJavaScriptで一種の作品をまとめました。

_//generate a random ID, doesn't really matter how    
if(!sessionStorage.tab) {
    var max = 99999999;
    var min = 10000000;
    sessionStorage.tab = Math.floor(Math.random() * (max - min + 1) + min);
}

//set tab_id cookie before leaving page
window.addEventListener('beforeunload', function() {
    document.cookie = 'tab_id=' + sessionStorage.tab;
});
_

HTML5 sessionStorageはタブ間で共有されないため、一意のタブIDをそこに格納できます。ウィンドウでbeforeunloadイベントをリッスンすると、離れる(そして他のページをロードする)ことがわかります。離れる前にcookieを設定することで、URLを余分に操作することなく、新しいリクエストに値を含めます。タブを区別するには、サーバーで_$_COOKIE['tab_id']_を確認し、セッション値を適切に保存するだけです。

window.open()をトリガーすると、親とsessionStorageを共有するウィンドウが作成され、同じIDの2つのタブが表示されるというFirefoxの動作がおかしいことに注意してください。空白のタブを手動で開いてから、ターゲットURLに移動すると、別のストレージが提供されます。 Chromeは、これまでのすべてのテストで機能します。

これはおそらく正しい答えではなく、「良い」答えでさえないことに気づきますが、それはanの答えです。

7
allknowingfrog

私はこの機能を備えたWebアプリを作成するために一生懸命取り組んでいます。

それは成熟しておらず、JavaScriptが外部のphpコードに投稿する場合、URLでセッションIDを送信する必要があるなどの制約とフローがありますが、機能的であり、私のニーズに適しています(今のところ)。

私はより安全な解決策を考えているので、あなたのニーズに自由に適合させて、私にあなたの提案をしてください。

<?php
/**
* Split $_SESSION by browser Tab emulator.
* methods exemples are used whith :
* $session = new SessionSplit();
* as SessionSplit may reload the page, it has to be used on top of the code.
* 
*/
class SessionSplit{
    public $id;
    private $gprefix="session_slice_";
    private $prefix="";
    private $witness="";
    function SessionSplit($witness='witness'){
        if(session_status()===PHP_SESSION_NONE){
            session_start();
        }
        $this->witness=$witness;
        if($this->get_id()){
            $this->prefix=$this->gprefix.$this->id;
            //set a witness to 'register' the session id
            $this->set($this->witness,'true');
        }else{
            // force the session id in the url to not interfere with form validation
            $actual_link = "http://$_SERVER[HTTP_Host]$_SERVER[REQUEST_URI]";
            $new_link = $actual_link.(strpos($actual_link,'?')===false?'?':'&').
                'session_id='.$this->id;
            header('Location: '.$new_link); 
        }
    }
    private function get_id(){
        if(isset($_GET['session_id'])){
            $this->id=$_GET['session_id'];
            return true;
        }else{
            $this->new_id();
            return false;
        }
    }
    private function new_id(){
        $id=0;
        while(isset($_SESSION[$this->gprefix.$id.'.'.$this->witness])){$id++;}
        $this->id=$id;
    }
    // ----------- publics
    public function clearAll(){
        foreach($_SESSION as $key=>$value){
            if(strpos($key,$this->prefix.'.')===0){
                unset($_SESSION[$key]);
            }
        }
    }
    /**
    * $is_user=$session->has('user');
    * equivalent to
    * $is_user=isset($_SESSION['user']);
    * @param {string} $local_id 
    * @return {boolean}
    */
    public function has($local_id){
        return isset($_SESSION[$this->prefix.'.'.$local_id]);
    }
    /**
    * 
    * $session->clear('user');
    * equivalent to
    * unset($_SESSION['user']);
    * @param {string} $local_id 
    */
    public function clear($local_id){
        unset($_SESSION[$this->prefix.'.'.$local_id]);
    }
    /**
    * $user=$session->get('user');
    * equivalent to
    * $user=$_SESSION['user'];
    * @param {string} $local_id 
    * @return {mixed}
    */
    public function get($local_id){
        if (isset($_SESSION[$this->prefix.'.'.$local_id])) {
            return $_SESSION[$this->prefix.'.'.$local_id];
        }else return null;
    }
    /**
    * $session->set('user',$user);
    * equivalent to
    * $_SESSION['user']=$user;
    * @param {string} $local_id 
    * @param {mixed} $value
    */
    public function set($local_id,$value){
        $_SESSION[$this->prefix.'.'.$local_id]=$value;
    }
};
?>
0
yorg

これが私の解決策です。これを使用して、クライアントごとに複数のアプリビューを開くことができます。

データを取得するPOST: 'doStuff = getData&model = GTD&sn = 6789&type = random&date = 18-Dec-2018'

次に、コントローラーはテーブルからデータを取得し、デバイスのオブジェクトを作成し、それをセッションオブジェクトに格納して、変数に格納します。タブごとのGUIDを生成するので、ユーザーはUIの同じビューを異なるビューと比較できます。

$ _session [$ model] [$ sn] [$ type] [$ guid] [$ key];

もちろん、GUIDもデータオブジェクトで送り返されるので、タブは後でそのデータを呼び出す方法を認識します。

ユーザーが結果をファイル(pdfなど)に印刷する場合、POSTで関連データを含む投稿を送信します。

「doStuff = saveFile&model = GTD&sn = 6789&type = random&calDate = 18-Dec-2018&guid = randomKey」

次に、コントローラーはそれをストレージに渡して取得します。

セッションクラスファイルの例:

<?php
class Session {
public $fieldKey1;
public $fieldKey2;

public function GetStorage($model, $sn, $type, $guid, $key) {
    return $_SESSION[$model][$sn][$type][$guid][$key];
}

}

?>

コントローラファイル:

<?php
require_once('session.php'); 
global $session; //from session class file
switch($_POST['doStuff']) {
  case 'saveFile':
     $session->GetStorage($_POST['model'], $_POST['sn'], $_POST['type'], $_POST['guid'], $key);
     break;
}
?>

これにより、ユーザーは各タブのデータセットを上書きせずに、同じデータの複数のビューを持つことができます。タブごとにそれほど多くのデータの細分性が必要ない場合は、もちろん$ _SESSION変数のキーの数を単純化できます。

0
Morris Buel