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(); |