質問
最近読んでいたのは このスレッド, 、最悪の PHP プラクティスのいくつかについて。2 番目の回答には、の使用に関するミニディスカッションがあります。 extract()
, 、そして私はただ、このハフとは何なのか疑問に思っています。
私は個人的に、次のような特定の配列を分割するためにそれを使用しています $_GET
または $_POST
ここで、変数には便宜的に名前が付けられているので、後でその変数をサニタイズします。
これは悪い習慣ですか?ここでのリスクは何ですか?の使用についてどう思いますか extract()
?
解決
これは、将来のメンテナー(または数週間のうちにあなた自身)がどこから来たのか分からない多くの変数につながる可能性があるという点で、悪い習慣であることがわかります。このシナリオを考慮してください:
extract($someArray); // could be これは、将来のメンテナー(または数週間のうちにあなた自身)がどこから来たのか分からない多くの変数につながる可能性があるという点で、悪い習慣であることがわかります。このシナリオを考慮してください:
$a = $someLongNameOfTheVariableArrayIDidntWantToType;
$a['myVariable'];
$ someVariable
はどこから来たのですか?誰に伝えることができますか?
変数が開始された配列内から変数にアクセスすることに問題はないので、 extract()を使用して for の良いケースを提示する必要がありますコード>私はそれが価値があると思う。余分な文字を入力することが本当に心配な場合は、次のようにします。
<*>
ここでのセキュリティ面に関するコメントは、いくぶん誇張されていると思います。関数は、既存の変数を上書きしない( EXTR_SKIP
)、既存の変数のみを上書きする(ホワイトリストを作成できる)など、新しく作成された変数を実際にかなり適切に制御する2番目のパラメーターを取ることができます( EXTR_IF_EXISTS
)、または変数にプレフィックスを追加( EXTR_PREFIX_ALL
)。
POST or anything
/* snip a dozen or more lines */
echo $someVariable;
$ someVariable
はどこから来たのですか?誰に伝えることができますか?
変数が開始された配列内から変数にアクセスすることに問題はないので、 extract()を使用して for の良いケースを提示する必要がありますコード>私はそれが価値があると思う。余分な文字を入力することが本当に心配な場合は、次のようにします。
ここでのセキュリティ面に関するコメントは、いくぶん誇張されていると思います。関数は、既存の変数を上書きしない( EXTR_SKIP
)、既存の変数のみを上書きする(ホワイトリストを作成できる)など、新しく作成された変数を実際にかなり適切に制御する2番目のパラメーターを取ることができます( EXTR_IF_EXISTS
)、または変数にプレフィックスを追加( EXTR_PREFIX_ALL
)。
他のヒント
さあ、どうぞ。ユーザーの代わりにツールを非難します。
これは unlink()
と話しているようなものです。ファイルを削除できるからです。 extract()
は他の関数と同様の関数であり、賢明かつ責任を持って使用してください。しかし、それ自体が悪いと主張しないでください。それは単に無知です。
リスクは次のとおりです。ユーザーからのデータを信頼しないでください。また、現在のシンボル テーブルに抽出するということは、ユーザーが提供したものによって変数が上書きされる可能性があることを意味します。
<?php
$systemCall = 'ls -lh';
$i = 0;
extract($_GET);
system($systemCall);
do {
print_r($data[$i];
$i++;
} while ($i != 3);
?>
(ナンセンスな例)
しかし今度は、コードを推測または知っている悪意のあるユーザーが次のように呼び出します。
yourscript.php?i=10&systemCall=rm%20-rf
の代わりに
yourscript.php?data[]=a&data[]=b&data[]=c
現在、$systemCall と $i が上書きされるため、スクリプトが最初にデータを削除し、その後ハングします。
これには何の問題もありません。それ以外の場合は実装されません。多くの(MVC)フレームワークは、変数をビューに渡す(割り当てる)ときに使用します。慎重に使用する必要があります。 extract()に渡す前にこれらの配列をサニタイズし、変数をオーバーライドしないことを確認してください。この関数はさらにいくつかの引数も受け入れることを忘れないでください! 2番目と3番目の引数を使用すると、衝突が発生した場合の動作を制御できます。プレフィックスを上書き、スキップ、または追加できます。 http://www.php.net/extract
慎重に使用しないと、検討している他のユーザーの混乱を招く可能性があります。
<?php
$array = array('huh' => 'var_dump', 'whatThe' => 'It\'s tricky!', 'iDontGetIt' => 'This Extract Function');
extract($array);
$huh($whatThe, $iDontGetIt);
?>
収量:
string(12) "It's tricky!"
string(21) "This Extract Function"
難読化で使用すると便利です。しかし、「その変数はどこから来たのですか?」私が遭遇する問題。
誤用される可能性のある可能性があるため、人々は抽出物についてすべての準備を整えています。 extract($ _ POST)のような処理を行うことは、何をしているのかを知っていても、どのような場合でも良い考えではありません。ただし、変数をビューテンプレートまたは類似のものに公開するようなことをしているときは、その用途があります。基本的に、使用する正当な理由があることが確実な場合にのみ使用し、$ _ POSTのようなおかしなものを渡すという考えが得られた場合に抽出タイプパラメータを使用する方法を理解します。
多くの人が使用を推奨しない理由は、 $ _ GET
と $ _ POST
( $ _ REQUEST
でも) )スーパーグローバルは、これらの配列内の各キーと同じ名前でグローバル名前空間に変数を登録します。これは基本的にREGISTER_GLOBALS = 1をエミュレートしています。
関数内で抽出する場合、変数はそのスコープ内でのみ使用可能になります。これはビューでよく使用されます。簡単な例:
//View.php
class View {
function render($filename = null) {
if ($filename !== null) {
$this->filename = $filename;
}
unset($filename);
extract($this->variables);
ob_start();
$this->returned = include($this->dir . $this->filename);
return ob_get_clean();
}
}
//test.php
$view = new View;
$view->filename = 'test.phtml';
$view->dir = './';
$view->variables = array('test' => 'tset');
echo $view->render('test.phtml');
var_dump($view->returned);
//test.phtml
<p><?php echo $test; ?></p>
いくつかの代替ディレクトリを使用して、ファイルが存在するかどうかを確認し、変数とメソッドを定義することで、Zend_View をほぼ複製することができます。
追加することもできます $this->outVariables = get_define_vars(); include の後に、特定の変数を使用してコードを実行し、古い PHP コードで使用するためにこれらの結果を取得します。
Extractは、安全に使用する限り安全です。実行するのは、使用する予定のキーのみに配列のキーをフィルターし、シナリオでそれらのキーの存在が必要な場合にそれらのキーがすべて存在することを確認することです。
#Extract only the specified keys.
$extract=array_intersect_key(
get_data()
,$keys=array_flip(['key1','key2','key3','key4','key5'])
);
#Make sure all the keys exist.
if ($missing=array_keys(array_diff_key($keys,$extract))) {
throw new Exception('Missing variables: '.implode(', ',$missing));
}
#Everything is good to go, you may proceed.
extract($extract);
または
#If you don't care to check that all keys exist, you could just do this.
extract(array_intersect_key(
get_data()
,array_flip(['key1','key2','key3','key4','key5'])
));
リスクはregister_globalsと同じです。リクエストを改ざんするだけで、攻撃者がスクリプトに変数を設定できるようにします。
グローバルスコープでextract($ _ GET)を実行しないでください。それ以外にも、(潜在的に)多くのオプションの引数を持つことができる関数を呼び出すなど、その用途があります。
これは、WordPress開発者に漠然と馴染みがあるはずです:
function widget (Array $args = NULL)
{
extract($args);
if($before_widget) echo $before_widget;
// do the widget stuff
if($after_widget) echo $after_widget;
}
widget(array(
'before_widget' => '<div class="widget">',
'after_widget' => '</div>'
));
別のスレッドで誰かが指摘したように、こちらがより安全な方法です配列に含まれるすべてではなく、指定した変数のみを抽出できるようにすることで、extract を使用します。
これは、どの変数がそれから出てくるかを文書化するという二重の目的に役立つので、変数の追跡はそれほど難しくありません。
すべてのメソッドの使用は、アプリケーションの障害点になる可能性があるいくつかの条件につながる可能性があります。 個人的には、extract()はユーザー入力(予測不可能)およびサニタイズされていないデータには使用しないでください。
CodeIgniterのコアコードでも抽出を使用しているため、データが適切にサニタイズされ、適切に処理されれば、メソッドを使用しても問題はありません。
EXTR_IF_EXISTSスイッチを使用してCodeIgniterモデルで抽出を使用し、変数の数を制限しましたが、かなりうまく機能します。
extract()
は、ユーザーデータ(要求の結果など)で作業している場合は安全ではないことに注意してください。したがって、 EXTR_IF_EXISTS
および EXTR_PREFIX_ALL
。
正しく使用すれば、安全に使用できます
以前の回答について少し説明するために...(他の人が述べているように)入力を正しくフィルタリングする限り、extract()に問題はありません。そうしないと、次のような大きなセキュリティ問題が発生する可能性があります。
<?php
// http://foobar.doo?isLoggedIn=1
$isLoggedIn = (new AdminLogin())->isLoggedIn(); // Let's assume this returns FALSE
extract(以前の回答について少し説明するために...(他の人が述べているように)入力を正しくフィルタリングする限り、extract()に問題はありません。そうしないと、次のような大きなセキュリティ問題が発生する可能性があります。
<*>GET);
if ($isLoggedIn) {
echo "Okay, Houston, we've had a problem here.";
} else {
echo "This is Houston. Say again, please.";
}
extract()を使用しないもう1つの理由は、PHPに HHVM を使用する勢いがあることです。 PHPを約10倍高速化すると主張しています。 Facebook(作成者)はそれを使用しており、Wikipediaはそれを使用しており、WordPressはそれを見ていると噂されています。
まだアルファのようなものなので、最大の懸念ではありません