PHP:有没有安全的提取方法($_POST)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5306498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP: is there a safe way to extract($_POST)
提问by superUntitled
Is there a safe way to auto assign the keys in a posted array? Below are two examples of wrong ways...
有没有一种安全的方法来自动分配已发布数组中的键?以下是错误方法的两个示例...
foreach( $_POST as $key => $value ) {
$$key = $value;
}
or
或者
extract($_POST)
Is there a better way, or is it best to code:
有没有更好的方法,或者最好编码:
$foo = $_POST('foo');
$bar = $_POST('bar');
....
for all 50 inputs on my form?
对于我表单上的所有 50 个输入?
(the posted info will be inserted into a database).
(发布的信息将被插入到数据库中)。
回答by mario
One more cautious way of extracting all input fields at once is:
一次提取所有输入字段的一种更谨慎的方法是:
extract( $_POST, EXTR_OVERWRITE, "form_" );
This way all your input variables will be called $form_foo
and $form_bar
at least. Avoid doing that in the global scope - not because global is evil, but because nobody ever cleans up there.
这样,所有的输入变量将被调用$form_foo
,并$form_bar
至少。避免在全局范围内这样做 - 不是因为全局是邪恶的,而是因为没有人会清理那里。
However, since mostly you do that in a localized scope, you can as well apply htmlentities if for example you need all fields just for output:
但是,由于大多数情况下您是在本地化范围内执行此操作,因此您也可以应用 htmlentities,例如,如果您需要所有字段仅用于输出:
extract(array_map("htmlspecialchars", $_POST), EXTR_OVERWRITE, "form_");
回答by Your Common Sense
There is not a single reason to do it.
To handle user inputs an array is 100 times better than separate variables
没有一个理由可以这样做。
为了处理用户输入,数组比单独的变量好 100 倍
回答by davogotland
I like an approach where you let dynamic getters and setters in a class do all the work for you. Here's how I would code it.
我喜欢让类中的动态 getter 和 setter 为您完成所有工作的方法。这是我将如何编码它。
First, create a bass class to hold data:
首先,创建一个bass类来保存数据:
class FormParameterHandler {
protected $parameters;
public function __construct($associative_array) {
$this->parameters = array();
foreach($associative_array as $key => $value) {
$this->{$key} = $value;
}
}
public function __get($key) {
$value = null;
if(method_exists($this, "get_$key")) {
$value = $this->{"get_$key"}();
} else {
$value = $this->parameters[$key];
}
return $value;
}
public function __set($key, $value) {
if(method_exists($this, "set_$key")) {
$this->{"set_$key"}($value);
} else {
$this->parameters[$key] = $value;
}
}
}
Next, create a specific class to use for some specific form where there is something special to validate. Use your freedom as a programmer here to implement it any way you want to. And remember, since we're using reflection to look for setter methods, we can write specific setter methods for known problem areas, like e.g. to check for equal passwords in a "register user" form:
接下来,创建一个特定的类以用于某些需要验证的特殊表单。在这里使用您作为程序员的自由,以任何您想要的方式实现它。请记住,由于我们使用反射来查找 setter 方法,因此我们可以为已知问题区域编写特定的 setter 方法,例如在“注册用户”表单中检查相同的密码:
class RegisterFormParameterHandler extends FormParameterHandler {
private $passwords_are_equal = null;
public function __construct($register_form_parameters) {
parent::__construct($register_form_parameters);
}
public function has_equal_passwords() {
return $this->passwords_are_equal;
}
public function set_password($password) {
$this->parameters['password'] = $password;
$this->compare_passwords();
}
public function set_password_repeat($password_repeat) {
$this->parameters['password_repeat'] = $password_repeat;
$this->compare_passwords();
}
private function compare_passwords() {
if(isset($this->parameters['password']) && isset($this->parameters['password_repeat'])) {
$this->passwords_are_equal = ($this->parameters['password'] === $this->parameters['password_repeat']);
}
}
}
Finally, use the derived class in a "register user" flow, to easily find out if the two entered passwords match:
最后,在“注册用户”流程中使用派生类,轻松找出输入的两个密码是否匹配:
$registerFormParameterHandler = new RegisterFormParameterHandler($_POST);
if($registerFormParameterHandler->has_equal_passwords()) {
print "are equal";
//register user
} else {
print "are not equal";
}
You can test this by creating an HTML form that has one input field with the name "password", and another input field with the name "password_repeat".
您可以通过创建一个 HTML 表单来测试这一点,该表单具有一个名为“password”的输入字段和另一个名为“password_repeat”的输入字段。
To access any of the form data, use your form data object variable name, followed by the access operator "dash larger than" -> , followed by the name of the parameter. In the example above, if there was an input field named "user_name", it would be accessed through a call to
要访问任何表单数据,请使用您的表单数据对象变量名称,后跟访问运算符“破折号大于” -> ,然后是参数名称。在上面的例子中,如果有一个名为“user_name”的输入字段,它将通过调用来访问
$registerFormParameterHandler->user_name
Rr, if you have defined the name of the field you want to get in some other variable, use reflection:
Rr,如果您已经定义了要在其他变量中获取的字段的名称,请使用反射:
$registerFormParameterHandler->{$settings['form_data_user_name']}
Have fun! :)
玩得开心!:)
回答by deceze
A safeway to extract variables into the local scope is not to. You're injecting variables into your local scope, which is a problem however you do it. Even if you limit the variables to only a few select ones that won't clash with other variable names in the scope now, if you start adding elements to your form you may be in trouble later.
将变量提取到局部作用域的安全方法不是将. 您正在将变量注入本地范围,但是您这样做是有问题的。即使你限制变量只有几个选择那些不会在范围与其他变量名称发生冲突,现在,如果你开始将元素添加到您的表格,您可就麻烦了以后。
Arrays are specifically for holding an unlimited amount of named values without crowding the variable namespace. Use them! You may have to type a little more, but that's par for the course.
数组专门用于保存无限数量的命名值,而不会使变量命名空间拥挤。使用它们!您可能需要输入更多内容,但这是课程的标准。
回答by Orbling
While it is best to refer to them with $_POST['variablename']
, it is possible to expand only the variables you are expecting.
虽然最好用 来引用它们$_POST['variablename']
,但也可以只扩展您期望的变量。
$expected = array('name', 'telephone', /* etc */);
foreach ($_POST as $key => $value) {
if (!in_array($key, $expected)) {
continue;
}
${$key} = $value;
}
Or, I prefer this:
或者,我更喜欢这个:
foreach ($_POST as $key => $value) {
switch ($key) {
case 'name':
case 'telephone':
/* etc. */
${$key} = $value;
break;
default:
break;
}
}
回答by Anthony Rutledge
The answer to your question depends on the computer, language, and security knowledge of the programmer. The opening sequence of processing $_POST is kind of like the opening move in a game of chess. Many use foreach
loops without realizing that foreach
will make a copy of the contents of $_POST the way you have it used (Programming PHP: Chapter 5, p.128-129). Wouldn't it be funny if you caused a buffer overflow simply by using foreach
!
您的问题的答案取决于程序员的计算机、语言和安全知识。处理 $_POST 的开局顺序有点像国际象棋中的开局。许多人在使用foreach
循环时没有意识到,它foreach
会按照您使用的方式复制 $_POST 的内容(PHP 编程:第 5 章,第 128-129 页)。如果您只是使用foreach
!
One commenter implied that everything should just be worked with inside of the $_POST
superglobal. There are some merits to this... However, forgetting cache memory for a moment, access to array values is slower than direct access to a variable.
一位评论者暗示,一切都应该在$_POST
超全局内部进行。这有一些优点......但是,暂时忘记缓存,访问数组值比直接访问变量慢。
Since you have fifty (50) controls to validate (with potentially large contents), I might not want to take that array access performance hit more than 50 times (the original access hits). Moreover, if you are concerned about writing secure input validation routines, keeping your dirtylaundry (non-validated input) separate from your clean(validated input) laundry is a good idea. That said, you may need a cleanarray anyway (hence the $_POST advocate's response), but at least you are reducing risk in the process by keeping the hopefully goodseparate from the potentially bad.
由于您有五十 (50) 个控件需要验证(可能包含大量内容),我可能不想让数组访问性能受到超过 50 次(原始访问命中)的影响。此外,如果您担心编写安全输入验证例程,将脏衣服(未验证输入)与干净(验证输入)衣服分开是个好主意。这就是说,你可能需要一个干净的阵列反正(因此$ _ POST倡导的反应),但至少你被保持还原的过程中风险有望好独立于潜在的不良。
Is there a safe way to auto assign the keys in a posted array?
有没有一种安全的方法来自动分配已发布数组中的键?
I might start like this:
我可能是这样开始的:
Function library for this example.
本例的函数库。
function all_controls_submitted($controls) {
$postKeys = array_keys($_POST);
foreach($controls as $key) {
if(! array_key_exists($key, $postKeys)) {
return false;
}
}
return true;
}
function all_controls_set($controls) {
foreach($controls as $key) {
if(! isset($_POST[$key])) {
return false;
}
}
return true;
}
if(is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER[REQUEST_URI]) && $_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = true;
} elseif (is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/contact.php') {
$newForm = false;
$controlNames = array('firstName', 'lastName', 'e-mail', 'company', 'subject', 'message', 'captcha');
define('NUM_CONTROLS_EXPECTED', count($controlNames)); //Seven (7)
if(is_array($_POST) && count($_POST) === NUM_CONTROLS_EXPECTED && all_controls_submitted($controlNames) && all_controls_set($controlNames)) {
//Begin input validation
}
} else {
header('location: http://www.nsa.gov');
}
Notice that I prep things with the $controlNames
array, therefore I do not have to ask $_POST
for the keys. After all, I should know them! :-) The two user-defined functions, all_controls_submitted()
and all_controls_set()
are two fundamental questions that should be asked before trying to use any values in $_POST
(I say, anyway). Admittedly, I do use $_POST
in all_controls_submitted()
, but only to obtain the names of the controls submitted, not the values.
请注意,我用$controlNames
数组准备了一些东西,因此我不必要求$_POST
密钥。毕竟,我应该认识他们!:-)两个用户自定义功能,all_controls_submitted()
而且all_controls_set()
是应该尝试使用任何值前,问了两个基本问题$_POST
(我说了,反正)。诚然,我确实使用$_POST
in all_controls_submitted()
,但只是为了获取提交的控件的名称,而不是值。
$postKeys = array_keys($_POST);
However, who is to say that the control names themselves could not be poisonous and in need of input validation?!! Same goes for values in $_SERVER. See, a chess game.
但是,谁说控件名称本身就不会有毒并且需要输入验证?!$_SERVER 中的值也是如此。看,一盘棋。
Is there a safe way to auto assign the keys in a posted array? I cannot tell you for certain, but perhaps something like the code above could help? You'd have the keys, at least.
有没有一种安全的方法来自动分配已发布数组中的键?我不能肯定地告诉你,但也许上面的代码会有所帮助?至少你有钥匙。
Programming PHP: Chapter 5, p.125
PHP 编程:第 5 章,第 125 页
回答by Mahesh
Try this inbuilt method/function filter_input
试试这个内置的方法/函数filter_input
Reference URL: php.net function filter input
参考网址:php.net 函数过滤输入