Удалить все элементы массива, кроме того, что я хочу?
У меня есть контроллер, который принимает пост-параметры из формы HTML, затем отправляет их в модель, которая будет вставлять массив в базу данных Cassandra.
Это доказательство SQLInjection, потому что это NoSQL, однако я боюсь, что пользователь может просто имитировать 100 000 пост-параметров или просто добавить некоторые, которые мне не нужны, и он будет вставлен в базу данных. Как я могу убедиться, что только мои значения останутся в моем массиве.
Пример:
$post = ['parent_id', 'type', 'title', 'body', 'tags']; // Good
$post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'] // Bad
Как я могу убедиться, что мой массив отключит все элементы, которые не в хорошем примере?
Ответы
Ответ 1
Вы ищете array_intersect
:
$good = ['parent_id', 'type', 'title', 'body', 'tags'];
$post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'];
print_r(array_intersect($good, $post));
Посмотрите на действие.
Конечно, этот конкретный пример не имеет большого смысла, потому что он работает с значениями массива, но есть также array_intersect_key
, который делает то же самое на основе ключей.
Ответ 2
Переименовав записи, вы ожидаете do.
<?php
$post = array(
'parent_id' => 1,
'type' => 'foo',
'title' => 'bar',
'body' => 'foo bar',
'tags' => 'foo, bar',
'one' => 'foo',
'two' => 'bar',
'three' => 'qux'
);
$whitelist = array(
'parent_id',
'type',
'title',
'body',
'tags'
);
$filtered = array_intersect_key( $post, array_flip( $whitelist ) );
var_dump( $filtered );
Во всяком случае, использование Cassandra в качестве хранилища данных, конечно, не является основанием для того, чтобы не выполнять валидацию данных, которые вы получаете.
Ответ 3
Использовать пересечение массива. массив пересекает, это поможет вам.
Ответ 4
Это будет выводиться так же, как $post_allowed. То, что он делает, это разрешить только значения в $post_input, которые также присутствуют в $post_allow.
$post_allowed = ['parent_id', 'type', 'title', 'body', 'tags'];
$post_input = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'];
$post = array_intersect($post_input, $post_allowed);
Ответ 5
Это называется белым листингом, ваш пример вводит в заблуждение, так как $_POST
является массивом ассоциаций.
$post = [
'parent_id' => 'val',
'type' => 'val',
'title' => 'val',
'body' => 'val',
'tags' => 'val',
'one' => 'val',
'two' => 'val',
'three'=>'val',
];
$whitelist = ['parent_id', 'type', 'title', 'body', 'tags'];
$sanitized_post = array_whitelist_assoc($post, $whitelist);
Это функция "белый список", созданная для ассоциативных массивов.
if(!function_exists('array_whitelist_assoc')){
/**
* Returns an associative array containing all the entries of array1 which have keys that are present in all the arguments when using their values as keys.
*
* @param array $array The array with master keys to check.
* @param array $array2 An array to compare keys against its values.
* @return array $array2,... A variable list of arrays to compare.
*
*/
function array_whitelist_assoc(Array $array1, Array $array2) {
if(func_num_args() > 2){
$args = func_get_args();
array_shift($args);
$array2 = call_user_func_array('array_merge', $args);
}
return array_intersect_key($array1, array_flip($array2));
}
}
Ответ 6
Если вы работаете с ассоциативными массивами, и по какой-либо причине вы не хотите использовать array_intersect_key()
, вы также можете сделать более простой подход для создания нового массива вручную, используя значения, которые вы хотите от старого.
$post = array(
'parent_id' => 1,
'type' => "post",
'title' => "Post title",
'body' => "Post body",
'tags' => "Post tags",
'malicious' => "Robert'); DROP TABLE students;--"
);
$good = array(
'parent_id' => $post['parent_id'],
'type' => $post['type'],
'title' => $post['title'],
'body' => $post['body'],
'tags' => $post['tags']
);
Ответ 7
Как насчет многомерного массива? Я был исследован на пару часов для этого решения, нигде не нашел оптимального решения. поэтому, я написал это сам
function allow_keys($arr, $keys)
{
$saved = [];
foreach ($keys as $key => $value) {
if (is_int($key) || is_int($value)) {
$keysKey = $value;
} else {
$keysKey = $key;
}
if (isset($arr[$keysKey])) {
$saved[$keysKey] = $arr[$keysKey];
if (is_array($value)) {
$saved[$keysKey] = allow_keys($saved[$keysKey], $keys[$keysKey]);
}
}
}
return $saved;
}
использовать: пример
$array = [
'key1' => 'kw',
'loaa'=> ['looo'],
'k' => [
'prope' => [
'prop' => ['proo', 'prot', 'loolooo', 'de'],
'prop2' => ['hun' => 'lu'],
],
'prop1' => [
],
],
];
вызов: пример
allow_keys($array, ['key1', 'k' => ['prope' => ['prop' => [0, 1], 'prop2']]])
выход:
Array ( [key1] => kw [k] => Array ( [prope] => Array ( [prop] => Array ( [0] => proo [1] => prot ) [prop2] => Array ( [hun] => lu ) ) ) )
поэтому вы получаете только нужные ключи из многомерного массива. он не ограничивается только "многомерным", вы можете использовать его, передав массив вроде
['key1', 'loaa']
вы получаете:
Array ( [key1] => kw [loaa] => Array ( [0] => looo ) )
ура!
Ответ 8
Стоит вспомнить, что, хотя array_intersect
и array_intersect_key
хороши, они вполне могут быть переполнены. В моей ситуации я хотел только 1 элемент слева, поэтому самым простым вариантом было просто перестроить массив, который я хотел, на основе ключа/значений, которые мне нужны. Интересно, в какой момент массив array_intersect не стоит того, и вам просто лучше с $new = array('whatI'=>'want');
. Я верю в ОП, это того стоит, но в меньших случаях это может быть излишним.
В качестве альтернативы в ответ на исходный вопрос просто использование unset
возможно, было более дешевым вариантом - unset($post['one'],$post['two'],$post['three'])
. Опять же, это относится к точке, в которой это становится слишком неэффективным, и функции array_intersect лучше.