PHPの質問です。

共有レンタルサーバーを借りてPHPでサイト構築中です。
PHPスクリプト内で、
header("Location:http://hoge.com/aaa/bbb.html");
を使って同サーバ内の別ファイルへ飛ばしている部分があります。
ローカル環境(PHP5.1.5(php4で使えるスクリプトのみで書いています))では問題ないのですが、借りているサーバ(php4.4.4)に上げると、この関数の直後にセッションが切れて(消えて?)しまうのです。

どういう原因が考えられるか分からず困っています。どなたかアドバイスをよろしくお願いします。

回答の条件
  • 1人3回まで
  • 登録:
  • 終了:2007/02/19 00:04:51
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:tobeoscontinue No.4

回答回数220ベストアンサー獲得回数59

ポイント100pt

現象を確かめようと下記のサンプルを動かしてみたのですが、カウントアップさえ満足に動かなかったので調査にしばらくかかってしまいました。

<?php
$url = "http://hoge.com";
session_start();
if (!isset($_SESSION['count'])) {
   $_SESSION['count'] = 0;
} else {
   $_SESSION['count']++;
}
if ($_SESSION['count'] % 2 == 0) {
	header("Location: ".$url);
}
else {
 echo "ADDR=".$_SERVER['SERVER_ADDR']."<br>";
 echo "PORT=".$_SERVER['SERVER_PORT']."<br>";
 echo session_id()."=".$_SESSION['count']."<br>";
 echo"time=".date("G:i:s")."<br>";
}
?>

原因はSERVER_ADDRが変わることです。urlが同一でも負荷分散のためか

異なるアドレスに割り振られていました。このような構成のサーバーではheader()によらず、再現性のない状態でセッションが切れると思います。


確かめる方法として上記をサーバーにアップして数回リロードしてカウントが正常にアップするか確かめることです。カウントが上下し、その時にサーバーアドレスが違っていたら、そういうことだと思います。


ローカルではSERVER_ADDRが変わるということはまずない(そこまではしていないだろうから)ので切れないのだと思います。


ただheader()でLocation:は特別の意味をもつので

http://jp.php.net/header

この場合はセッションIDは送られていません。

リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。


回避方法としてはDBへsaveするようsession_save_handlerを書くことかなぁと思います。

id:smegu

丁寧な回答を、本当にありがとうございます。

作っていただいたサンプルを動かしてみました。カウントは加算されていき、SERVER_ADDRは変わりませんでした。

そして、『リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。』

というアドバイスを読んで、ではheade(Location:~)を使ってないところでは本当にセッション切れは起こしていないかどうか、今更ながらチェックした所、セッション切れしてしまうところがでてきてしまいました。

aコンテンツTOPページ→bコンテンツTOPページリンクの順だとセッションは継続されるのに、

aコンテンツTOPページでログイン処理。→ログイン状態でaコンテンツページを再表示→bコンテンツTOPページリンク

の順だとセッション切れを起こしているようなのです。この流れではheader(Location:~)は使っていないので、header(Location:~)が原因ではない気がしてきました。

皆さんに色々アドバイスをいただいてきたのに申し訳ありません。

でも、やはりセッション切れを起こす原因は分かりません。

私のソースの書き方が問題を起こしているのかも知れないのでもう少しじっくり見てみますが、もうどうしても駄目なら

tobeoscontinueさんが教えてくださった回避方法を実装できるようがんばってみます。

ローカルでは全然問題なく動くので、本当によく分からないです。こちらのソースで変えてるのはドメイン名くらいなのに…。

もしも何かお気付きの点があれば、何でもいいので教えてください。よろしくおねがいします。

2007/02/18 21:14:36

その他の回答3件)

id:GEN111 No.1

回答回数472ベストアンサー獲得回数58

ポイント50pt

header() の前に session_write_close() を呼んでみてはどうでしょうか。

id:smegu

ありがとうございます。

早速試してみてご報告します。

………

header("Location:~");の直前でsession_write_close();を書いて試してみたのですが、やはりセッションが消えてしまいます。

