PHPを使用した「通知:未定義の変数」、「通知:未定義のインデックス」、および「通知:未定義のオフセット」

2010年11月24日に質問されました。  ·  閲覧回数 1.8M回  ·  ソース

Pekka picture
2010年11月24日

PHPスクリプトを実行していますが、次のようなエラーが引き続き発生します。

注意:未定義の変数:10行目のC:\ wamp \ www \ mypath \ index.phpのmy_variable_name

注意:未定義のインデックス:11行目のmy_index C:\ wamp \ www \ mypath \ index.php

10行目と11行目は次のようになります。

echo "My variable value is: " . $my_variable_name;
echo "My index value is: " . $my_array["my_index"];

これらのエラーメッセージの意味は何ですか?

なぜ突然現れるのですか? 私はこのスクリプトを何年も使用していましたが、問題はありませんでした。

どうすれば修正できますか?


これは、問題を何度も説明するのではなく、重複してリンクするための

関連するメタディスカッション:

回答

Alin Purcaru picture
2010年11月24日
1115

注意:未定義の変数

PHPマニュアルの広大な知恵から:

初期化されていない変数のデフォルト値に依存することは、同じ変数名を使用する別のファイルに1つのファイルを含める場合に問題があります。 また、 register_globalsがオンになっている場合の主要なE_NOTICEレベルのエラーは、初期化されていない変数を操作する場合に発行されますが、初期化されていない配列に要素を追加する場合は発行されません。 isset()言語構造を使用して、変数がすでに初期化されているかどうかを検出できます。 さらに、より理想的なのは、変数が初期化されていない場合に警告またはエラーメッセージを生成しないため、 empty()のソリューションです。

PHPドキュメントから:

変数が存在しない場合、警告は生成されません。 つまり、 empty()は本質的に!isset($ var)||と簡潔に同等$ var == false

つまり、変数が設定されているかどうかを判断するために使用できるのはempty()のみであり、さらに、変数を次の00.0""に対してチェックします"0"nullfalseまたは[]

例:

$o = [];
@$var = ["",0,null,1,2,3,$foo,$o['myIndex']];
array_walk($var, function($v) {
    echo (!isset($v) || $v == false) ? 'true ' : 'false';
    echo ' ' . (empty($v) ? 'true' : 'false');
    echo "\n";
});

3v4l.orgオンラインPHPエディターで上記のスニペットをテストします

PHPは変数宣言を必要としませんが、スクリプトの後半で使用される変数に値を指定するのを忘れるセキュリティの脆弱性やバグを回避するために、PHPで宣言することをお勧めします。 宣言されていない変数の場合にPHPが行うことは、非常に低レベルのエラーE_NOTICE発行することです。これはデフォルトでも報告されませんが、マニュアルで開発中アドバイスしています

問題に対処する方法:

  1. 推奨:たとえば、未定義の変数に文字列を追加しようとする場合など、変数を宣言します。 または、次のように、 isset() / !empty()を使用して、参照する前に宣言されているかどうかを確認します。

    //Initializing variable
    $value = ""; //Initialization value; Examples
                 //"" When you want to append stuff later
                 //0  When you want to add numbers later
    //isset()
    $value = isset($_POST['value']) ? $_POST['value'] : '';
    //empty()
    $value = !empty($_POST['value']) ? $_POST['value'] : '';
    

    これはPHP7.0の時点ではるかにクリーンになり、 null合体演算子を使用できるようになりました。

    // Null coalesce operator - No need to explicitly initialize the variable.
    $value = $_POST['value'] ?? '';
    
  2. E_NOTICEのカスタムエラーハンドラーを設定し、メッセージを標準出力から(おそらくログファイルに)リダイレクトします。

    set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
    
  3. E_NOTICEのレポートを無効にします。 E_NOTICEだけを除外する簡単な方法は次のとおりです。

    error_reporting( error_reporting() & ~E_NOTICE )
    
  4. @演算子を使用してエラーを抑制します。

注:ポイント1だけを実装することを強くお勧めします。

注意:未定義のインデックス/未定義のオフセット

この通知は、ユーザー(またはPHP)が配列の未定義のインデックスにアクセスしようとしたときに表示されます。

問題に対処する方法:

  1. アクセスする前に、インデックスが存在するかどうかを確認してください。 これには、 isset()またはarray_key_exists()を使用できます。

    //isset()
    $value = isset($array['my_index']) ? $array['my_index'] : '';
    //array_key_exists()
    $value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
    
  2. 言語コンストラクトlist()は、存在しない配列インデックスにアクセスしようとすると、これを生成する場合があります。

    list($a, $b) = array(0 => 'a');
    //or
    list($one, $two) = explode(',', 'test string');
    

2つの配列要素にアクセスするために2つの変数が使用されますが、配列要素はインデックス0であるため、次のように生成されます。

注意:未定義のオフセット:1

$_POST / $_GET / $_SESSION変数

上記の通知は、 $_POST$_GETまたは$_SESSIONする場合によく表示されます。 $_POST$_GET場合、使用する前にインデックスが存在するかどうかを確認する必要があります。 $_SESSION場合、セッションがsession_start()で開始されていること、およびインデックスも存在することを確認する必要があります。

