- 締切済み
PHPでWarning(Cannot modify header information - headers already sent..
初めまして!PHP初心者です。 PHPとMySQLを使ってプログラムを作成しています。 昨日から、 PHP Warning: Cannot modify header information - headers already sent by (output started at /srv/htdocs/Common/add_comment.php3:251) in /srv/htdocs/Common/add_comment.php3 on line 260, referer: http://Pewit3/add_comment.php3?STRNUMBER=11747 というメッセージが、"時々"出ます。 理解出来ないのが、出る時と出ない時があるという点で、指摘されてるソースの部分は以下の通りです。 249: $result = mysql_db_query(DATABASE,"SELECT STRNO, TEXT FROM SOLUTION WHERE STRNO=$STRNUMBER;"); 249: if ($result) { 248: print "<PRE>\n"; 249: while ($row = mysql_fetch_array($result)) 250: { 251: printf("%s\n",$row["TEXT"]); 252: } 253: print "</PRE>\n"; 254: mysql_free_result( $result ); 255: } 256:} 257: 258:if ($COMMENT_ADDED && empty($SUCCESS)) { 259: $url_append="?STRNUMBER=$STRNUMBER&SUCCESS=1"; 260: header("Location: ".$_SERVER['PHP_SELF'].$url_append); 261:} <?php と ?>の前後にスペース、またはタブはありません。 何かヒントを頂けたら幸いです。
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- nicolish
- ベストアンサー率72% (13/18)
見るのはそこではない。 最初の行が実行され、かつ($COMMENT_ADDED && empty($SUCCESS))が真となる条件があるかどうかのチェックが必要。だから、最初の行が実行される条件と、この2変数への代入がどこでどう行なわれているかを追う必要がある。 たとえSELECTで返ってくる結果が空だろうと、テーブルが空だろうと、SELECT文が文法的に正しくテーブル定義と一致している限り、mysql_db_queryの結果は常にfalse以外の何かになる。 つまり、一行目が実行されればif($result)は常に成立する(DBが落ちたりDB定義を変更したりしない限りは)。SELECT結果が0件でもな。 するとprint "<PRE>\n";は実行されるので、つまり少なくとも"<PRE>\n"は出力される。これが出力されてしまったあとにheader関数が呼ばれたら、その時点でWarningになる。 DBカラムの中身の精査は不要。STRNOやTEXTの中身がテキストだろうと数値だろうとバイナリだろうとENUMだろうと悪魔だろうと、そんな事は(少なくとも提示された部分では)このエラーとは一切関係ない。 デバッグするなら、headers_sent関数を使い、既に出力があった場合には最後から2行目のheader関数が実行されないようにしてWarningを防いでおく。と同時に、headerの前のどこで出力が起きたのかと、実際に出力された内容をチェックする(ついでに俺なら$_REQUESTを丸ごとログに出力しておく)。 この部分以外で出力がある事も考えられるわけだが、この方法なら原因を突き止めるための情報が手に入るはず。 ついでにちょっと書き換えて、実際に実行されたSQLクエリも記録すると完璧かな。前述の通り、実行内容が何だろうとそうそう問題は起きないはずなのだけれど。 それと、今回の問題とは直接関係ないのだが、SQLインジェクション脆弱性の匂いがする。$STRNUMBERに'1 OR 1=1'という文字列が入ってきたら全件出力される、とか。 どこかで$STRNUMBERが数値のみで構成されていると検証しているならば問題はないのだが。
- nicolish
- ベストアンサー率72% (13/18)
L.248、L.251、L.253のprint文がいずれか一度でも実行された後L.260が実行されるとエラーになる。 header()は画面出力の前に呼ばれなければいけない。 逆に言うと、既に何かが出力されていたらheader()は呼んではいけない。そのWarningはそう言っている。
補足
nicolishさん、早速回答をありがとうございます! エラーの内容は理解出来るのですが、元々既存のプログラムで全く 問題なく稼動していたため、途方に暮れています。 L249で取得しているTEXTエリアに変な文字が入ってるのかとも思い、INT型のSTRNOだけ取得して出力するようにしてみたのですが、結果は同じでした。 正常に処理が実行される場合と、Warningが出る場合の違いが良くわかりません。
お礼
nicolishさん、またまた素早い回答を本当にありがとうございます! 先ほどのプログラムの補足をさせてください。 先ほど記述したSQL文の前に、もう1つSQL処理をしています。 $result = mysql_db_query (DATABASE,"SELECT COMMENT,STATUS FROM DFSCOMMENTS WHERE STRNO=$STRNUMBER AND STATUS !=\"incorporated\";"); if ($result) { print "<PRE>\n"; while ($row = mysql_fetch_array($result)) { printf("\n<B>Status: %s</B>\n",$row["STATUS"]); printf("%s\n",$row["COMMENT"]); } print "</PRE>\n"; mysql_free_result( $result ); } 先ほど記述した箇所をコメント化すれば、全く問題なく処理は進むのです。 この2つのSQL処理は同じIF文の中で実行されていて、どちらかだけが実行されるという事はありません。 そこで、データベースのデータに原因があるのかもしれないと思ってしまったのです。 そこで追加質問ですが、PHPソースの中にタブや空白が混在していても問題ないでしょうか?(段落分けのためなど)