質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

1558閲覧

header関数がうまく動かない。。

ringoame49

総合スコア46

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2021/09/19 16:04

1日中調べましたがどうにもならないのでお知恵をおかしください。

現在簡単なログインシステムを作っています。
header関数を使用して様々な場合にログインページへ遷移させています。
しかし1箇所だけ下記エラーがでます。
Notice: Trying to access array offset on value of type bool in ~ on line ~
Warning: Cannot modify header information - headers already sent by ~

header関数で遷移させているパターンは
直接このコードがかかれたページにアクセスした時、メアドとパスワードが間違っていた時等ですが、特定のheaderだけエラーが出ます。
エラーが出るのはアドレスを間違えた時です。アドレスの型を間違えた場合はキチンとheader関数は動きます。
アドレスが合っていてパスワードが間違っていた場合はエラーはでません。
メアド、パスワードに間違いがなければログインんができheader関数もキチンと動きます。
下記部分でエラーが出ています。

if($check === false || $check == '' || $check === NULL){ $_SESSION['E-message'] = "mistaken"; header("Location: login"); exit();

DBからpassを拾えてないのが問題なのでしょうか。。。XAMPPではキチンと動いています。
サーバーはロリポップでPHPのバージョンは7.4のLiteSpeedなるものです。
BOMもなしで保存しています。
exit();をdie('location header sent'); に変えたりheader("Location: フルパス");にしてもダメでした。。

下記ソースです。

<?php session_set_cookie_params(0); session_name('didyesclean'); session_start(); if($_SESSION['token'] == ""){ header("Location: login"); exit(); } $token = filter_input(INPUT_POST, 'token'); if ($token != '' || $token != NULL) { if($token != $_SESSION['token']){ $_SESSION['EM'] = "ut"; header("Location: login"); exit(); } } function db_connect(){ $dsn = 'mysql:dbname=sample;host=sample;charset=utf8'; $user = 'sample'; $password = 'sample'; try{ $dbh = new PDO($dsn, $user, $password); return $dbh; }catch (PDOException $e){ print('Error:'.$e->getMessage()); die(); } } $dbh = db_connect(); $mail = filter_input(INPUT_POST, 'mail'); $pass = filter_input(INPUT_POST, 'password'); if (!empty($mail)){ if(!preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9._-]+)+$/", $mail)){ $_SESSION['EM'] = "im"; header("Location: login"); exit(); } } $statement = $dbh->prepare("SELECT pass FROM users WHERE mail = :mail"); $statement->bindValue(':mail', $mail, PDO::PARAM_STR); $statement -> execute(); $result = $statement -> fetch(PDO::FETCH_ASSOC); $check = password_verify($pass, $result['pass']); if($check === false || $check == '' || $check === NULL){ $_SESSION['EM'] = "mt"; header("Location: login"); exit(); } elseif($check === true) { } header("Location: mypage"); exit(); }else{ header("Location: login"); exit(); } ?>

どなたかご教授していただけますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

php

1$result = $statement -> fetch(PDO::FETCH_ASSOC); 2$check = password_verify($pass, $result['pass']);

この部分ですが、リファレンスによるとPDOStatement::fetch()は失敗するとfalseを返します。
https://www.php.net/manual/ja/pdostatement.fetch.php
そして、失敗してbool型を受け取った$resultに対して、配列アクセスを試みています。
故に下記のNoticeが出ていると思われます。

Notice: Trying to access array offset on value of type bool in ~ on line ~

ここで、header関数は呼び出される前になんらかの出力が行われると機能しない仕様であることから、
エラー出力が先行してしまったので、ヘッダー出力ができずにリダイレクトに失敗しているということを下記のエラーメッセージが指しています。

Warning: Cannot modify header information - headers already sent by ~

PDOStatement::fetch()がなぜ失敗したか調査する必要もありますが、
ケースバイケースで以下のいずれかまたは複数の対応を実施すると良いかと思います。

  • 本来は失敗してはならないのであればそのように修正する
  • 失敗することも想定内の場合(false)を判定する処理を追加してエラーを吐かせないようにする
  • そもそもエラー出力させない(別途ログ出力させる)
  • PHPの設定でNoticeを吐かないようにする

投稿2021/09/19 16:31

編集2021/09/19 16:35
surface_0

総合スコア497

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ringoame49

2021/09/19 20:31 編集

とてもわかりやすいご説明ありがとうございます!! 現在PHPのエラーを可視化できるよう.htaccessにphp_flag display_errors onの設定をしています。 それのせいでNotice: Trying to access array offset on value of type bool in ~ on line ~ が表示されheader関数は呼び出される前になんらかの出力が行われると機能しないに抵触してしまっていたんですね。。。 >失敗することも想定内の場合(false)を判定する処理を追加してエラーを吐かせないようにする これは事前に入力されたアドレスがDBに存在するかCOUNTし「0」ならpassをSELECTするロジックへ進む前にheader関数でloginに飛ばせるので動き的には意図した動きになったのですが、このような処置でよろしいのでしょうか?
surface_0

2021/09/20 01:38 編集

> これは事前に入力されたアドレスがDBに存在するかCOUNTし「0」ならpassをSELECTするロジックへ進む前にheader関数でloginに飛ばせるので動き的には意図した動きになったのですが、このような処置でよろしいのでしょうか? 今回のfetch()がfalseになることに関しては結果が0件だったことが原因だと思うので、そのやり方も一つの解だとは思います。 ですが、逆にその他の要因は考える必要が無いのであれば、 最初の通りいきなりSELECTして、そのfetch()結果がfalseならば0件と解釈して、ログインページへ戻すようにすればいいと思います。 一般的にDBアクセスする回数は少ない方が良いので、なるべく減らす方向で最適化すると良いと思います。 こういうユーザー入力の検証処理はどこまで細かく分別するかの粒度がシステムによって様々で無数に考えられるので、あえて言及しませんでしたが、 提示されているコードのように同じ結果に行きつくところがパターンが複数ある場合はthrowとtry ~ catchを有効に使うと同じコードの繰り返しが減ってシンプルになります。
ringoame49

2021/09/20 04:03

度々のご回答ありがとうございます! throwとtryについて調べてみましたが便利そうですね! 今回のソース内ではどのように組み込めばいいのか100%の理解はできていませんが頑張って勉強します!
guest

0

Notice: Trying to access array offset on value of type bool in ~ on line ~

というメッセージが、header関数実行前に出力されているからでしょう。
出力されないようにしましょう。

投稿2021/09/19 16:19

otn

総合スコア84499

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ringoame49

2021/09/19 20:30

ご回答ありがとうございます! 上の方の回答で理解できました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問