Подтвердить что ты не робот

Что не так с extract()?

Недавно я читал эту тему, о некоторых из худших практик PHP. Во втором ответе есть мини-дискуссия об использовании extract(), и им просто интересно, о чем идет речь.

Я лично использую его для измельчения заданного массива, такого как $_GET или $_POST, где я потом дезактивирую переменные, так как они были удобно названы для меня.

Это плохая практика? В чем здесь риск? Каковы ваши мысли об использовании extract()?

4b9b3361

Ответ 1

Я нахожу, что это только плохая практика, потому что это может привести к ряду переменных, которые будущие сопровождающие (или вы сами в течение нескольких недель) понятия не имеете, откуда они идут. Рассмотрим этот сценарий:

extract($someArray); // could be $_POST or anything

/* snip a dozen or more lines */

echo $someVariable;

Откуда взялся $someVariable? Как может кто-нибудь сказать?

Я не вижу проблемы с доступом к переменным из массива, в котором они запускались, поэтому вам действительно нужно представить хороший пример использования extract(), чтобы я подумал, что это того стоит. Если вы действительно обеспокоены типизацией некоторых дополнительных символов, просто выполните это:

$a = $someLongNameOfTheVariableArrayIDidntWantToType;

$a['myVariable'];

Я думаю, что комментарии здесь по аспектам безопасности несколько раздуты. Функция может принимать второй параметр, который фактически дает вам достаточно хороший контроль над вновь созданными переменными, в том числе не переписывая любые существующие переменные (EXTR_SKIP), ТОЛЬКО перезаписывая существующие переменные (чтобы вы могли создать белый список) (EXTR_IF_EXISTS), или добавление префиксов к переменным (EXTR_PREFIX_ALL).

Ответ 2

Давай. Люди обвиняют инструмент вместо пользователя.

Это нравится говорить с unlink(), потому что вы можете удалять с ним файлы. extract() - это функция, как и любая другая, используйте ее мудро и ответственно. Но не утверждайте, что это плохо как таковое, это просто невежество.

Ответ 3

риск: не доверять данным от пользователей, а извлечение из текущей таблицы символов означает, что ваши переменные могут быть перезаписаны тем, что предоставляет пользователь.

<?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 перезаписываются, в результате ваш script сначала удаляет ваши данные и висит.

Ответ 4

В этом нет ничего плохого. В противном случае это не будет реализовано. Многие (MVC) фреймворки используют его, когда вы передаете (присваиваете) переменные Views. Вам просто нужно использовать его осторожно. Санируйте эти массивы, прежде чем передавать их для извлечения() и убедитесь, что они не переопределяют ваши переменные. Не забывайте, что эта функция также принимает еще несколько аргументов! Используя второй и третий аргументы, вы можете контролировать поведение, если происходит столкновение. Вы можете переопределить, пропустить или добавить префикс. http://www.php.net/extract

Ответ 5

Если он не используется тщательно, он может смутить черт из других, с которыми вы работаете:

<?php

    $array = array('huh' => 'var_dump', 'whatThe' => 'It\ tricky!', 'iDontGetIt' => 'This Extract Function');
    extract($array);
    $huh($whatThe, $iDontGetIt);


?>

Доходность:

string(12) "It tricky!"
string(21) "This Extract Function"

Было бы полезно использовать в обфускации. Но я не могу преодолеть "Откуда взялся этот вар?" проблема, с которой я сталкиваюсь.

Ответ 6

Люди получают все о том, как извлечь выгоду из-за того, что они могут быть использованы неправильно. Выполнение чего-то вроде extract ($ _ POST) не является хорошей идеей в любом случае, даже если вы знаете, что делаете. Тем не менее, он использует его, когда вы делаете такие вещи, как выставление переменных в шаблон представления или что-то подобное. В основном, используйте его только в том случае, если вы очень уверены в том, что у вас есть веские основания для этого, и поймите, как использовать параметр типа extract, если у вас есть идея передать что-то сумасшедшее, как $_POST.

Ответ 7

Я думаю, причина, по которой многие люди не рекомендуют использовать ее, заключается в том, что экстракты $_GET и $_POST (даже $_REQUEST) суперглобальные регистры регистрируют переменные в глобальном пространстве имен с тем же именем, что и каждый ключ в этих массивах, который в основном эмулирует REGISTER_GLOBALS = 1.

Ответ 8

Я позволю PHP-руководству поговорить для меня.

Фон: extract($_REQUEST) совпадает с настройкой register_globals = On в php.ini

Ответ 9

Если вы извлечете из функции, переменные будут доступны только в этой области. Это часто используется в представлениях. Простой пример:

//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_defined_vars(); после включения для запуска кода с определенными переменными и получения результата для использования со старым PHP-кодом.

Ответ 10

Риск такой же, как у register_globals. Вы разрешаете злоумышленнику устанавливать переменные в script, просто путем вмешательства в запрос.

Ответ 11

Никогда не извлекайте ($ _ 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>'
));

Ответ 12

Как кто-то отметил в другом потоке, вот более безопасный способ использования extract, только позволяя ему извлекать указанные вами переменные, вместо всего, что содержит массив.

Это служит двойной цели для документирования того, какие переменные выходят из него, поэтому отслеживание переменной не так сложно.

Ответ 13

Каждое использование метода может привести к некоторым условиям, где это может быть точкой отказа для приложения. Я лично считаю, что extract() не следует использовать для ввода пользователем (что не предсказуемо) и для данных, которые не подвергаются дезинфекции.

Даже основной код CodeIgniter использует извлечение, поэтому при использовании метода не должно быть вреда, если данные дезинфицируются и обрабатываются хорошо.

Я использовал экстракт в моделях CodeIgniter с переключателем EXTR_IF_EXISTS и ограничил количество переменных, он работает очень хорошо.

Ответ 14

Экстракт безопасен до тех пор, пока вы его используете безопасным образом. То, что вы хотите сделать, - это фильтровать ключи массива только теми, которые вы собираетесь использовать, и, возможно, проверить, что все эти ключи существуют, если ваш сценарий требует их существования.

#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'])
));

Ответ 15

Помните, что extract() небезопасно, если вы работаете с пользовательскими данными (например, результаты запросов), поэтому лучше использовать эту функцию с флагами EXTR_IF_EXISTS и EXTR_PREFIX_ALL.

Если вы используете его правильно, безопасно использовать

Ответ 16

Просто немного пояснить предыдущие ответы... Нет ничего плохого в extract(), если вы правильно фильтруете ввод (как уже говорили другие); в противном случае вы можете столкнуться с огромными проблемами безопасности:

<?php

// http://foobar.doo?isLoggedIn=1

$isLoggedIn = (new AdminLogin())->isLoggedIn(); // Let assume this returns FALSE

extract($_GET);

if ($isLoggedIn) {
    echo "Okay, Houston, we've had a problem here.";
} else {
    echo "This is Houston. Say again, please.";
}

Ответ 17

Еще одна важная причина, по которой больше не использовать extract(), заключается в том, что в PHP есть импульс для использования HHVM, который претендует на сделайте PHP примерно в 10 раз быстрее. Facebook (кто это сделал) использует его, Wikipedia на нем, и WordPress, по слухам, смотрит на него.

HHVM не разрешает извлечение()

Это все еще вроде альфа, поэтому это не самая большая проблема