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

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

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

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

GET

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

POST

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

PHP

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

Q&A

解決済

4回答

24350閲覧

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

退会済みユーザー

退会済みユーザー

総合スコア0

Cookie

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

GET

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

POST

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

PHP

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

6グッド

17クリップ

投稿2017/01/28 23:16

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

php

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

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

php

1$str = $_POST['str'];

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

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

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

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

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

ningen, Reoh, KiyoshiMotoki, ruuusaamarki, tokkun01, gsuisk👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

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

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

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

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

投稿2017/01/29 03:22

maisumakun

総合スコア145495

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

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

退会済みユーザー

退会済みユーザー

2017/01/29 04:23 編集

コードを疎結合にするために、スーパーグローバルを直接触らないようにするのですね。非常に理解が進みました。ありがとうございます。 もう少し教えてください。 (User Contributed Notes からの抜粋です) $b = isset($_GET['b']) && is_string($_GET['b']) ? $_GET['b'] : ''; と $b = (string)filter_input(INPUT_GET, 'b'); は同意義であると認識しています。 この場合、結合レベルは変わらないのではないかと思いますが、スーパーグローバルをラッピングした filter_input() を利用する意味合いはあるのでしょうか?
maisumakun

2017/01/29 04:26

filter_input()を使った場合、スーパーグローバルの$_GETや$_POSTではなく、本当にHTTPで投げられた値を元に結果を返します。 何かしらのライブラリやバグなどで$_GETが書き換わっても、filter_input()は影響しません。つまり、filter_input()の返り値は、他のプログラムから影響されることはありません。
退会済みユーザー

退会済みユーザー

2017/01/29 05:10 編集

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

0

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

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

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

php

1<?php 2//test.php?a=a 3echo $_GET['a'] ;//a 4 5$_GET['a'] = 'b'; 6echo $_GET['a'] ;//b 7 8echo filter_input(INPUT_GET, 'a');//a 9

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

投稿2017/01/29 05:10

編集2017/01/29 05:14
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2020/11/09 23:32

久しぶりに読み返しましたが、「めっちゃ疎」って表現は微妙ですね^^; あと、filter_input() はテストしにくいので、検証フィルタはなるべく軽いものを選択し、厳密なバリデーションは別途するのが良さげ。
guest

0

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

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

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

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

other.php

PHP

1<?php 2$x = 1; 3function f() { 4 global $x; 5 return $x++; 6}

では、メイン側である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 03:59

raccy

総合スコア21735

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

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

退会済みユーザー

退会済みユーザー

2017/01/29 04:31

回答ありがとうございます。頂いた回答でかなり理解が進んだと思います。 変更可能なグローバル変数であるから、その値を利用するときは、直接記述せず、書き換え機能のない読み込みだけの制限された関数 filter_input を使用する事を推奨するのですね。
guest

0

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

悪い例として、

php

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

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

$str

html

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

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

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

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

参考:Improve Your Code With New Hints

投稿2017/01/29 00:55

bash_sh

総合スコア30

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

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

退会済みユーザー

退会済みユーザー

2017/01/29 02: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()」の部分で、型チェックや文言チェックを含めてちゃんと入力値の正しさの確認をやりなさいよ。ということだと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.42%

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

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

質問する

関連した質問