スレッド表示 | フラット表示〕 全トピック 920 件中 125 番目 次≫ ≪前

セッション クッキーの保存期間

created: 2007-01-21 00:50 | modified: 2007-04-04 01:37 | reply: 19

[3536] セッション クッキーの保存期間

user: 江戸川アダモ | created: 2007-01-21 00:50
デフォルト設定では、会員ページでログインしても、ブラウザを閉じるとセッション情報は消えてしまいます。
毎回ログインするのがめんどうなので、セッションクッキーとサーバ側のセッションの保存期限を1週間に設定すべく、次のようなスクリプトを追加しました。

ini_set("session.cookie_lifetime", "604800");//初期値は0
session_cache_expire(10080);//初期値は180
session_start();

その結果、とりあえずブラウザを閉じてすぐに再度ページを表示してもログイン状態は保持されていました。しかし、ブラウザを閉じてから何時間か経つと、ログアウトした状態に戻ってしまいます。
どうすれば1週間くらいログイン状態を保持することができるのでしょうか?
reply: 3538 返信 編集 削除

[3538] セッションの有効期間の制御

user: ゆうじ | created: 2007-01-23 00:00
こんばんわ。遅くなりました。

セッションの有効期限を制御するには、
session.cookie_lifetime の設定と合わせて
session.gc_maxlifetime も設定が必要です。

session.gc_maxlifetime は、
サーバに保存されているセッションのファイルを
破棄するまでの時間なんですが、
他のユーザと共用してるサーバでは、
全てユーザのセッションのファイルが
(デフォルトで)'/tmp' に保存しているため、
この値を設定するだけでは思うような制御ができません。


対応策としては、ポイントが2つあります。

(1)先ずセッションのファイルを保存するディレクトリを
自分だけが利用できるディレクトリに変更する。

session_save_path('/home/MyHomeDir/tmp');

この '/home/MyHomeDir/tmp' はあらかじめ
ドキュメントルート下ではない場所に任意のディレクトリをつくり、
ウェブサーバの権限で書き込める属性を設定しておきます。


(2)ディレクトリを変更すると
いらなくなったセッションファイルを自動的に破棄してくれなくなるので
これ様のセッションハンドラを書く。

セッションハンドラのコードについては
自分で使ってるコードを簡素化してみましたので使ってみてください。

実際使う際は、
セッションを使う全てのファイルが同じ設定である必要があるので
セッション関連はひとつのファイルにまとめて
使うスクリプトでinludeするのが良いと思います。


セッションハンドラ
file.sessionhandler.php
<?php
/*
* file session handler - for PHP4
*/
class file_sessionhandler
{
var $save_path = '';
var $name = '';
var $gc_maxlifetime = '';
var $gc_divisor = '';
var $gc_probability = '';

function open ( $save_path, $session_name )
{
if (!strlen($this->save_path)) {
$this->save_path = $save_path;
}
if (!strlen($this->name)) {
$this->name = $session_name;
}
$this->gc_execute();
return true;
}

function close ()
{
return true;
}

function read ( $id )
{
$filename = $this->save_path.
DIRECTORY_SEPARATOR. $this->name. '_'. $id;
return (string) @file_get_contents($filename);
}

function write ( $id, $data )
{
$filename = $this->save_path.
DIRECTORY_SEPARATOR. $this->name. '_'. $id;
if ($fp = @fopen($filename, 'w')) {
$return = fwrite($fp, $data);
fclose($fp);
return $return;
} else {
return false;
}
}

function destroy ( $id )
{
$filename = $this->save_path.
DIRECTORY_SEPARATOR. $this->name. '_'. $id;
return @unlink($filename);
}

function gc ( $maxlifetime )
{
if (is_integer($this->gc_maxlifetime)) {
$lifetime = $this->gc_maxlifetime;
} else {
$lifetime = $maxlifetime;
}

$search = $this->save_path.
DIRECTORY_SEPARATOR. $this->name. '_*';
foreach (glob($search) as $filename) {
if (filemtime($filename) + $lifetime < time()) {
@unlink($filename);
}
}
return true;
}

/*
* Protected:
*/
function gc_execute ()
{
$gc_tmp = 'gc.tmp';
$filename = $this->save_path.
DIRECTORY_SEPARATOR. $gc_tmp;
if (!is_readable($filename)) {
if ($fp = @fopen($filename, 'w')) {
fwrite($fp, '0');
fclose($fp);
return true;
} else {
return false;
}
}

$divisor =
(is_integer($this->gc_divisor) && $this->gc_divisor > 0) ?
$this->gc_divisor:
(integer)ini_get('session.gc_divisor');
$probability =
(is_integer($this->gc_probability) && $this->gc_probability > 0) ?
$this->gc_probability:
(integer)ini_get('session.gc_probability');
$count = (integer)trim(file_get_contents($filename));
$max_count = (integer)floor($divisor/$probability);
if ($fp = @fopen($filename, 'w')) {
if ($max_count <= $count) {
$this->gc(ini_get('session.gc_maxlifetime'));
fwrite($fp, '0');
} else {
fwrite($fp, $count+1);
}
fclose($fp);
return true;
} else {
return false;
}
}
}
?>

