共有レンタルサーバーを借りてPHPでサイト構築中です。
PHPスクリプト内で、
header("Location:http://hoge.com/aaa/bbb.html");
を使って同サーバ内の別ファイルへ飛ばしている部分があります。
ローカル環境(PHP5.1.5(php4で使えるスクリプトのみで書いています))では問題ないのですが、借りているサーバ(php4.4.4)に上げると、この関数の直後にセッションが切れて(消えて?)しまうのです。
どういう原因が考えられるか分からず困っています。どなたかアドバイスをよろしくお願いします。
現象を確かめようと下記のサンプルを動かしてみたのですが、カウントアップさえ満足に動かなかったので調査にしばらくかかってしまいました。
<?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:は特別の意味をもつので
この場合はセッションIDは送られていません。
リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。
回避方法としてはDBへsaveするようsession_save_handlerを書くことかなぁと思います。
header() の前に session_write_close() を呼んでみてはどうでしょうか。
ありがとうございます。
早速試してみてご報告します。
………
header("Location:~");の直前でsession_write_close();を書いて試してみたのですが、やはりセッションが消えてしまいます。
でもとても勉強になりました。ありがとうございます。
headerで飛ぶ際に新しいセッションIDが作られているのが問題ではないでしょうか?
そうであれば明示的にセッションIDを渡すことで対応できるようです。
具体的なコードは下のURLを参考にしてみてください。
http://ml.php.gr.jp/pipermail/php-users/2002-May/007496.html
回答ありがとうございます。
教えていただいた記事を読みました。
SIDをくっつけるやり方だと、URLに常にセッションIDがくっついていってしまうのですよね。
私のサイトでは.htaccessを使って、動的ページを静的ページに見せる処理をしています。
できる限り、今の状態を保ちたいのです…。
教えていただいたURL先で対処法を学ばせていただきました。でも、header("Location:~")の後にセッションが引き継がれない現象はなぜ起こるのか、原因は突き止められていなかったようです。
今朝借りてるサーバのサポートセンターに問い合わせたのですが、調査して折り返します、といわれました。こういうことってイレギュラーなんでしょうか。
私も何回かコレでハマったことがあります。
その時はLocationのタイミングの問題だった気がします。
ちょっと気になる事がいくつか。
・SESSIONが消えてしまうというのはどういうところから確認されましたか?
・おまじない的なものですが書式はheader('Location: http://hoge.com')というふうにLocation: のあとに半角スペースを入れます。
・念のため確認ですが、レンタルサーバーから自宅へのLocationになってしまっていないですよね?w
・display_errorsはどうなっていますか?(noticeでもあればはっきりわかる環境ですか?
・上記と関連しますがLocationの前にヘッダ出力はありませんか?(echo, print, include_once, require_once・・・etc
ピンポイントで原因を挙げられなかったので思いついたまま書きました。
乱文ごめんなさい。
心強くなる回答、ありがとうございます!
私のサイトでは.htaccessを使って、動的ページを静的ページに見せる処理をしており、たとえば
をリクエストすると
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~ というエラーが図れるので、多分これも大丈夫かなあ、と思います。もう少し細かくスクリプトを見てみます。
具体的にアドバイスしてくださってありがとうございます!
現象を確かめようと下記のサンプルを動かしてみたのですが、カウントアップさえ満足に動かなかったので調査にしばらくかかってしまいました。
<?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:は特別の意味をもつので
この場合はセッションIDは送られていません。
リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。
回避方法としてはDBへsaveするようsession_save_handlerを書くことかなぁと思います。
丁寧な回答を、本当にありがとうございます。
作っていただいたサンプルを動かしてみました。カウントは加算されていき、SERVER_ADDRは変わりませんでした。
そして、『リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。』
というアドバイスを読んで、ではheade(Location:~)を使ってないところでは本当にセッション切れは起こしていないかどうか、今更ながらチェックした所、セッション切れしてしまうところがでてきてしまいました。
aコンテンツTOPページ→bコンテンツTOPページリンクの順だとセッションは継続されるのに、
aコンテンツTOPページでログイン処理。→ログイン状態でaコンテンツページを再表示→bコンテンツTOPページリンク
の順だとセッション切れを起こしているようなのです。この流れではheader(Location:~)は使っていないので、header(Location:~)が原因ではない気がしてきました。
皆さんに色々アドバイスをいただいてきたのに申し訳ありません。
でも、やはりセッション切れを起こす原因は分かりません。
私のソースの書き方が問題を起こしているのかも知れないのでもう少しじっくり見てみますが、もうどうしても駄目なら
tobeoscontinueさんが教えてくださった回避方法を実装できるようがんばってみます。
ローカルでは全然問題なく動くので、本当によく分からないです。こちらのソースで変えてるのはドメイン名くらいなのに…。
もしも何かお気付きの点があれば、何でもいいので教えてください。よろしくおねがいします。
丁寧な回答を、本当にありがとうございます。
作っていただいたサンプルを動かしてみました。カウントは加算されていき、SERVER_ADDRは変わりませんでした。
そして、『リダイレクトするクライアントにキャッシュされているセッションIDが送られているので毎回セッションIDを変えるようなものでないかぎり問題はないと思います。』
というアドバイスを読んで、ではheade(Location:~)を使ってないところでは本当にセッション切れは起こしていないかどうか、今更ながらチェックした所、セッション切れしてしまうところがでてきてしまいました。
aコンテンツTOPページ→bコンテンツTOPページリンクの順だとセッションは継続されるのに、
aコンテンツTOPページでログイン処理。→ログイン状態でaコンテンツページを再表示→bコンテンツTOPページリンク
の順だとセッション切れを起こしているようなのです。この流れではheader(Location:~)は使っていないので、header(Location:~)が原因ではない気がしてきました。
皆さんに色々アドバイスをいただいてきたのに申し訳ありません。
でも、やはりセッション切れを起こす原因は分かりません。
私のソースの書き方が問題を起こしているのかも知れないのでもう少しじっくり見てみますが、もうどうしても駄目なら
tobeoscontinueさんが教えてくださった回避方法を実装できるようがんばってみます。
ローカルでは全然問題なく動くので、本当によく分からないです。こちらのソースで変えてるのはドメイン名くらいなのに…。
もしも何かお気付きの点があれば、何でもいいので教えてください。よろしくおねがいします。