でもとても勉強になりました。ありがとうございます。

2007/02/15 19:14:11
id:nori0620 No.2

回答回数2ベストアンサー獲得回数0

ポイント50pt

headerで飛ぶ際に新しいセッションIDが作られているのが問題ではないでしょうか?

そうであれば明示的にセッションIDを渡すことで対応できるようです。

具体的なコードは下のURLを参考にしてみてください。

http://ml.php.gr.jp/pipermail/php-users/2002-May/007496.html

id:smegu

回答ありがとうございます。

教えていただいた記事を読みました。

SIDをくっつけるやり方だと、URLに常にセッションIDがくっついていってしまうのですよね。

私のサイトでは.htaccessを使って、動的ページを静的ページに見せる処理をしています。

できる限り、今の状態を保ちたいのです…。

教えていただいたURL先で対処法を学ばせていただきました。でも、header("Location:~")の後にセッションが引き継がれない現象はなぜ起こるのか、原因は突き止められていなかったようです。

今朝借りてるサーバのサポートセンターに問い合わせたのですが、調査して折り返します、といわれました。こういうことってイレギュラーなんでしょうか。

2007/02/16 11:40:28
id:y-asano No.3

回答回数2ベストアンサー獲得回数0

ポイント60pt

私も何回かコレでハマったことがあります。

その時はLocationのタイミングの問題だった気がします。

ちょっと気になる事がいくつか。

・SESSIONが消えてしまうというのはどういうところから確認されましたか?

・おまじない的なものですが書式はheader('Location: http://hoge.com')というふうにLocation: のあとに半角スペースを入れます。

・念のため確認ですが、レンタルサーバーから自宅へのLocationになってしまっていないですよね?w

