PHP - eval код из БД - PullRequest
       27

PHP - eval код из БД

2 голосов
/ 02 декабря 2010

были сотни, если не тысячи сообщений об использовании PHP eval ();запустить код из базы данных.В ходе всех моих поисков я не нашел ответа на свой вопрос (объясняется в ближайшее время).

Сначала я познакомлю вас с моей заявкой.

У меня есть три записи действительного кода, хранящиеся вбаза данных:
например:
['code1']

$num1 = 1;
$num2 = 3;
$num3 = $num1+$num2;  //4

['code2']

$num4 = $num3;        //4
$num5 = 5;
$num6 = $num4+$num5;  //9

['code3']

$num7 = $num4;        //4
$num8 = $num6;        //9
$num9 = $num7+$num8;  //13
echo $num9;           //13

Далее у меня есть функция для вызова и запуска записи:
Например:

function runCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row) {
            die('No rows returned.');
        } else {
            return eval($row['code']);
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}

Теперь необходимо вызвать три вышеупомянутых фрагмента, один за другим, и получитьПеременные внутри ($ numX) доступны для использования между собой.
Например:

runCode('code1');
runCode('code2');
runCode('code3');

Вышеприведенный вызов трех фрагментов из БД должен повторить '13', но это не так.И вот мой вопрос:

Как я могу сделать эти переменные доступными вне кода eval'd?

Ответы [ 4 ]

2 голосов
/ 02 декабря 2010

Вы не получаете результаты из базы данных.mysql_query() не не возвращает все выделенные строки.

function runCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row)
            die('No rows returned.');
        $valid = eval($row['code']);
        if($valid) {
            return $valid;
        } else {
            die('Error executing: '.$codeName);
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}

См. Руководство для mysql_fetch_assoc.

Какя могу сделать эти переменные доступными вне кода eval'd?

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

Если вам достаточно сохранить переменные, вы можете попробовать get_defined_vars (ивозможно, комбинация из compact и extract или замена ваших функций по отдельности).Однако эта функция возвращает имя всех определенных переменных (включая суперглобальные переменные, такие как $_GET и т. Д.).
Если вы создадите умный алгоритм сравнения, вы, вероятно, сможете сравнить переменные, которые были определены до и после кода eval'd иузнать, какие переменные являются новыми.Удачи с этим:).

1 голос
/ 02 декабря 2010

В дополнение к ответу svens , я думаю, что вы не проверяете возвращаемое значение из eval() правильно.Из руководства по PHP :

eval () возвращает NULL, если в обработанном коде не вызывается return, и в этом случае возвращается значение, переданное в return.Если в обработанном коде есть ошибка синтаксического анализа, eval () возвращает FALSE и выполнение следующего кода продолжается в обычном режиме.

Вы должны рассматривать это как сбой, только если FALSE === eval($code).Даже в этом случае вы можете столкнуться с проблемами, если ваш код вернет FALSE.

0 голосов
/ 02 декабря 2010

Я бы определенно пошел путем "передать массив имен кодов в runCode ()".Преимущества, которые вы получаете:

  1. Все фрагменты можно получить с помощью одного SELECT ... WHERE name IN ('code1', 'code2', ...) запроса
  2. Вы разделяете переменные между фрагментами, сохраняя их в области действия * 1007.* вызов функции (чтобы они уничтожались при завершении выполнения функции)

Затем вы можете работать двумя способами:

  1. eval() их по одномуодин при извлечении строк из базы данных приводит
  2. implode() к ним с символом новой строки, чтобы получить один фрагмент кода сразу к eval().
0 голосов
/ 02 декабря 2010

Переменные из БД являются локальными в функции.Сделайте их глобальными.

Так что вы можете использовать глобальное ключевое слово для изменения области действия переменных:

<?php
error_reporting (E_ALL);

$txt = array(
'$num1 = 1;
$num2 = 3;
global $num3; // make it global, will be used later
$num3 = $num1+$num2;
echo "num3=" . $num3 . "<br>"; //4',

'global $num3; // need to use value from this var
global $num4; // make it global, will be used later
$num4 = $num3;        //4
$num5 = 5;
global $num6; // make it global, will be used later
$num6 = $num3+$num5; 
echo "num6=" . $num6 . "<br>"; //9',

'global $num4; // need to use value from this var
global $num6; // need to use value from this var
$num7 = $num4;        //4
$num8 = $num6;        //9
global $num9; // make it global, will be used later (maybe)
$num9 = $num7+$num8;  //13
echo "num9=" . $num9 . "<br>";           //13'
);

function runCode($codeName) { // just for example
    eval($codeName);
}

runCode($txt[0]);
runCode($txt[1]);
runCode($txt[2]);
?>

Это решение требует изменения существующего кода в БД.Это может быть сложно.

Итак, вот другой алгоритм.Сначала объедините все фрагменты кода.Затем запустите функцию eval и передайте ей присоединенный код.Например:

function composeCode($codeName) {
    // assume db connection is established
    $result = mysql_query("SELECT `code` FROM CodeStore WHERE `name` = '".$codeName."'");
    if ($result) {
        // Fetch one row
        $row = mysql_fetch_assoc($result);
        if (!$row) {
            die('No rows returned.');
        } else {
            return $row['code']; // CHANGED ORIGINAL CODE
        }
    } else {
        die('Invalid query: '.mysql_error());
    }
}
$code = '';
$code .= composeCode('code1');
$code .= composeCode('code2');
$code .= composeCode('code3');
eval($code);
...