セッションの設定ファイル
session.conf.php
<?php
/*
* セッションハンドラ設定
*/
require_once 'file.sessionhandler.php';
$_shandler = new file_sessionhandler;
session_set_save_handler(
array(&$_shandler, 'open'),
array(&$_shandler, 'close'),
array(&$_shandler, 'read'),
array(&$_shandler, 'write'),
array(&$_shandler, 'destroy'),
array(&$_shandler, 'gc')
);

/*
* セッションパラメータ設定
*/
ini_set('session.cookie_lifetime', '604800');
ini_set('session.gc_maxlifetime', '604800');
session_save_path('/home/MyHomeDir/tmp');
?>


実行ファイル側
<?php
require_once 'session.conf.php';
session_start();

/*
* 以下は各処理
*/

?>
Parent: 3536  reply: 3539 3642 返信 編集 削除

[3539] セッションの有効期限

user: 江戸川アダモ | created: 2007-01-23 21:56
ゆうじさん。いつもありがとうございます。
気軽に考えていましたが、結構大変な制御ですね。自分専用のセッション保存用ディレクトリを使って、その中でセッションが自動的に消えるようにするんですね。
只今、紹介いただいたコードを解読中ですが、実はオブジェクト指向のスクリプトを書いた事がないので、少々難航しています。
ところで参考までに、現状では私はデフォルト設定でセッションを使っている事になりますが、
'session.gc_maxlifetime=1440'
ですので、24分しかもたないことになります。
しかし、実際には数時間ログイン情報は保持されます。これはなぜなのでしょう?
Parent: 3538  reply: 3541 返信 編集 削除

[3541] Re.セッションの有効期限

user: ゆうじ | created: 2007-01-24 23:52
確かに24分以上アクセスしなくても
セッションが保持され続けてることはありますね。
これも結構深い話になりますよ。

セッションが切断されるのは、クッキーが破棄された場合と、
セッションのファイルが破棄された場合の2パターンがあり
それぞれタイミングが違います。


クッキーの方は有効期限が切れた時で、
session.cookie_lifetimeで設定できます。
実際のところユーザPCが有効期限を判断して破棄します。


セッションファイルの方は、
ガーベージコレクション(以降gc)と呼ばれる、
利用しなくなった物を破棄する仕組みが用いられてます。
gc は省エネ的ポリシーの持ち主で、
ゴミを破棄するのにせっせと働いたりはしません。
何かの条件によって実行するのではなく
○○%の確立で実行するちょっと特殊な代物です。

gc が実行されさえすれば、最終更新時刻が
session.gc_maxlifetime よりも古いファイルは
破棄されますがそれまでファイルは残ったままです。


これらを踏まえていただくと、
最終アクセスから各設定時間を過ぎた場合でも、
セッションが確立され続けてる時間が存在することが
おわかりいただけるかと思います。


ちなみに以下で
session.gc_probability = 1
session.gc_divisor = 100
(デフォルトで1/100の確立)
gcが実行される確立を設定できますが、
共用サーバだと設定したところで
どれほど効力があるのわかりません。