・display_errorsはどうなっていますか?(noticeでもあればはっきりわかる環境ですか?

・上記と関連しますがLocationの前にヘッダ出力はありませんか?(echo, print, include_once, require_once・・・etc


ピンポイントで原因を挙げられなかったので思いついたまま書きました。

乱文ごめんなさい。

id:smegu

心強くなる回答、ありがとうございます!

私のサイトでは.htaccessを使って、動的ページを静的ページに見せる処理をしており、たとえば

http://hoge.com.jp/a/b.html

をリクエストすると

http://hoge.com.jp/index.php?hoge1=a&hoge2=b

というように置換えて、すべてルートディレクトリ直下のindex.phpを呼び出し、そのパラメータから必要なファイルを読み込んだりしています。セッションの関わるファイルには全て先頭にsession_start();を書いています。ですので、SESSIONが消えてしまうかvar_dump($_SESSION);でチェックしたのはindex.phpのsession_start()直後です。

header("Location:~")の部分はLocation:の後は半角あけ、絶対パスで書いています。

Location先はちゃんとサーバのURLです。

display_errorsはonになっており、noticeエラーも表示されます。エラーログにもエラーは吐かれていませんでした。

Locationの前にヘッダ出力、これが、もしかしたら…。でも、Locationの直前でechoを意図的にするとheaders already sent by~ というエラーが図れるので、多分これも大丈夫かなあ、と思います。もう少し細かくスクリプトを見てみます。

具体的にアドバイスしてくださってありがとうございます!

2007/02/16 14:18:44
id:tobeoscontinue No.4

回答回数220ベストアンサー獲得回数59ここでベストアンサー

ポイント100pt

現象を確かめようと下記のサンプルを動かしてみたのですが、カウントアップさえ満足に動かなかったので調査にしばらくかかってしまいました。

<?php
$url = "http://hoge.com";
session_start();
if (!isset($_SESSION['count'])) {
   $_SESSION['count'] = 0;
} else {
   $_SESSION['count']++;
}
if ($_SESSION['count'] % 2 == 0) {
	header("Location: ".$url);
}
else {
 echo "ADDR=".$_SERVER['SERVER_ADDR']."<br>";
 echo "PORT=".$_SERVER['SERVER_PORT']."<br>";
 echo session_id()."=".$_SESSION['count']."<br>";
 echo"time=".date("G:i:s")."<br>";
}
?>

原因はSERVER_ADDRが変わることです。urlが同一でも負荷分散のためか

異なるアドレスに割り振られていました。このような構成のサーバーではheader()によらず、再現性のない状態でセッションが切れると思います。


確かめる方法として上記をサーバーにアップして数回リロードしてカウントが正常にアップするか確かめることです。カウントが上下し、その時にサーバーアドレスが違っていたら、そういうことだと思います。


ローカルではSERVER_ADDRが変わるということはまずない(そこまではしていないだろうから)ので切れないのだと思います。


ただheader()でLocation:は特別の意味をもつので

http://jp.php.net/header

この場合はセッションIDは送られていません。

リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。


回避方法としてはDBへsaveするようsession_save_handlerを書くことかなぁと思います。

id:smegu

丁寧な回答を、本当にありがとうございます。

作っていただいたサンプルを動かしてみました。カウントは加算されていき、SERVER_ADDRは変わりませんでした。

そして、『リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。』

というアドバイスを読んで、ではheade(Location:~)を使ってないところでは本当にセッション切れは起こしていないかどうか、今更ながらチェックした所、セッション切れしてしまうところがでてきてしまいました。

aコンテンツTOPページ→bコンテンツTOPページリンクの順だとセッションは継続されるのに、

aコンテンツTOPページでログイン処理。→ログイン状態でaコンテンツページを再表示→bコンテンツTOPページリンク

の順だとセッション切れを起こしているようなのです。この流れではheader(Location:~)は使っていないので、header(Location:~)が原因ではない気がしてきました。

皆さんに色々アドバイスをいただいてきたのに申し訳ありません。

でも、やはりセッション切れを起こす原因は分かりません。

私のソースの書き方が問題を起こしているのかも知れないのでもう少しじっくり見てみますが、もうどうしても駄目なら

tobeoscontinueさんが教えてくださった回避方法を実装できるようがんばってみます。

ローカルでは全然問題なく動くので、本当によく分からないです。こちらのソースで変えてるのはドメイン名くらいなのに…。

もしも何かお気付きの点があれば、何でもいいので教えてください。よろしくおねがいします。

2007/02/18 21:14:36
  • id:GEN111
    かなりあてずっぽうなのでコメントで。
    たぶんこれはないと思いますが、自分で session_start() を呼ばずに session.auto_start を使っているとか……

    また、スクリプトの文字コードが UTF-8 なら UTF-8N で保存してみるとか。
  • id:smegu
    GEN111さん

    session_start()は先頭に必ず書くようにしているので、それは大丈夫じゃないかと思います。文字コードはEUC-JPなのですが、この保存にも、サーバに上げる時も同じコードで上げるように気をつけて、確認しています。
    明日サーバの管理者にも問い合わせてみます。

    気にしてくださってありがとうございます。
  • id:tobeoscontinue
    追記:回避方法として自分に割り当てられているディレクトリーへsession_save_path()を設定することも回避できるように思います。
  • id:tobeoscontinue
    >カウントは加算されていき、SERVER_ADDRは変わりませんでした。
    私の考えではサーバーの負荷分散なので再現性がないのが厄介です。


    とりあえず簡単には御自分のディレクトリ(/hogeとする)にtmp(名前はなんでもいい)を作って書き込み権限を設定しておく。
    session_save_path("/hoge/tmp");
    session_start();
    とすれば解決するので試してもらえればと思います。
    session_start()をしているものの前にsession_save_path()をすべて入れないと意味がないので、修正が大変かもしれません。
    php.iniを設定できるならソースの変更は必要がないのでいいのですが。
  • id:smegu
    tobeoscontinueさん

    教えていただいた通りにしたらできました!!
    やった!わーーい!
    本当に、本当にありがとうございます。
    GEN111さん、nori0620さん、y-asanoさんにもお世話になりました。

    私ももっともっと精進して、他の困っている人の手助けができるような人になれるようになりたいです。

    皆様、本当にありがとうございました。

  • id:tobeoscontinue
    沢山、ありがとうございます。
    逆に、勉強させてもらいました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません