Использование eval() в коде, и как бы вы этого избежали?
В моем коде я хочу попробовать извлечь переменные $_POST или $_GET и сбросить их, как только они были запрошены один раз.
Эта функция возвращает используемый метод, который достаточно прост. К сожалению, я не могу просто вернуть переменные $_POST или $_GET напрямую или по ссылке, потому что я не смог бы их сбросить (сброс по ссылке не работает). Итак, я возвращаю имена переменных:
class Input {
protected function interface_get($method): string {
switch ($method) {
case 'post':
return '_POST';
break;
case 'get':
return '_GET';
break;
case 'ajax':
// Not supported yet.
return null;
break;
default:
return null; // returns '_GET' or '_POST'
}
}
public function fetch_eval(string $method, ?string $request = null) { // ...fetch('post', 'username')
if ($request !== null) {
$request = '[\'' . $request . '\']'; // "['username']"
}
$request = $this->interface_get($method) . $request; #"$_POST['username']"
eval('$return = $' . $request . ';'); #$return = $_POST['username'];
eval('unset($' . $request . ');'); #unset($_POST['username']);
return $return;
}
public function fetch_varvar(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = (${$interface});
unset(${$interface});
} else {
$return = ${$interface}; #"Notice: Undefined variable: _POST in [...]"
$return = ${$interface}[$request]; #"Warning: Illegal string offset 'email' in [...]"
unset($interface[$request]);
}
return $result;
}
}
// set $_POST = ['email'=>'spam@me'];
$in = new Input();
echo $in->fetch_eval('post', 'email'); #'spam@me'
// $_POST = [];
// set $_POST = ['email'=>'spam@me']; again
echo $in->fetch_varvar('post', 'email'); #'Notice: Undefined variable: _POST [...]'
Забавная часть обрабатывает этот вывод. Вот моя функция извлечения, самый простой, но, я думаю, самый грязный способ:
Я пытался использовать переменные переменные, это работало в тестовом скрипте:
// $_POST = [0 => 5, 'bob' => 5];
$e = '_POST';
$var = 'bob';
echo ${$e}[$var]; #5
unset(${$e}[$var]);
echo ${$e}[$var ]; #NOTICE Undefined index: bob on line number 22
// Works as expected.
Но это не сработало в моем сценарии (Undefined variable: _POST [...]
.). Я подумал, может быть, причина в том, что это было в классе, но в любом случае я не мог решить это. Более того, если вы поместите эти функции вне класса и удалите $this->
Да, они работают! Но не внутри класса.
Если бы кто-то мог сказать мне, почему мой последний код не работает, я был бы признателен. Но в любом случае, вы бы сказали, что использование eval() разумно? Я знаю, что некоторые люди избегают этого несмотря ни на что. Очевидно, что в этом случае это открывает довольно большую уязвимость, поэтому вместо дезинфекции и беспокойства я бы предпочел вообще ее избежать.
Я хотел бы сохранить interface_get()
как отдельная функция, но при необходимости я могу продублировать ее внутри fetch()
тоже, наверное.
Заранее большое спасибо.
2 ответа
Вы могли бы использовать $GLOBALS[$interface]
чтобы получить ваши данные.
Если предположить, $_POST
а также $_GET
всегда определяется, однако, вы можете проверить, определены ли ключи прежде, чтобы получить его и сбросить его, чтобы избежать предупреждений.
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$result = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
return $result;
}
if (isset($GLOBALS[$interface][$request])) {
$result = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
return $result;
}
return null;
}
@Syscall и @Ignacio Vazquez-Abrams предоставили ответы на этот вопрос в комментариях.
Согласно документации PHP ( https://php.net/manual/en/language.variables.superglobals.php):
Суперглобальные переменные нельзя использовать в качестве переменных переменных внутри функций или методов класса.
Вот почему это не работает внутри Input
учебный класс. Чтобы это работало, мне пришлось использовать переменную $GLOBALS следующим образом:
public function fetch(string $method, ?string $request = null) {
$interface = $this->interface_get($method); #$interface = '_POST';
if ($request === null) {
$return = $GLOBALS[$interface];
unset($GLOBALS[$interface]);
} else {
$return = $GLOBALS[$interface][$request];
unset($GLOBALS[$interface][$request]);
}
return $return;
}
Этот код работал. Большое спасибо за ваш вклад. Там может быть лучший или более элегантный способ достичь того, что я искал. В этом случае дальнейший ввод всегда приветствуется.