また、3つの変数はすべてスーパーグローバルであり、大文字であることに注意してください。

関連:

Ish picture
2010年11月24日
150

これらを試してください

Q1:この通知は、スクリプトの現在のスコープで$ varnameが定義されていないことを意味します。

Q2:疑わしい変数を使用する前にisset()、empty()条件を使用するとうまくいきます。

// recommended solution for recent PHP versions
$user_name = $_SESSION['user_name'] ?? '';

// pre-7 PHP versions
$user_name = '';
if (!empty($_SESSION['user_name'])) {
     $user_name = $_SESSION['user_name'];
}

または、迅速で汚い解決策として:

// not the best solution, but works
// in your php setting use, it helps hiding site wide notices
error_reporting(E_ALL ^ E_NOTICE);

セッションに関する注意:

mario picture
2010年11月24日
67

エラー表示@演算子

望ましくない冗長な通知の場合は、専用の@演算子を使用して、«未定義の変数/インデックスメッセージを»非表示にすることができます。

$var = @($_GET["optional_param"]);
  • 通常、これはお勧めしません。 新規参入者はそれを使いすぎる傾向があります。
  • 関数パラメーターやループなど、アプリケーションロジックの奥深くにあるコード(宣言されていない変数を無視する)には非常に不適切です。
  • ただし、 isset?:または??超抑制には@隠された通知を次のように復活させることができます: set_error_handler("var_dump");
    • さらに、最初のコードでif (isset($_POST["shubmit"]))を習慣的に使用/推奨するべきではありません。
    • 新規参入者はそのようなタイプミスを見つけることはありません。 まさにそのような場合のPHP通知を奪うだけです。 機能確認した @またはissetを追加します。
    • 最初に原因を修正してください。 通知ではありません。

  • @は、特にオプションの場合、主に$_GET / $_POST入力パラメーターで使用できます

そして、これはそのような質問の大部分をカバーしているので、最も一般的な原因について詳しく見ていきましょう。

$_GET / $_POST / $_REQUEST未定義の入力

  • 未定義のインデックス/オフセットに遭遇したときに最初に行うことは、タイプミスをチェックすることです。
    $count = $_GET["whatnow?"];

    • これは予想されるキー名であり、ページリクエストに存在しますか?
    • PHPでは変数名
  • 次に、通知に明らかな原因がない場合は、 var_dumpまたはprint_rを使用して、現在のコンテンツのすべての入力配列を確認

    var_dump($_GET);
    var_dump($_POST);
    //print_r($_REQUEST);
    

    どちらも、スクリプトが正しいパラメータで呼び出されたか、パラメータで呼び出されたかを明らかにします。

  • 別の方法として、または追加でブラウザのdevtoolsF12を使用し、ネットワークタブでリクエストとパラメータを調べます。

    browser developer tools / network tab

    POSTパラメータとGET入力は別々に表示されます。

  • $_GETパラメータについては、のQUERY_STRINGを確認することもできます。

    print_r($_SERVER);
    

    PHPはするいくつかのルールがある合体スーパーグローバルへの非標準のパラメータ名を。 Apacheもいくつかの書き換えを行う可能性があります。 提供された生の$_COOKIESやその他のHTTPリクエストヘッダーをそのように確認することもできます。

  • より明確に、 GETパラメータについてブラウザのアドレスバーを見てください:

    http://example.org/script.php?id=5&sort=desc

    ?疑問符の後のname=valueペアは、クエリ(GET)パラメーターです。 したがって、このURLは$_GET["id"]$_GET["sort"]しか生成できない可能性があります。

  • 最後に、 <form><input>宣言を確認します。パラメーターが必要なのに、パラメーターがない場合は、

    • 必要な各入力に<input name=FOO>があることを確認してください
    • id=またはtitle=属性では不十分です。
    • method=POSTフォームは$_POSTます。
    • 一方、 method=GET (または省略)は$_GET変数を生成します。
    • フォームが$ _GETを介してaction=script.php?get=paramを提供し、残りのmethod=POSTフィールドを$ _POSTの横に提供することも可能です。
    • 最新のPHP構成(≥5.6)では、 $_REQUEST['vars']再度使用することが可能になりました(ファッショナブルではありません)。これにより、GETパラメーターとPOSTパラメーターがマッシュアップされます。
  • mod_rewriteを使用している場合は、 access.log両方をチェックし、 RewriteLogを有効にして存在しないパラメーターを特定する必要があります。

$_FILES

  • 同じサニティチェックがファイルのアップロードと$_FILES["formname"]適用されます。
  • さらに、 enctype=multipart/form-data確認してください
  • <form>宣言のmethod=POSTと同様に。
  • 参照: PHP未定義インデックスエラー$ _FILES?

$_COOKIE

  • $_COOKIE配列は、 setcookie()直後に入力されることはなく、フォローアップHTTPリクエストでのみ入力されます。
  • さらに、それらの有効性はタイムアウトし、サブドメインまたは個々のパスへの制約となる可能性があり、ユーザーとブラウザーはそれらを拒否または削除することができます。
