最近因项目需要,引出一个议题:如何执行字符串的php代码(php和html混写)。 注:传统情况下,php代码存储在文件中,直接运行文件即可。以下讨论的情况是,如果php代码是从数据库中获取到,那么要如何运行? 最直观的方案
进一步的瞎想
几种思路的验证
** 首先,php中的include是什么原理?** 并没有去看过源码,猜一下吧,1:读取文件(fopen,fread之类的)2:解析php语法 3:运行代码 ** 那么,如果可以让fopen,fread操作字符串,也许这个问题就解决了?** 设想:把字符串转换为一个对象或者流,提供fopen,fread接口。首先想到php的SPL中应该有此类接口,查php官方手册,找到php手册中关于”支持的协议与封装协议“章节(同事也提过使用自定义协议的方式),以下为测试的最简demo:(封装自定义协议,使用include直接操作字符串) <?php //业务需要:从数据库中读出字符串的php代码 function mysql_get($id) { return '<?php $i = '.$id.'; echo "contextValue: ".$contextName."\n"; echo "hello $i \n"; '; } //自定义协议 class VariableStream { private $string; private $position; public function stream_open($path, $mode, $options, &$opened_path) { $url = parse_url($path); $id = $url["host"]; //根据ID到数据库中取出php字符串代码 $this->string = mysql_get($id); $this->position = 0; return true; } public function stream_read($count) { $ret = substr($this->string, $this->position, $count); $this->position += strlen($ret); return $ret; } public function stream_eof() {} public function stream_stat() {} } stream_wrapper_register("var", "VariableStream"); //上下文变量 $contextName = "1000"; //include字符串php代码。(php代码是从数据库中读出来,这里传入的199是数据库的主键ID) include("var://199"); //修改上下文变量 $contextName = "2000"; //引入另一个字符串php代码 include("var://299"); OK,终于找到一种解决思路。再继续思考,既然我们希望最终的展示是include这种方式,include的内部是fopen之类的系统函数,那么fopen除了支持自定义协议之外,还支持哪些呢? 手册中,fopen的第一个参数$filename,可以是文件名,也可以是"scheme://..." 的格式,第二种格式就是上面说的自定义协议方式。再继续查看相关的东西,发现SplFileInfo、 stream_context_create,不过并不能解决问题。 总结现在已经有3种方式可以做成这个事情,那么哪种方式更好 1:写临时文件,加缓存,直接include 2: eval,官方手册上说这个函数有安全问题 3:自定义协议,直接include 首先排除方法1,原因1:缓存文件会增加硬盘I/O。原因2:不够专业(这不是小问题) 至于eval提到的安全问题,仔细阅读手册上写的那段话后,发现他只是提示你现在正在运行一段项目代码以外的代码,请多小心。这样看来,方法2并没有比方法3更危险。 选取标准,如果项目中只有一个很小的功能需要执行php字符串,那直接使用eval即可 如果项目中有大量的此类需求,封装一个自定义协议会很方便。项目中的引用会是这样的: include("protocolName://param"); 好吧,以上提供的大部分都是思路,希望思路对你有用 (责任编辑:最模板) |