こんな具合なので
セッションを維持し続けるのもひと工夫いりますが、
確実に破棄するにもひと工夫必要です。

セッションクッキーを破棄するには、
過去の有効期限を持つクッキーを送信すれはOKです。
セッションファイルの破棄は、
gcに任せず破棄するコードを自前でを書く必要があります。

ただログイン・ログアウトの判定だけならば、
セッションにアクセス時間を記録しておき、
特定の時間を過ぎていれば無効と判断しログイン処理へ導けば
セッションを破棄するまでもありません。


それと、先のセッションハンドラですが
一応テストして稼動を確認しましたので
設定のところだけ書き換えてもらえれば
特に考えなくても使えますよ。
オブジェクト指向プログラミングは
理解できないまでも使いつづけるうちに
ある日突然全てが理解出来たりするので
まずは使って慣れることをおすすめします。
Parent: 3539  reply: 3546 返信 編集 削除

[3546] gcの不確定性

user: 江戸川アダモ | created: 2007-01-26 06:21
そうなんですか。ゴミ収集は確率的にしかやってくれないんですね。
個々のセッションの期限通りに廃棄なんてもちろんできないし、何曜日に収集に来てくれるかすら判らないと。
何だか素粒子の振る舞いみたいで深い話ですね。

で、先のセッションハンドラでやっていることは、そのゴミ収集の確率を設定している訳ですね。
私がソースを見ても判らないのは、それがオブジェクト指向だからなのか、それともセッション破棄のロジックそのものが判らないのか、がイマイチわからないのが原因だと思います。
ただ、仰るように、とりあえずこれをそのまま使ってできるかどうかやってみようと思います。ありがとうございました。
Parent: 3541  返信 編集 削除

[3642] 実行ファイルの書き方

user: 江戸川アダモ | created: 2007-03-11 08:30
アドバイス頂いてから随分経ってしまいましたが、まだ躓いている点があります。

まず、(1)ログイン認証を行うページがあって、ここではIDとPassを照合して正しければ:

$_SESSION['name']=$name;(←POSTされたID)

等として、セッション変数を設定します。
それで、このページの冒頭に

require_once 'session.conf.php';

を挿入することにより、自分で作ったフォルダの中にセッションファイルを作成することは出来ました。

しかし、そのセッションを引き継いで(2)掲示板の内容を表示するページでは、