Erik picture
2010年11月24日
49

一般的には「悪いプログラミング」と、現在または後で間違いが発生する可能性があるためです。

  1. 間違いの場合は、最初に変数に適切な割り当てを行います。$ varname = 0;
  2. 本当にたまにしか定義されていない場合は、使用する前にif (isset($varname))でテストしてください。
  3. スペルが間違っていることが原因である場合は、それを修正してください
  4. たぶん、 PHP設定の警告をオフにすることさえでき
DGM picture
2010年11月24日
43

これは、まだ何も割り当てていない変数をテスト、評価、または印刷していることを意味します。 これは、タイプミスがあるか、変数が最初に何かに初期化されたことを確認する必要があることを意味します。 ロジックパスを確認してください。あるパスに設定されている場合と、別のパスに設定されていない場合があります。

Ferenci Zolt&#225;n L&#225;szl&#243; picture
2011年12月30日
36

通知は役立つので無効にしたくありませんでしたが、入力しすぎないようにしたかったのです。

私の解決策はこの関数でした:

function ifexists($varname)
{
  return(isset($$varname)?$varname:null);
}

したがって、$ nameを参照し、存在する場合はエコーする場合は、次のように記述します。

<?=ifexists('name')?>

配列要素の場合:

function ifexistsidx($var,$index)
{
  return(isset($var[$index])?$var[$index]:null);
}

$ _REQUEST ['name']を参照したい場合は、ページで:

<?=ifexistsidx($_REQUEST,'name')?>
mpyw picture
2014年08月27日
28

入力文字列を取得するための最良の方法は次のとおりです。

$value = filter_input(INPUT_POST, 'value');

このワンライナーは、次のものとほぼ同等です。

if (!isset($_POST['value'])) {
    $value = null;
} elseif (is_array($_POST['value'])) {
    $value = false;
} else {
    $value = $_POST['value'];
}

どうしても文字列値が必要な場合は、次のようにします。

$value = (string)filter_input(INPUT_POST, 'value');
Roger picture
2012年12月29日
26

これは、変数 '$ user_location'が定義されていないためです。 '$ user_location'変数を宣言しているifループを使用している場合は、elseループも使用して同じものを定義する必要があります。 例えば:

$a=10;
if($a==5) { $user_location='Paris';} else { }
echo $user_location;

上記のコードは、ifループが満たされておらず、elseループで '$ user_location'が定義されていないため、エラーが発生します。 それでもPHPは変数をエコーアウトするように求められました。 したがって、コードを変更するには、次のことを行う必要があります。

$a=10;
if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; }
echo $user_location;
Robbie picture
2016年11月23日
26

「なぜ突然現れるのか?

ほとんどのサイトでは、「すべてのエラーを表示しますが、「通知」および「非推奨」ではない」という「デフォルト」のエラーレポートの下で動作するのが非常に一般的です。 これはphp.iniで設定され、サーバー上のすべてのサイトに適用されます。 これは、例で使用されている「通知」が抑制(非表示)され、より重大と見なされる他のエラーが表示/記録されることを意味します。

もう1つの重要な設定は、エラーを非表示にできることです(つまり、 display_errorsを「off」または「syslog」に設定します)。

この場合に発生するのは、 error_reportingが変更されて通知も表示されるようになったか(例のように)、設定が画面にdisplay_errorsに変更された(抑制ではなく)それら/ログ)。

なぜ彼らは変わったのですか?

明白で最も簡単な答えは、誰かがphp.iniでこれらの設定のいずれかを調整したか、PHPのアップグレードバージョンが以前とは異なるphp.iniを使用しているということです。 それが最初に見る場所です。

ただし、これらの設定をでオーバーライドすることもできます。

  • .htconf(vhostsとサブ構成を含むWebサーバー構成)*
  • .htaccess
  • PHPコード自体で

これらのいずれも変更されている可能性があります。

また、Webサーバー構成で.htaccessディレクティブを有効/無効にできるという複雑な問題もあります。そのため、.htaccessに突然動作を開始/停止するディレクティブがある場合は、それを確認する必要があります。

(.htconf / .htaccessは、Apacheとして実行していることを前提としています。コマンドラインを実行している場合、これは適用されません。IISまたは他のWebサーバーを実行している場合は、それに応じてこれらの構成を確認する必要があります)

概要

  • php.iniのerror_reportingおよびdisplay_errors phpディレクティブが変更されていないこと、または以前とは異なるphp.iniを使用していないことを確認してください。
  • .htconf(またはvhostsなど)のerror_reportingおよびdisplay_errors phpディレクティブが変更されていないことを確認します
  • .htaccessのerror_reportingおよびdisplay_errors phpディレクティブが変更されていないことを確認します
  • .htaccessにディレクティブがある場合は、それらが.htconfファイルでまだ許可されているかどうかを確認してください
  • 最後にコードを確認してください。 おそらく無関係のライブラリ。 error_reportingおよびdisplay_errors phpディレクティブがそこに設定されているかどうかを確認します。
Shahin Mammadzada picture
2014年05月13日
21

簡単な修正は、コードの先頭で変数をnullに割り当てることです。

$user_location = null;