note 103360 added to function.eval
| From: | sfinktah at php dot spamtrak dot org | Date: | Sat, 09 Apr 2011 11:17:08 +0000 |
| Subject: | note 103360 added to function.eval | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-178656@lists.php.net to get a copy of this message | ||
If you really want a bullet-proof eval, you can use a socket_pair and fork(). (Not tested under
windows).
<?php
function lookupErrorCode($errno) { static $lookup = false;
if ($lookup == false) foreach (array("E_ERROR", "E_WARNING",
"E_PARSE", "E_NOTICE",
"E_CORE_ERROR", "E_CORE_WARNING", "E_COMPILE_ERROR",
"E_COMPILE_WARNING",
"E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE",
"E_STRICT", "E_RECOVERABLE_".
"ERROR", "E_DEPRECATED", "E_USER_DEPRECATED") as $k
=> $v) $lookup[1<<$k] = $v;
return (!empty($lookup[$errno]) ? $lookup[$errno] : "UNKNOWN"); }
function child_exit_handler($socket = NULL) {
static $paired_socket = false;
if ($socket || $socket === false) return $paired_socket = $socket;
if ($paired_socket) {
$e = error_get_last();
$result = "ERROR_" . lookupErrorCode($e["type"]) . ":
{$e["message"]}";
if (socket_write($paired_socket, $result, strlen($result)) === false)
echo "socket_write() failed. Reason:
".socket_strerror(socket_last_error($sockets[0]));
socket_close($sockets[0]);
}
exit(2); # Child Process Dies, writing an error to it's paired socket.
}
function forked_eval($eval) {
$sockets = array();
/* On Windows we need to use AF_INET */
$domain = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' ? AF_INET : AF_UNIX);
/* Setup socket pair */
if (socket_create_pair($domain, SOCK_STREAM, 0, $sockets) === false) {
echo "socket_create_pair failed. Reason:
".socket_strerror(socket_last_error());
}
switch ($child = pcntl_fork()) {
case -1:
throw new Exception("Could not fork");
case 0:
# Child Thread
register_shutdown_function("child_exit_handler");
child_exit_handler($sockets[0]); # Register the socket
$result = serialize(eval($eval));
child_exit_handler(false); # We didn't crash
if (socket_write($sockets[0], $result, strlen($result)) === false)
echo "socket_write() failed. Reason: ".
socket_strerror(socket_last_error($sockets[0]));
socket_close($sockets[0]);
exit(3);
default :
# Parent Thread
if (($nread = socket_recv($sockets[1], $data, 1<<16, 0)) < 1)
echo "socket_read() failed. Reason:
".socket_strerror(socket_last_error($sockets[1]));
if (!strncmp($data, "ERROR_", 6)) {
return substr($data, 6); # throw new Exception(substr($data, 6));
}
socket_close($sockets[1]);
return unserialize($data);
}
}
function safe_eval($cmd, $str = false, $file = false, $line = false, $context = false) {
static $err_strings = array();
if ($cmd === true) return count($err_strings) ? $err_strings : false;
if ($str !== false)
return ($err_strings[] = lookupErrorCode($cmd) . ": $str in $file on line
$line") && true;
$err_strings = array(); $old_error_handler = set_error_handler(__FUNCTION__, E_ALL);
$rv = @eval("return true; $cmd") ? forked_eval($cmd)
: ($or = error_get_last()) && call_user_func_array(__FUNCTION__, $or);
restore_error_handler(); return $rv;
}
foreach (array( "return sleep(2) && foobar();"
, "return date('Y-m-d');" , "return
touch('/error/error/error') ? 'OK' : 'Failed';"
, "return ==" , "return 2 + array();" , "return foobar();" ,
"return 2;") as $cmd) {
printf("\nAttempting to evaluate: $cmd\n"); $rv = safe_eval($cmd);
printf("%s\n", ($e = safe_eval(true)) ? "ERROR: $e" :
"Result: $rv"); }
?>
----
Server IP: 117.55.229.1
Probable Submitter: 124.190.251.137
----
Manual Page -- http://www.php.net/manual/en/function.eval.php
Edit -- https://master.php.net/note/edit/103360
Del: integrated -- https://master.php.net/note/delete/103360/integrated
Del: useless -- https://master.php.net/note/delete/103360/useless
Del: bad code -- https://master.php.net/note/delete/103360/bad+code
Del: spam -- https://master.php.net/note/delete/103360/spam
Del: non-english -- https://master.php.net/note/delete/103360/non-english
Del: in docs -- https://master.php.net/note/delete/103360/in+docs
Del: other reasons-- https://master.php.net/note/delete/103360
Reject -- https://master.php.net/note/reject/103360
Search -- https://master.php.net/manage/user-notes.php