diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000..383dbae
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.php]
+indent_style = space
+indent_size = 4
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4278655
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+tmp/
+.env
+*.tmp
+*.bak
+*.swp
+*~.nib
+data/
+local.properties
+.settings/
+composer.lock
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+nb-configuration.xml
+
+
+### vim ###
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+*.un~
+Session.vim
+.netrwhist
+*~
+
+### Composer ###
+vendor/
+autotune.json
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..80407e7
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,19 @@
+# The MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d0924fe
--- /dev/null
+++ b/README.md
@@ -0,0 +1,57 @@
+Lua PHP
+=======
+
+This library enables you to add Lua scripting support to your PHP applications.
+
+## LuaSandbox
+
+The LuaSandbox class allows you to easily run user-supplied Lua scripts in an empty sandbox environment.
+This means that dangerous functions (i.e. for file and network IO) are unavailable by default.
+To make the sandbox useful, you register your own PHP-implemented functions that you allow the chunks to execute.
+
+## Use-cases
+
+* Support user-supplied scripts to respond to events in your application
+* Advanced expressions, filters, segments
+* Customizable routing
+* ... and many more :)
+
+## Usage
+
+Check the `example/` directory for a well-documented example.
+
+## About Lua
+
+* Website: http://www.lua.org/
+* Wikipedia: https://en.wikipedia.org/wiki/Lua_(programming_language)
+
+## Requirements
+
+This library requires that the [PHP Lua extension](https://www.php.net/manual/en/book.lua.php) is installed.
+
+A quick install guide for Ubuntu:
+
+```sh
+# Install lua library
+apt-get install -y --no-install-recommends lua5.3 liblua5.3-dev
+# pecl expects liblua and includes in specific locations, so move them around a bit:
+cp /usr/lib/x86_64-linux-gnu/liblua5.3.a /usr/lib/liblua.a
+cp /usr/lib/x86_64-linux-gnu/liblua5.3.so /usr/lib/liblua.so
+ln -s /usr/include/lua5.3 /usr/include/lua
+# Install the lua extension through pecl
+pecl install lua
+# Activate the lua extension in your PHP config
+php --ini # find out where your PHP config files are located
+echo "extension=lua.so" > /path/to/my/php/conf.d/lua.ini
+```
+
+## License
+
+MIT. Please refer to the [license file](LICENSE) for details.
+
+## Brought to you by the LinkORB Engineering team
+
+
+Check out our other projects at [linkorb.com/engineering](http://www.linkorb.com/engineering).
+
+Btw, we're hiring!
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..4914d7c
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,23 @@
+{
+ "name": "linkorb/lua",
+ "description": "Lua PHP: Library for extending your application with lua scripts",
+ "homepage": "http://www.github.com/linkorb/lua-php",
+ "keywords": ["php", "lua", "scripting", "sandbox", "linkorb"],
+ "type": "library",
+ "authors": [
+ {
+ "name": "LinkORB Engineering",
+ "email": "engineering@linkorb.com",
+ "role": "Development"
+ }
+ ],
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "LinkORB\\Lua\\": "src/"
+ }
+ },
+ "license": "MIT"
+}
diff --git a/example/example-advanced.lua b/example/example-advanced.lua
new file mode 100644
index 0000000..72ea513
--- /dev/null
+++ b/example/example-advanced.lua
@@ -0,0 +1,13 @@
+local function on_click(data)
+ -- error("BWAM")
+ print("On click!!")
+end
+
+return {
+ name = "My advanced chunk",
+ description = "This is an example structure",
+ on_click = on_click,
+ on_exit = function(data)
+ print("I'll be back")
+ end,
+}
diff --git a/example/example-simple.lua b/example/example-simple.lua
new file mode 100644
index 0000000..3f23505
--- /dev/null
+++ b/example/example-simple.lua
@@ -0,0 +1,9 @@
+-- This is an example lua file to load into the sandbox
+
+return function(foo, bar)
+ print(reverse(foo) .. ", " .. bar)
+ -- local f = io.open('/etc/hostname', "rb")
+ -- local content = f:read "*a"
+ -- print(content)
+ return "This is returned from Lua"
+end
diff --git a/example/example.php b/example/example.php
new file mode 100644
index 0000000..feaadfd
--- /dev/null
+++ b/example/example.php
@@ -0,0 +1,42 @@
+registerCallback('print', function($text) {
+ echo "PRINT: " . $text . PHP_EOL;
+});
+
+$sandbox->registerCallback('reverse', function($text) {
+ return strrev($text);
+});
+
+// Let's register some callable Lua chunks:
+$code = file_get_contents(__DIR__ . '/example-simple.lua');
+$sandbox->registerChunk('example-simple', $code);
+
+$code = file_get_contents(__DIR__ . '/example-advanced.lua');
+$sandbox->registerChunk('example-advanced', $code);
+
+
+// You can now call a chunk (assuming it is a function) with arguments:
+$res = $sandbox->callChunk('example-simple', ['hello', 'world']);
+echo "RETURN VALUE: " . $res . PHP_EOL;
+
+// You can also retrieve a chunk by name:
+$chunk = $sandbox->getChunk('example-advanced');
+print_r($chunk);
+$chunk['on_click']('Click test');
+
+// You can retrieve the environment for inspection:
+$e = $sandbox->getEnvironment();
+print_r($e);
+
+echo "Done\n";
diff --git a/lua/sandbox.lua b/lua/sandbox.lua
new file mode 100644
index 0000000..0cd8f77
--- /dev/null
+++ b/lua/sandbox.lua
@@ -0,0 +1,43 @@
+local sandbox_env = {
+ -- start with an empty environment
+}
+
+-- array of registered chunks
+local chunks = {}
+
+function registerChunk(chunk_name, code)
+ local chunk, message = load(code, 'sandbox:' .. chunk_name, 't', sandbox_env)
+ if not chunk then
+ error("Failed to register chunk: " .. chunk_name)
+ end
+ chunks[chunk_name] = chunk()
+end
+
+-- promote an item in the global _ENV to the sandbox env
+function registerCallback(name)
+ sandbox_env[name] = _ENV[name]
+end
+
+-- call a chunk by name as a function with parameters
+function callChunk(chunk_name, ...)
+ local chunk = getChunk(chunk_name)
+ local status, res = pcall(chunk, ...)
+ if (not status) then
+ error(res)
+ end
+ return res
+end
+
+-- retrieve a chunk by name
+function getChunk(chunk_name)
+ local chunk = chunks[chunk_name]
+ if (not chunk) then
+ error("Getting unregistered chunk: " .. chunk_name)
+ end
+ return chunk
+end
+
+-- retrieve the sandbox environment for inspection
+function getEnvironment()
+ return sandbox_env
+end
diff --git a/src/LuaException.php b/src/LuaException.php
new file mode 100644
index 0000000..2d02203
--- /dev/null
+++ b/src/LuaException.php
@@ -0,0 +1,10 @@
+lua = $lua;
+
+ $this->lua->registerCallback("error", function($message) {
+ $this->error($message);
+ });
+
+ $this->lua->registerCallback("cool", function($message) {
+ echo "COOL: $message\n";
+ });
+
+ $this->lua->registerCallback("print", function($message, $a = null, $b = null, $c = null) {
+ echo "PRINT: $message $a $b $c\n";
+ });
+
+ $sandboxCode = file_get_contents(__DIR__ . '/../lua/sandbox.lua');
+ $this->lua->eval($sandboxCode);
+ }
+
+ public function registerChunk(string $name, string $code): void
+ {
+ $res = $this->lua->call("registerChunk", array($name, $code));
+ if ($res) {
+ throw new LuaException("Failed to register chunk " . $name);
+ }
+ }
+
+ public function registerCallback(string $name, callable $cb)
+ {
+ $this->lua->registerCallback($name, $cb);
+ $res = $this->lua->call("registerCallback", array($name));
+ }
+
+
+ public function getChunk(string $name)
+ {
+ $res = $this->lua->call("getChunk", array($name));
+ return $res;
+ }
+
+
+ public function callChunk(string $name, $arguments)
+ {
+ array_unshift($arguments, $name);
+ $res = $this->lua->call("callChunk", $arguments);
+ return $res;
+ }
+
+ public function getEnvironment()
+ {
+ $res = $this->lua->call("getEnvironment", []);
+ return $res;
+ }
+
+
+
+// $x = $lua->call("getChunk", array('demo-advanced'));
+// if (!$x) {
+// echo "PHP: That failed\n";
+// }
+// print_r($x);
+// $f = $x['onFrame'];
+// try {
+// $f('ahaha');
+// } catch (\Exception $e) {
+// print_r($e);
+// }
+// $f = ($x['onTerminate'] ?? null);
+// $f("bye", "x");
+
+// echo "Done\n";
+
+// }
+
+}