Вопрос

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

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

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

Это было полезно?

Решение

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

extract($someArray); // could be 

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

$a = $someLongNameOfTheVariableArrayIDidntWantToType;

$a['myVariable'];

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

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

<*>

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

POST or anything /* snip a dozen or more lines */ echo $someVariable;

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

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

<*>

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

Другие советы

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

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

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

<?php
    $systemCall = 'ls -lh';
    $i = 0;

    extract(

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

yourscript.php?i=10&systemCall=rm%20-rf

(бессмысленный пример)

но теперь злонамеренный пользователь, который угадывает или знает код, вызывает:

yourscript.php?data[]=a&data[]=b&data[]=c

вместо

<*>

теперь $ systemCall и $ i перезаписываются, в результате чего ваш скрипт сначала удаляет ваши данные, а затем зависает.

GET); system($systemCall); do { print_r($data[$i]; $i++; } while ($i != 3); ?>

(бессмысленный пример)

но теперь злонамеренный пользователь, который угадывает или знает код, вызывает:

<*>

вместо

<*>

теперь $ systemCall и $ i перезаписываются, в результате чего ваш скрипт сначала удаляет ваши данные, а затем зависает.

В этом нет ничего плохого. В противном случае это не будет реализовано. Многие (MVC) фреймворки используют его при передаче (назначении) переменных в Views. Вам просто нужно использовать это осторожно. Очистите эти массивы перед передачей его в extract () и убедитесь, что он не переопределяет ваши переменные. Не забывайте, что эта функция также принимает еще несколько аргументов! Используя второй и третий аргументы, вы можете контролировать поведение в случае столкновения. Вы можете переопределить, пропустить или добавить префикс. 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"

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

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

Думаю, причина, по которой многие люди не рекомендуют его использовать, заключается в том, что извлекаются $ _ GET и $ _ POST (даже $ _ REQUEST ) superglobals регистрирует переменные в глобальном пространстве имен с тем же именем, что и каждый ключ в этих массивах, что в основном эмулирует REGISTER_GLOBALS = 1.

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

Фон: extract ($ _ REQUEST) аналогичен настройке register_globals = On в php.ini

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

//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.

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

#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. Вы позволяете атакующему устанавливать переменные в вашем скрипте, просто изменяя запрос.

Никогда не извлекайте ($ _ 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 использует извлечение, поэтому использование метода не должно быть вредным, если данные очищены и обрабатываются хорошо.

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

Помните, что 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 (), состоит в том, что в PHP есть импульс для использования HHVM , который утверждает, что сделать PHP примерно в 10 раз быстрее. Facebook (который сделал это) использует это, Wikipedia на этом, и по слухам WordPress, чтобы смотреть на это.

HHVM не позволяет извлекать ()

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top