PHP eval и фиксация ошибок (насколько это возможно)

Отказ от ответственности ; Я полностью осознаю подводные камни и «зла» eval, включая, помимо прочего, проблемы производительности, безопасности, мобильности и т. Д.

Проблема

Чтение руководства PHP по eval …

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

Короче говоря, никакого захвата ошибки, кроме возвращения false, что очень полезно, но я уверен, что я мог бы сделать лучше!

Причина

Часть функциональности сайта, над которой я работаю, зависит от выполнения выражений. Я бы хотел, чтобы я не проходил путь по песочнице или исполняющим модулям, поэтому я закончил использовать eval. Прежде чем вы начнете кричать: «Что, если клиент испортится ?!» знайте, что клиент в значительной степени доверен; он не захочет ломать свой сайт, и любой, кто получает доступ к этой функциональности, в значительной степени владеет сервером, независимо от eval.

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

Это то, что у меня есть до сих пор:

define('CR',chr(13)); define('LF',chr(10)); function test($cond=''){ $cond=trim($cond); if($cond=='')return 'Success (condition was empty).'; $result=false; $cond='$result = '.str_replace(array(CR,LF),' ',$cond).';'; try { $success=eval($cond); if($success===false)return 'Error: could not run expression.'; return 'Success (condition return '.($result?'true':'false').').'; }catch(Exception $e){ return 'Error: exception '.get_class($e).', '.$e->getMessage().'.'; } } 

Заметки

  • Функция возвращает строку сообщения в любом случае
  • Выражение кода должно быть однострочным фрагментом PHP, без PHP-тегов и без конечной точки с запятой
  • Новые строки преобразуются в пробелы
  • Добавлена ​​переменная, содержащая результат (выражение должно возвращать либо true, либо false, и для того, чтобы не противоречить возврату eval, используется временная переменная).

Итак, что бы вы добавили к дальнейшему помощнику пользователя? Существуют ли какие-либо дополнительные функции синтаксического анализа, которые могут лучше определить возможные ошибки / проблемы?

Крис.

Related of "PHP eval и фиксация ошибок (насколько это возможно)"

Я не думаю, что eval бросит вам исключение, это вызовет нормальные ошибки. Чтобы поймать это место

 ob_start(); 

до eval и после eval:

 if ('' !== $error = ob_get_clean()) { // output the error somehow to the client } 

Я не думаю, что есть еще одна функция, такая как eval с лучшей обработкой ошибок. Существует php_check_syntax но он проверяет только файл.

Я нашел хорошую альтернативу / ответ на мой вопрос.

Прежде всего, позвольте мне начать с того, что предложение nikic работает, когда я устанавливаю error_reporting (E_ALL); уведомления отображаются на выходе PHP, и благодаря OB они могут быть захвачены.

Затем я нашел этот очень полезный код:

 /** * Check the syntax of some PHP code. * @param string $code PHP code to check. * @return boolean|array If false, then check was successful, otherwise an array(message,line) of errors is returned. */ function php_syntax_error($code){ if(!defined("CR")) define("CR","\r"); if(!defined("LF")) define("LF","\n") ; if(!defined("CRLF")) define("CRLF","\r\n") ; $braces=0; $inString=0; foreach (token_get_all('<?php ' . $code) as $token) { if (is_array($token)) { switch ($token[0]) { case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: case T_START_HEREDOC: ++$inString; break; case T_END_HEREDOC: --$inString; break; } } else if ($inString & 1) { switch ($token) { case '`': case '\'': case '"': --$inString; break; } } else { switch ($token) { case '`': case '\'': case '"': ++$inString; break; case '{': ++$braces; break; case '}': if ($inString) { --$inString; } else { --$braces; if ($braces < 0) break 2; } break; } } } $inString = @ini_set('log_errors', false); $token = @ini_set('display_errors', true); ob_start(); $code = substr($code, strlen('<?php ')); $braces || $code = "if(0){{$code}\n}"; if (eval($code) === false) { if ($braces) { $braces = PHP_INT_MAX; } else { false !== strpos($code,CR) && $code = strtr(str_replace(CRLF,LF,$code),CR,LF); $braces = substr_count($code,LF); } $code = ob_get_clean(); $code = strip_tags($code); if (preg_match("'syntax error, (.+) in .+ on line (\d+)$'s", $code, $code)) { $code[2] = (int) $code[2]; $code = $code[2] <= $braces ? array($code[1], $code[2]) : array('unexpected $end' . substr($code[1], 14), $braces); } else $code = array('syntax error', 0); } else { ob_end_clean(); $code = false; } @ini_set('display_errors', $token); @ini_set('log_errors', $inString); return $code; } 

Кажется, он легко делает то, что мне нужно (yay)!

Как проверить ошибки анализа в eval ():

 $result = @eval($evalcode . "; return true;"); 

Если $result == false , $evalcode имеет ошибку синтаксического анализа и не выполняет $evalcode "return true". Очевидно, что $evalcode не должен возвращать себе что-то, но с помощью этой трюки вы можете эффективно проверить ошибки синтаксического анализа в выражениях …

Вы также можете попробовать что-то вроде этого:

 $filePath = '/tmp/tmp_eval'.mt_rand(); file_put_contents($filePath, $evalCode); register_shutdown_function('unlink', $filePath); require($filePath); 

Таким образом, любые ошибки в $ evalCode будут обрабатываться обработчиком ошибок.