2010-12-01 2 views
2

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

Во-первых, я расскажу вам о своем заявлении.

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

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

[ 'Кодекса2']

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

[ 'code3' ]

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

Next У меня есть функция позвонить и запустить запись:
например:

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?

ответ

0

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

Таким образом, вы можете использовать глобальное ключевое слово, чтобы изменить переменные сферы:

<?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); 
+0

Либо это, либо передать в массиве кодовых имен и 'eval()' все они в одном вызове функции. –

+0

так: глобальный $ numX; // для каждой переменной? ?? –

+0

Да. Дайте мне несколько минут, я отредактирую свой пост, чтобы показать образец кода. – Lex

2

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

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 или рулонной собственную замену этих функций). Однако эти функции возвращают имя всех определенных vars (включая суперглобали, такие как $_GET и т. Д.).
Если вы построите алгоритм умного разложения, вы, вероятно, можете сравнить переменные, которые были определены до и после кода eval'd, и выяснить, какие переменные являются новыми. Удачи с этим :).

+0

спасибо svens, я натолкнулся на это некоторое время назад. Я смотрю на него дальше –

1

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

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

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

+0

Мне действительно не нужно проверять, действительно ли код действителен, но я добавил ваше предложение в свой список. thanks –

0

Я бы определенно пошел с «переходом массива кодовых имен к методу runCode()». Преимущества Вы получаете:

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

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

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

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

+0

Как использовать некоторые «теги» (что-то вроде '{{codeXX}}'), чтобы заменить соответствующим фрагментом кода из БД с помощью 'preg_replace_callback()' перед фактическим 'eval()' -в коде? (Это также поможет вам при отладке кода, который может стать довольно сложным из-за гнездования.) – redShadow

Смежные вопросы