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

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

ただいまの
回答率

90.32%

  • PHP

    21373questions

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

  • POST

    242questions

    POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

  • Cookie

    197questions

    HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

  • GET

    96questions

    GETとはHTTPが対応するリクエストメソッドの一つです。クライアントからサーバーへ送られたURLパラメータのデータを取得する時必要がある時に使われます。

スーパーグローバル変数に直接アクセスしない方がいい理由

解決済

回答 4

投稿

  • 評価
  • クリップ 8
  • VIEW 5,263

te2ji

score 11976

$_GET, $_POST などの値を使用する場合、よくサンプルとして

$str = isset($_POST['str']) ? $_POST['str'] : '';

のようにスーパーグローバル変数を直接扱っているものを見かけます。

$str = $_POST['str'];

なんて記述は論外ですが、上の三項演算子のモノでも、IDE によっては「スーパーグローバル変数には直接アクセスしないでね。」と警告をクラってしまいます。

少し調べてみたのですが、理由は以下のようでした。

スーパーグローバル変数は、変更可能な変数であるため、直接アクセスすべきではない。

利便性も良いので、filter_input()を利用することは嫌ではないのですが、警告内容に納得がいっていません。

スーパーグローバル変数に直接アクセスしない方がいい理由とはなんなんでしょうか?
できれば具体的な内容も交えて説明いただけると助かります。
少しとんがった回答でもありがたいです。よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+6

$_GETなどに限らず、グローバル変数を多用することは、コードを密結合にしてしまいます。

たとえば、あるメソッドのユニットテストをするとしたときに、「リクエストパラメータは$request引数で渡す」としておけば、その$requestさえ差し替えればうまくテストができます。

一方で、$_GETに依存するままコードを書いていると、$_GETを差し替えるという荒技を取らなければテストできませんし、さらに「$_GETを書き換える」ことで動作するようなコードがあった場合、うまく動作しなくなってしまいます。

実際、フレームワークでも、スーパーグローバルをラッピングして、インスタンスメソッドとして実装していることが、よくあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/29 13:21 編集

    コードを疎結合にするために、スーパーグローバルを直接触らないようにするのですね。非常に理解が進みました。ありがとうございます。

    もう少し教えてください。

    (User Contributed Notes からの抜粋です)
    $b = isset($_GET['b']) && is_string($_GET['b']) ? $_GET['b'] : '';

    $b = (string)filter_input(INPUT_GET, 'b');
    は同意義であると認識しています。

    この場合、結合レベルは変わらないのではないかと思いますが、スーパーグローバルをラッピングした filter_input() を利用する意味合いはあるのでしょうか?

    キャンセル

  • 2017/01/29 13:26

    filter_input()を使った場合、スーパーグローバルの$_GETや$_POSTではなく、本当にHTTPで投げられた値を元に結果を返します。

    何かしらのライブラリやバグなどで$_GETが書き換わっても、filter_input()は影響しません。つまり、filter_input()の返り値は、他のプログラムから影響されることはありません。

    キャンセル

  • 2017/01/29 13:34 編集

    filter_input() は、スーパーグローバルの $_GET や $_POST を参照すると勝手に勘違いしていました。。。大元の HTTP のヘッダを参照するのですね。

    ありがとうございました!

    キャンセル

+3

推奨されない理由はスーパーグローバル変数だからではなく変更可能なグローバル変数だからだと思われます。これはPHPだけではなく、他のプログラミング言語においてもグローバル変数はなるべく使用すべきでは無いとされています。

グローバル変数が使うべきでは無いという理由は、複数のモジュールやライブラリを呼び出すようなある程度の規模があるプログラムでは管理が難しくなるからです。

実際のアプリケーションを作成するとき、簡単なツールでなければ、機能の増加に伴いプログラムはどんどん大きくなっていきます。やがて一つのソースコードで管理することは不可能になります。そこで行うのはファイルの分割です。それぞれの機能を複数のファイルに分けて管理しやすくします。この時点でグローバル変数の扱いが難しくなります。いま書いているファイルとは別のファイルでグローバル変数を書き替えていた場合はどうなるでしょうか?また、実は名前が被っていてうまく動かなかったらどうなるでしょうか?ファイル間で同じグローバル変数を全く別の用途に使っていれば、きっと予想もしない動作をすることになるでしょう。

具体例を見てみましょう。呼び出す度に1ずつカウントしていく関数f()を作成し、別のファイルother.phpとして用意したとします。other.phpのドキュメントには「関数f()は呼び出す度に1から1ずつカウントする関数」と書いておきましょう。

other.php

<?php
$x = 1;
function f() {
  global $x;
  return $x++;
}

では、メイン側であるmain.phpで使ってみましょう。

main.php

<?php
require_once('other.php');
$x = 2;
var_dump(f());
var_dump($x);

果たしてこれは期待通りの動作でしょうか?main.phpをコーディングしているときにother.phpのソースコードは見ません。参考にするのはother.phpに関する「関数f()は呼び出す度に1から1ずつカウントする関数」という情報だけです。しかし、実際はグローバル変数$xの名前が被っているため、カウントは2から始まってしまいますし、$xも3になってしまっています。このような動作を変数汚染といい、グローバル変数は最も汚染されやすい変数です。

この例は単純なため、一つのファイルにすれば問題ないと思うかも知れません。しかし、実際はもっとたくさんの処理が入るため、適切にファイルを分割しないと難しくなります。ファイルを分割すると、今度はグローバル変数が同じだった場合に問題が起きてしまうため、グローバル変数はコード全体を通してなるべく使うべきではありません。