if(isset($_SESSION['name'])){・・・・・

としてログインチェックを行っているのですが、ここではログインされていない事になってしまいます。
何もせずにsession_start();してしまうと、セッションファイルを探しにいくフォルダが元の初期設定のフォルダになってしまうと思って、冒頭に

require_once 'session.conf.php';

を入れたのですが、だめでした。

何か抜けてる点があるような気がするのですが、多分実行ファイルの書き方の問題だと思うのですが、いかがでしょう?
Parent: 3538  reply: 3643 返信 編集 削除

[3643] Re. 実行ファイルの書き方

user: ゆうじ | created: 2007-03-11 16:35
まいどどうも。

文章を読む限り間違ってはいないと思います。

実行ファイルの書き方でちょっと考えてみたのですが
session_start() は実行中1回呼ぶだけで良いので、
session.conf.php の最後に session_start() を書き足してしてもいいですね。
セッションを利用する全てのファイルの冒頭で
require_once 'session.conf.php';
を書くだけで済みます。

【改】session.conf.php
<?php
/*
* セッションハンドラ設定
*/
require_once 'file.sessionhandler.php';
$_shandler = new file_sessionhandler;
session_set_save_handler(
array(&$_shandler, 'open'),
array(&$_shandler, 'close'),
array(&$_shandler, 'read'),
array(&$_shandler, 'write'),
array(&$_shandler, 'destroy'),
array(&$_shandler, 'gc'));

/*
* セッションパラメータ設定
*/
ini_set('session.cookie_lifetime', '604800');
ini_set('session.gc_maxlifetime', '604800');
session_save_path('/home/MyHomeDir/tmp');

/*
* セッション開始
*/
session_start();
?>

セッションを使うファイル全ての冒頭で
<?php
require_once 'session.conf.php';

/*
* 以降各処理
*/


?>

エラーは出ないんですよね。
セッションが使えない原因として
ログイン処理と掲示板の内容を表示する処理で
ドメインが違うなんてことはありませんか。
Parent: 3642  reply: 3644 返信 編集 削除

[3644] Re2 実行ファイルの書き方

user: 江戸川アダモ | created: 2007-03-12 01:13
ゆうじさん。まいど有難うございます。

エラーは出ませんし、ドメインは全て同一です。
session.conf.php【改】は試してみますが、これ自体は不具合には関係ないですよね。

あとは思い当たることは無いのですが、あえて言えばセッションハンドラーファイルは純粋に関数の定義であって、私の環境特有の変数を入れる所は無いですよね?
それと、このハンドラーはセッションファイルの保存場所や寿命等を設定しているので、ログイン認証の時に一度実行すれば、その後は呼び出す必要は無いと思うのですが。単にセッションファイルのありかを示してやれば良いような気がするのですが。
Parent: 3643  reply: 3645 返信 編集 削除

[3645] Re. 実行ファイルの書き方

user: ゆうじ | created: 2007-03-12 01:51
> ゆうじさん。まいど有難うございます。
>
> エラーは出ませんし、ドメインは全て同一です。
> session.conf.php【改】は試してみますが、これ自体は不具合には関係ないですよね。
>
> あとは思い当たることは無いのですが、あえて言えばセッションハンドラーファイルは純粋に関数の定義であって、私の環境特有の変数を入れる所は無いですよね?

その通りです。file.sessionhandler.php は触らなくてOKです。
江戸川アダモさん所の固有の値を入れるのは
session.conf.php の中の
セッションパラメータ設定部分だけです。


> それと、このハンドラーはセッションファイルの保存場所や寿命等を設定しているので、ログイン認証の時に一度実行すれば、その後は呼び出す必要は無いと思うのですが。単にセッションファイルのありかを示してやれば良いような気がするのですが。

スクリプトで設定した値が有効なのはリクエストが終了するまでの間だけです。
リクエストが終了してしまえば
セッションハンドラも含め各設定はデフォルトに戻りますよ。

このセッションを参照する全てのリクエストが
同じセッションハンドラで、且つ同じ設定でなければ
セッションの整合性は保てなくなります。
なのでリクエストの度に以下の3つは必須です。

(1)セッションハンドラの設定
(2)セッションパラメータの設定
(3)セッション開始

つまり、このセッションを利用する
全てのスクリプトの冒頭で
require_once 'session.conf.php';
する必要があります。
Parent: 3644  reply: 3646 返信 編集 削除

[3646] セッション変数が引き継がれない

user: 江戸川アダモ | created: 2007-03-12 06:00
なるほど、わかりました。
しかし、仰るとおりにしているはずなんですが、やはり同じ状況ですね。

試しに、①ログイン認証のページとその後の②掲示板のページで:

var_dump($_SESSION['name']);

を入れてみたところ、①では問題なくログイン名が表示されるのに、②では"NULL"になってしまいます。つまりセッション変数を読み込めていないのです。
もちろん②の冒頭にもrequire_once 'session.conf.php';を入れています。ちなみに、①と②は同じフォルダにあり、①上にあるリンクを踏んで②に行きます。

あと考えられるのは…php.iniの設定で問題になるような項目なんてあるのでしょうか?あるいはその他のレンタルサーバーの設定とか?
Parent: 3645  reply: 3647 返信 編集 削除

[3647] Re. セッション変数が引き継がれない

user: ゆうじ | created: 2007-03-12 22:55
さて、どうやって確かめましょう。
段階を追って原因を切り分けましょうか。

先ず、セッションの挙動を確かめる為に
該当ディレクトリに以下のテストコードを置いてみてください。

setdate.php では現在時刻をセッションに保存し、
showdate.php でその時刻を表示しています。
この間を行き来すれば時刻が更新されます。

setdate.php
<?php
error_reporting(E_ALL);

require_once 'session.conf.php';

$_SESSION['time'] = date('Y-m-d H:i:s', time());

echo '<h3>setdate.php</h3>';
echo '<div>', $_SESSION['time'], '</div>';
echo '<div><a href="showdate.php">SHOW DATE</a></div>';

phpinfo();
?>

showdate.php
<?php
error_reporting(E_ALL);

require_once 'session.conf.php';

echo '<h3>showdate.php</h3>';
echo '<div>', $_SESSION['time'], '</div>';
echo '<div><a href="setdate.php">SET DATE</a></div>';

phpinfo();
?>

きちんと時刻が表示されれば、
原因はセッションハンドラや設定周りではありません。

動かなければ、
phpinfo() で表示されたセッション周りの設定を比較しましょう。
違いがあれば そこから設定周りの原因が見えてくるでしょう。

もし設定が同じなら、実行してるスクリプトか、
ブラウザの設定に原因があると考えられますね。
Parent: 3646  reply: 3649 返信 編集 削除

[3649] Re2. セッション変数が引き継がれない

user: 江戸川アダモ | created: 2007-03-13 05:20
なるほど、こうやってデバグするんですね。

それで結果ですが、時刻は引き継がれませんね。showdate.phpでは
Notice: Undefined index: time in .........../showdate.php on line 5
と出ます。

また、php.iniですが、セッション関係の設定はsetdate.phpとshowdate.phpで変わっていませんでした。

と言うことは・・・・ブラウザはIE,Firefox,Operaと試してみましたが同じ結果でした。

いい忘れてましたが、こちらのPHPのヴァージョンは5なんですが、このせいでスクリプトがうまく作動しないと言うことはあるのでしょうか?
Parent: 3647  reply: 3650 返信 編集 削除

[3650] PHP4 vs PHP5

user: 江戸川アダモ | created: 2007-03-13 05:30
ちょっと調べてみたら、結構ちがうようですね。$thisの使い方とか:
http://phpspot.net/php/php5_topics.html
すみません。もっと早く気づくべきでした。
Parent: 3649  reply: 3683 返信 編集 削除

[3683] session_start()は冒頭では?

user: 江戸川アダモ | created: 2007-03-24 20:17
いつも忘れたころにやってくる江戸川です。先ほどはこのコメントを修正しようと思って削除してしまいました。

あれからPHP4とPHP5の違いを調べてみたのですが、どうも当スクリプトで問題になるような変更点が見つかりませんでした。
第一、もし問題があれば途中でエラーが出るか、少なくとも所定のフォルダにセッションが出来たりしないのではないかと思いました。

そこで、視点を変えて、【session_start();】はrequire_once 'session.conf.php';
の後ではなく、スクリプトの冒頭にコールすべきではないかと思い立ち、例のsetdate.php/showdate.phpでやってみたら、なんと日付がうまく引き継がれるでは無いですか!
それでいて、phpinfoのsessionに関する設定も'session.conf.php'で指定した通りになっています。
Parent: 3650  reply: 3684 返信 編集 削除

[3684] 勘違いでした

user: 江戸川アダモ | created: 2007-03-25 14:20
単にデフォルトの設定でセッションが確立していただけのようです。
先のゆうじさんの解説の通り、セッションハンドラ呼び出し→セッション開始、という順序が正しいようです。
そうなるとまた以前の疑問に戻ってしまう訳ですが、下手な鉄砲で色々と試してみようと思います。
Parent: 3683  reply: 3685 返信 編集 削除

[3685] session_id の確認

user: ゆうじ | created: 2007-03-27 00:07
一応これまでに挙げたコードは
ココのサーバを使って動作確認しましたので
やり方やコードがおかしいとは考えにくいところです。

エラーが出ないことからすると
セッションは確立されてるとおもわれます。
ただ、アクセスの度に新しいセッションが
確立されてるのではないでしょうか。

以下のコードでセッションIDを確かめてみてください。


setdate.php
<?php
error_reporting(E_ALL);

require_once 'session.conf.php';

$_SESSION['time'] = date('Y-m-d H:i:s', time());

echo '<h3>setdate.php</h3>';
echo '<div>time: ', $_SESSION['time'], '</div>';
echo '<div>id: ', session_id(), '</div>';
echo '<div><a href="showdate.php">SHOW DATE</a></div>';

phpinfo();
?>

showdate.php
<?php
error_reporting(E_ALL);

require_once 'session.conf.php';

echo '<h3>showdate.php</h3>';
echo '<div>time: ', $_SESSION['time'], '</div>';
echo '<div>id: ', session_id(), '</div>';
echo '<div><a href="setdate.php">SET DATE</a></div>';

phpinfo();
?>

これで毎回セッションIDが変わるなら
session_start() する前に余分な空白や改行が出力され、
セッションのクッキーがブラウザに
送信されてないと考えられます。

file.sessionhandler.php や session.conf.php の
先頭と末尾のPHPタグの外側に
余分な改行や空白が含まれてないか
確かめてみてください。

なんなら末尾のPHPタグ(?>)は削除してしもかまいませんので。
Parent: 3684  reply: 3686 返信 編集 削除

[3686] Re.session_id の確認

user: 江戸川アダモ | created: 2007-03-27 17:35
残念ながらというか、session_idは変わっていませんね。
サーバー側のフォルダをみてもセッションは無駄に増えてはいません。

ちなみに、サーバに何か問題があるのかと思って、ホスティング会社に尋ねてみましたが、ユーザによるセッション周りの設定を無効にするような仕掛けは無いそうです。
逆に、.htaccessを設置すれば設定(セッション保存先フォルダや有効期限)を変更できると言われたので、やってみたらうまく行っています。
以前ゆうじさんが仰ったように、これではセッションは自動削除されないのでは?と尋ねましたが、問題なく消えるそうです。
もしそうなら私のニーズは満たしているのですが、ゆうじさんのスクリプトが作動しない原因が判らないと気になりますね。
Parent: 3685  reply: 3689 返信 編集 削除

[3689] Re.session_id の確認

user: ゆうじ | created: 2007-03-29 22:29
セッションファイルが自動削除されるなら
デフォルトのセッションハンドラのまま
パラメータ設定するだけでOKですね。
かなり遠回りしましたがひとまず解決ですね。

自作セッションハンドラについては
やはりPHP4とPHP5の違いで希望通りの動作を
しなかったってとこに行き着きますね。
そろそろPHP5の環境を入れて勉強してみようと思います。
Parent: 3686  reply: 3692 返信 編集 削除

[3692] セッションは難しい

user: 江戸川アダモ | created: 2007-03-30 23:28
この度は長々とお付き合い頂きありがとうございました。
PHP4とPHP5の違いに関しては、エラーが出てくれたら判りやすいのですが、なんだかわからないがPHP5だと動かない、じゃ難儀ですよね。

一方、こちらの共用サーバでうまく行っているのは、個々のユーザーが.htaccessを設置出来れば、それぞれのフォルダにあるセッションファイルを、gcがちゃんと消しに行くとからと考えてよいのでしょうか?
Parent: 3689  reply: 3697 返信 編集 削除

[3697] Re. セッションは難しい

user: ゆうじ | created: 2007-04-04 01:37
遅くなりました。

> 一方、こちらの共用サーバでうまく行っているのは、個々のユーザーが.htaccessを設置出来れば、それぞれのフォルダにあるセッションファイルを、gcがちゃんと消しに行くとからと考えてよいのでしょうか?

私が試した環境だけがセッションのファイルを
自動的に削除してくれない可能性もありますので
.htaccess 云々というより
サーバの仕様と考えた方が良いと思います。

# 追記
# 自動的に削除してくれないのは
# サーバの仕様ではなく
# 私の思い違いだったようです。
# 現在はちゃんと消されています
# すみません。
Parent: 3692  返信 編集 削除
スレッド表示 | フラット表示〕 全トピック 920 件中 125 番目 次≫ ≪前
ページの一番上へ
Googleグックマークに登録 Yahooグックマークに登録 livedoorクリップに登録 @niftyクリップに登録 はてなブックマークに登録 deliciousに登録 Buzzurlに登録 FC2ブックマークに登録
最近更新された掲示板トピックス
管理人Blog
Yahoo Search

最近更新したNote
PHPマニュアル
今日のブックマーク
PHPマニュアル関数検索
関数名を入力し検索ボタンをクリック↑