| Index: trunk/extensions/Lua/Lua.wrapper.php |
| — | — | @@ -31,13 +31,14 @@ |
| 32 | 32 | */ |
| 33 | 33 | class LuaWrapper { |
| 34 | 34 | private $defunct, $lua, $proc, $pipes; |
| | 35 | + private $sandbox, $out; |
| 35 | 36 | |
| 36 | 37 | /** |
| 37 | 38 | * Creates a new LuaWrapper. |
| 38 | 39 | */ |
| 39 | 40 | public function __construct() { |
| 40 | 41 | global $wgLuaMaxLines, $wgLuaMaxCalls, |
| 41 | | - $wgLuaExternalInterpreter, $wgLuaExternalCompiler; |
| | 42 | + $wgLuaExternalInterpreter, $wgLuaExternalCompiler, $wgLuaExtension; |
| 42 | 43 | |
| 43 | 44 | # Optionally byte-compile the wrapper library |
| 44 | 45 | $wrapperLib = dirname(__FILE__) . '/LuaWrapper.lua'; |
| — | — | @@ -56,7 +57,28 @@ |
| 57 | 58 | } |
| 58 | 59 | |
| 59 | 60 | # Are we using the Lua PHP extension or an external binary? |
| 60 | | - if (!$wgLuaExternalInterpreter) { |
| | 61 | + if ($wgLuaExternalInterpreter) { |
| | 62 | + # We're using an external binary; run the wrapper |
| | 63 | + # library as a shell-script, and it'll start an REPL |
| | 64 | + $luacmd = "$wgLuaExternalInterpreter $wrapperLib $wgLuaMaxLines $wgLuaMaxCalls"; |
| | 65 | + # Create a new process and configure pipes to it |
| | 66 | + $this->proc = proc_open($luacmd, |
| | 67 | + array(0 => array('pipe', 'r'), |
| | 68 | + 1 => array('pipe', 'w')), |
| | 69 | + $this->pipes, null, null); |
| | 70 | + if (!is_resource($this->proc)) { |
| | 71 | + $this->defunct = TRUE; |
| | 72 | + throw new LuaError('interp_notfound'); |
| | 73 | + } |
| | 74 | + stream_set_blocking($this->pipes[0], 0); |
| | 75 | + stream_set_blocking($this->pipes[1], 0); |
| | 76 | + stream_set_write_buffer($this->pipes[0], 0); |
| | 77 | + stream_set_write_buffer($this->pipes[1], 0); |
| | 78 | + |
| | 79 | + # Ready to go. |
| | 80 | + $this->defunct = FALSE; |
| | 81 | + return TRUE; |
| | 82 | + } elseif ( $wgLuaExtension === 'lua' ) { |
| 61 | 83 | # We're using the extension - verify it exists |
| 62 | 84 | if (!class_exists('lua')) { |
| 63 | 85 | $this->defunct = TRUE; |
| — | — | @@ -76,27 +98,17 @@ |
| 77 | 99 | # Ready to go. |
| 78 | 100 | $this->defunct = FALSE; |
| 79 | 101 | return TRUE; |
| 80 | | - } else { |
| 81 | | - # We're using an external binary; run the wrapper |
| 82 | | - # library as a shell-script, and it'll start an REPL |
| 83 | | - $luacmd = "$wgLuaExternalInterpreter $wrapperLib $wgLuaMaxLines $wgLuaMaxCalls"; |
| 84 | | - # Create a new process and configure pipes to it |
| 85 | | - $this->proc = proc_open($luacmd, |
| 86 | | - array(0 => array('pipe', 'r'), |
| 87 | | - 1 => array('pipe', 'w')), |
| 88 | | - $this->pipes, null, null); |
| 89 | | - if (!is_resource($this->proc)) { |
| | 102 | + } elseif ( $wgLuaExtension === 'luasandbox' ) { |
| | 103 | + if (!class_exists('luasandbox')) { |
| 90 | 104 | $this->defunct = TRUE; |
| 91 | | - throw new LuaError('interp_notfound'); |
| | 105 | + throw new LuaError( 'extension_notfound' ); |
| 92 | 106 | } |
| 93 | | - stream_set_blocking($this->pipes[0], 0); |
| 94 | | - stream_set_blocking($this->pipes[1], 0); |
| 95 | | - stream_set_write_buffer($this->pipes[0], 0); |
| 96 | | - stream_set_write_buffer($this->pipes[1], 0); |
| 97 | 107 | |
| 98 | | - # Ready to go. |
| 99 | | - $this->defunct = FALSE; |
| 100 | | - return TRUE; |
| | 108 | + $this->sandbox = new LuaSandbox; |
| | 109 | + $this->sandbox->registerLibrary( 'mw', array( 'print' => array( $this, 'luaPrint' ) ) ); |
| | 110 | + $this->sandbox->loadString( 'print = mw.print; io = {write = mw.print}' )->call(); |
| | 111 | + } else { |
| | 112 | + throw new MWException( 'Invalid value for $wgLuaExtension' ); |
| 101 | 113 | } |
| 102 | 114 | } |
| 103 | 115 | |
| — | — | @@ -133,6 +145,16 @@ |
| 134 | 146 | $res = $this->lua->wrap($input); |
| 135 | 147 | $out = $res[0]; |
| 136 | 148 | $err = $res[1]; |
| | 149 | + } elseif ( isset( $this->sandbox ) ) { |
| | 150 | + $err = ''; |
| | 151 | + $out = ''; |
| | 152 | + try { |
| | 153 | + $this->out = ''; |
| | 154 | + $this->sandbox->loadString( $input )->call(); |
| | 155 | + $out = $this->out; |
| | 156 | + } catch ( LuaSandboxError $e ) { |
| | 157 | + $err = $e->getMessage(); |
| | 158 | + } |
| 137 | 159 | } else { |
| 138 | 160 | # We're using an external binary; send the chunk |
| 139 | 161 | # through the pipe |
| — | — | @@ -198,7 +220,9 @@ |
| 199 | 221 | return FALSE; |
| 200 | 222 | |
| 201 | 223 | # Destroy the lua instance and/or external process and pipes |
| 202 | | - if (isset($this->lua)) { |
| | 224 | + if ( isset( $this->sandbox ) ) { |
| | 225 | + $this->sandbox = null; |
| | 226 | + } elseif (isset($this->lua)) { |
| 203 | 227 | $this->lua = null; |
| 204 | 228 | } else { |
| 205 | 229 | if (isset($this->proc)) { |
| — | — | @@ -212,4 +236,19 @@ |
| 213 | 237 | $this->defunct = TRUE; |
| 214 | 238 | return TRUE; |
| 215 | 239 | } |
| | 240 | + |
| | 241 | + public function luaPrint() { |
| | 242 | + $args = func_get_args(); |
| | 243 | + foreach ( $args as $i => $arg ) { |
| | 244 | + if ( $i >= 1 ) { |
| | 245 | + $this->out .= "\t"; |
| | 246 | + } |
| | 247 | + if ( $arg instanceof LuaSandboxPlaceholder ) { |
| | 248 | + $this->out .= "[placeholder]"; |
| | 249 | + } else { |
| | 250 | + $this->out .= $arg; |
| | 251 | + } |
| | 252 | + } |
| | 253 | + } |
| | 254 | + |
| 216 | 255 | } |
| Index: trunk/extensions/Lua/Lua.php |
| — | — | @@ -22,16 +22,12 @@ |
| 23 | 23 | $wgAutoloadClasses['LuaError'] = $dir . 'Lua.wrapper.php'; |
| 24 | 24 | $wgAutoloadClasses['LuaWrapper'] = $dir . 'Lua.wrapper.php'; |
| 25 | 25 | |
| 26 | | -if (!isset($wgLuaExternalInterpreter)) |
| 27 | | - $wgLuaExternalInterpreter = FALSE; |
| 28 | | -if (!isset($wgLuaExternalCompiler)) |
| 29 | | - $wgLuaExternalCompiler = FALSE; |
| 30 | | -if (!isset($wgLuaMaxLines)) |
| 31 | | - $wgLuaMaxLines = 1000000; |
| 32 | | -if (!isset($wgLuaMaxCalls)) |
| 33 | | - $wgLuaMaxCalls = 2000; |
| 34 | | -if (!isset($wgLuaMaxTime)) |
| 35 | | - $wgLuaMaxTime = 5; |
| | 26 | +$wgLuaExternalInterpreter = FALSE; |
| | 27 | +$wgLuaExternalCompiler = FALSE; |
| | 28 | +$wgLuaExtension = 'lua'; |
| | 29 | +$wgLuaMaxLines = 1000000; |
| | 30 | +$wgLuaMaxCalls = 2000; |
| | 31 | +$wgLuaMaxTime = 5; |
| 36 | 32 | |
| 37 | 33 | |
| 38 | 34 | $wgHooks['ParserFirstCallInit'][] = 'LuaHooks::parserInit'; |
| Index: trunk/extensions/Lua/Lua.hooks.php |
| — | — | @@ -32,30 +32,30 @@ |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | /** Parser hook for the <lua> tag */ |
| 36 | | - public static function renderTag($input, $args, &$parser) { |
| 37 | | - global $wgLua; |
| 38 | | - # Create a new LuaWrapper if needed |
| 39 | | - if (!isset($wgLua)) |
| 40 | | - $wgLua = new LuaWrapper; |
| | 36 | + public static function renderTag($input, $args, $parser) { |
| | 37 | + try { |
| | 38 | + global $wgLua; |
| | 39 | + # Create a new LuaWrapper if needed |
| | 40 | + if (!isset($wgLua)) |
| | 41 | + $wgLua = new LuaWrapper; |
| 41 | 42 | |
| 42 | | - # Process the tag's arguments into a chunk of Lua code |
| 43 | | - # that initializes them in the Lua sandbox |
| 44 | | - $arglist = ''; |
| 45 | | - foreach ($args as $key => $value) |
| 46 | | - $arglist .= (preg_replace('/\W/', '', $key) . '=\'' . |
| 47 | | - addslashes($parser->recursiveTagParse($value)) . |
| 48 | | - '\';'); |
| 49 | | - if ($arglist) { |
| 50 | | - try { |
| 51 | | - $wgLua->wrap($arglist); |
| 52 | | - } catch (LuaError $e) { |
| 53 | | - return $e->getMessage(); |
| | 43 | + # Process the tag's arguments into a chunk of Lua code |
| | 44 | + # that initializes them in the Lua sandbox |
| | 45 | + $arglist = ''; |
| | 46 | + foreach ($args as $key => $value) |
| | 47 | + $arglist .= (preg_replace('/\W/', '', $key) . '=\'' . |
| | 48 | + addslashes($parser->recursiveTagParse($value)) . |
| | 49 | + '\';'); |
| | 50 | + if ($arglist) { |
| | 51 | + try { |
| | 52 | + $wgLua->wrap($arglist); |
| | 53 | + } catch (LuaError $e) { |
| | 54 | + return $e->getMessage(); |
| | 55 | + } |
| 54 | 56 | } |
| 55 | | - } |
| 56 | 57 | |
| 57 | | - # Execute this Lua chunk, and send the results through the |
| 58 | | - # Parser. |
| 59 | | - try { |
| | 58 | + # Execute this Lua chunk, and send the results through the |
| | 59 | + # Parser. |
| 60 | 60 | return $parser->recursiveTagParse($wgLua->wrap($input)); |
| 61 | 61 | } catch (LuaError $e) { |
| 62 | 62 | return $e->getMessage(); |