さらに規模が大きくなると、プログラム全体をモジュール化して、ライブラリとして使用するようになります。よく使うような機能はライブラリとして分離しておくと再利用することも可能ですし、そのようなライブラリが多く公開されていて、誰でも利用できるようになっています。しかし、ライブラリのソースコードを一つ一つ見てから使用するには非現実的です。実際はライブラリのドキュメント、つまり「関数f()は呼び出す度に1から1ずつカウントする関数」のような情報だけを参考にライブラリを使用することになります。

もし、ライブラリが上のような作りだった場合はどうなるでしょうか?ましてや、自分が作ったのでは無い誰かが作って公開しているライブラリを使う場合はどうなるでしょうか?もはや、安全にグローバル変数を使うことはできません。どのような動作をするのか予測することができなくなり、重大なバグのきっかけとなることでしょう。

実際の所、ライブラリの作者達はそのような危険性を知っているため、行儀の良いライブラリはグローバル変数を使うことが全く無いか、グローバル変数を使う場合は、ライブラリのドキュメントに明記しています。

話は変わってスーパーグローバル変数について考えましょう。$_POSTはPHP開発者であればスーパーグローバル変数であることはわかっているはずです。まさか、それを変更しようなどと言う人はいない…と思いたいところがそうでもありません。例えばPOSTで渡されたファイルを自動的に判断して便利になるように書きかえるようなライブラリを作ったとします。ファイルのエンコードを自動判断して、Shift_JISやEUC-JP等であったら、UTF-8に書きかえておくなんてあると便利だと思いませんか?ライブラリを使っても使わなくても便利なように$_POSTを書きかえておけばさらに便利だと思いませんか?もちんろ、グローバルへ数が汚染されてしまいますので、そのようなことはすべきではありません。しかし、自分が作った物ではないライブラリではそのような行儀が悪い実装をしている可能性があります。むしろ、自分が昔作ったライブラリでそのような行儀が悪い実装をしてしまっているかもしれません。そのようなときに、$_POSTを使おうとしたら、きっと予測ができない動作が起きてしまうかも知れません。

このように、グローバル変数はなるべく使うべきではありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/29 13:31

    回答ありがとうございます。頂いた回答でかなり理解が進んだと思います。

    変更可能なグローバル変数であるから、その値を利用するときは、直接記述せず、書き換え機能のない読み込みだけの制限された関数 filter_input を使用する事を推奨するのですね。

    キャンセル

+3

maisumakun さんと raccy さんの回答で非常に理解が進みました。
スーパーグローバル変数に直接アクセスしない方がいい理由に関して、以下の通り理解したのでまとめておきます。

書き換え可能なグローバル変数を利用しない
プログラムを疎結合とするため。疎結合であるべき理由はググれ。

filter_input関数を利用する理由
filter_input関数はスーパーグローバル変数のただの代替ではない。

<?php
//test.php?a=a
echo $_GET['a'] ;//a

$_GET['a'] = 'b';
echo $_GET['a'] ;//b

echo filter_input(INPUT_GET, 'a');//a


直接 HTTP header から値を取ってくるため、グローバル変数が変更されても影響を受けない。結果、めっちゃ疎。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

$_GET$_POSTなどにはユーザからの入力が入っています。
この入力には悪意のあるものが入っているかもしれません。
仮にJavaScriptでチェックしてあっても容易に回避できるので
信用してはいけません。

悪い例として、

$str = isset($_POST['str']) ? $_POST['str'] : '';


で取得した$strを他の利用者の画面にそのまま表示したとします。

$str

<script type="text/javascript">
// 悪意のあるJavaScript
</script>


のようなものが入っていた場合、そのままJavaScriptとして実行されてしまいますので、
<&lt;に変えるなどの処理が必要になります。

以上のような処理が必要であることを気づかせるための警告だと認識しています。

スーパーグローバル変数に直接アクセスしていても、
自分でちゃんとチェックしていれば無視してもいいと思います。

参考:Improve Your Code With New Hints

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/29 11:00

    世に言われている 'スーパーグローバル変数は、変更可能な変数であるため、直接アクセスすべきではない。' なんて意味のない戯言なので無視しちゃってイイよ。ってことでしょうか?

    リンク先見ても確かに
    > Everyone knows superglobals, but not everyone knows that superglobal arrays shouldn't be accessed directly. Never ever trust to user inputs. Every user input should be somehow filtered/validated. And that's why this hint was created :-)
    と警告内容とはずれた内容が記載されているので、たしかに戯言感が強いですが、逆になぜこんな言葉が世に広まっているのか気になります。ご存知ですか?

    蛇足ですが、「should be somehow filtered/validated. 」は変数を出力することに対してのフィルタを指してはいないので、回答にある「以上のような処理が必要であることを気づかせるための警告」では無いかと。この場合、私が書いた「isset()」の部分で、型チェックや文言チェックを含めてちゃんと入力値の正しさの確認をやりなさいよ。ということだと思います。

    キャンセル

同じタグがついた質問を見る

  • PHP

    21373questions

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

  • POST

    242questions

    POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

  • Cookie

    197questions

    HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

  • GET

    96questions

    GETとはHTTPが対応するリクエストメソッドの一つです。クライアントからサーバーへ送られたURLパラメータのデータを取得する時必要がある時に使われます。