LUA for PHP
About
phplua is a PHP extension that enables you to embed the LUA interpreter in a PHP application.
Huh? A script language embedded in a script language? This is probably what you are asking yourself now.
But imagine you have an application and want to allow users to customize it using some API.
PHP will be sufficient if you are the webmaster and want to extend a foreign application by a separate module.
But you certainly do NOT want to give an ordinary web user of this application the ability to inject their own PHP code.
PHP is simply not designed to do this.
At least not in a secure way.
Of course you can restrict the available functions using disable_functions in the ini file.
You could even try to parse out evil code.
But you will probably never reach 100% safety.
This is where the LUA interpreter comes in.
LUA has been designed as an embeddable language.
You can very easily control what the user is allowed to do and what shouldn't be allowed.
Furthermore it has a very low memory footprint, it's fast and it has a reasonable set of (base) features.
Using it from PHP is very easy:
$lua=new lua;
$lua->test="test";
$value=$lua->evaluate("print(test)
return 2
");
print $value[0];
This is a fork of the pecl extension "lua" and provides better integration with PHP.
Merging with it again is desired :)
Differences from the original source tree
The original extension doesn't support array handling and doesn't support calling PHP functions from within LUA. These are in my opinion the most important features which
were missing. Furthermore this extension allows compiling a LUA script for faster execution. Apart from that it should be more or less the same currently.
API
LUA Class API
public __construct() - Create a LUA object
public static string compile(string $chunk) - Compiles (faster execution) a LUA chunk for use with evaluate()
public mixed call_function(string $function,array $args) - Calls a LUA function from within PHP
public mixed call_table(array $table,$args) - Calls a table function (array($tablename,$functionname)) and returns the result (LUA: table.function(arg1,arg2))
public mixed call_table_self(array $table,$args) - Like call_table() but prepends self (LUA: table:function(arg1,arg2))
public mixed evaluate(string $lua_chunk) - Evaluates the LUA chunk and returns the result
public mixed evaluatefile(string $lua_file) - Evaluates the LUA chunk contained in $file and returns the result
public void expose_function(string $lua_name,mixed $callback) - exposes the callback represented by $callback to lua as function $lua_name
Limiting the default LUA sandbox
As said before LUA can be limited quite easily. Just do the following and you prevent users from having access to the filesystem:
$lua=new lua();
$lua->io=NULL;
Download
phplua-0.1.1.tar.bz2
Source Code
Can be obtained from the git repository here.
Simple Zend View Proof of concept
Well. I don't like template systems (limited functionality). I don't like the phtml approach of Zend Framework either (enables you to do dirty stuff inside the view).
Here is the golden middle: LUA views in Zend Framework. A fully fledged language and it is still restricted and prevents you from doing evil stuff ;)
Notice that all helpers are automagically available in LUA ;) Please also note that this was a quick hack and is not meant to be used in a production environment.
<?php
class Zend_View_Lua extends Zend_View_Abstract
{
const TYPE_STATIC=0;
const TYPE_LUA =1;
protected $_lua;
protected $_scriptPath;
protected $_luavars=array();
public function __construct()
{
$this->_lua=new lua;
$this->_lua->expose_function("helper",array($this,"__call"));
}
public function getEngine()
{
return $this->_lua;
}
public function __set($key, $val)
{
if (!is_object($val))
{
$this->_lua->$key=$val;
$this->_luavars[$key]=true;
}
}
public function __isset($key)
{
return (null !== $this->_lua->$key);
}
public function __unset($key)
{
$this->_lua->$key=NULL;
unset($this->_luavars[$key]);
}
public function assign($spec, $value = null)
{
if (is_array($spec)) {
foreach ($spec as $key => $val)
$this->_lua->$key=$val;
return;
}
$this->_lua->$spec=$value;
}
public function clearVars()
{
foreach (array_keys($this->_luavars) as $var)
$this->_lua->$var=NULL;
$this->_luavars=array();
}
private function __clone()
{
}
protected function _run()
{
$filename=func_get_arg(0);
if (!is_readable($filename))
throw new Exception("File ".$filename." is not readable");
$content=file_get_contents($filename);
preg_match_all("/((<\?lua)\s+|\s*(\?>))/",$content,$matches,PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$in_lua=false;
$views=array();
$end =array();
$last_lua=0;
$lua_start=NULL;
for ($i=0;$i<sizeof($matches);$i++)
{
if ($matches[$i][2][0]=="<?lua")
{
$ends_len=sizeof($ends);
if ($in_lua)
{
if ($ends_len==0)
continue;
}
if ($ends_len>0)
{
// stupid trial and error
for ($j=$ends_len-1;$j>=0;$j--)
{
$lua_script=substr($content,$lua_start+5,$ends[$j][1]-($lua_start+5));
$compiled=lua::compile(substr($content,$lua_start+5,$ends[$j][1]-($lua_start+5)));
if ($compiled)
{
$views[]=array("type"=>self::TYPE_LUA,"content"=>$compiled);
$last_lua=$ends[$j][1]+strlen($ends[$j][0]);
break;
}
}
if ($j<0)
throw new Exception("Parse error");
$ends=array();
}
$in_lua=true;
$lua_start=$matches[$i][0][1];
$len=$lua_start-$last_lua;
if ($len>0)
$views[]=array("type"=>self::TYPE_STATIC,"content"=>substr($content,$last_lua,$len));
}
elseif ($in_lua && $matches[$i][3][0]=="?>")
{
$ends[]=$matches[$i][0];
}
}
if ($in_lua)
{
$ends_len=sizeof($ends);
if ($ends_len>0)
{
// stupid trial and error
for ($j=$ends_len-1;$j>=0;$j--)
{
$lua_script=substr($content,$lua_start+5,$ends[$j][1]-($lua_start+5));
$compiled=lua::compile(substr($content,$lua_start+5,$ends[$j][1]-($lua_start+5)));
if ($compiled)
{
$views[]=array("type"=>self::TYPE_LUA,"content"=>$compiled);
$last_lua=$ends[$j][1]+strlen($ends[$j][0]);
break;
}
}
if ($j<0)
throw new Exception("Parse error");
$ends=array();
}
}
if ($last_lua<strlen($content)-1)
{
$static=substr($content,$last_lua);
$views[]=array("type"=>self::TYPE_STATIC,"content"=>$static);
}
foreach ($views as $view)
{
if ($view["type"]==self::TYPE_STATIC)
print $view["content"];
else
$this->_lua->evaluate($view["content"]);
}
}
}
?>
Your webdesign sucks
Yes
Bugs and wishes
By mail to andreas.streichardt _klammerÀffche_ globalpark.com