最近因项目需要,引出一个议题:如何执行字符串的 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=p
- arse_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");
好吧,以上提供的大部分都是思路,希望思路对你有用
来源: http://www.cnblogs.com/dormscript/p/6163774.html