如何执行字符串的PHP代码

最近因项目需要,引出一个议题:如何执行字符串的php代码(php和html混写)。
注:传统情况下,php代码存储在文件中,直接运行文件即可。以下讨论的情况是,如果php代码是从数据库中获取到,那么要如何运行?

最直观的方案

  • 将字符串代码写到临时文件,然后在项目中include该文件,执行完成再删除这个临时文件
  • system exec 之类的系统函数
  • php函数eval (会不会有安全问题?)

进一步的瞎想

  • 把字符串代码当做参数,传入到php的cli或者php-fpm中运行
  • 重新定义include,让include可以直接操作字符串

几种思路的验证

  • 1:写临时文件,然后include文件。豪无疑问,可行。那么岂不是每次都要写文件,每个请求都要写一次文件。好吧,总有办法解决,缓存+过期验证之类的,但总感觉这方案不够专业。。
  • 2:system exec之类的函数。稍微思考下就会明白,这类函数是执行系统命令,不是运行php代码
  • 3:eval函数,手册上写着:

    Caution :The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.

  • 4: php-fpm cli模式是否有办法解决此类问题
    初步设想是把字符串代码传到fpm、cli模式中,等待返回结果。
    但有一个硬伤,需要执行的字符串代码是有上下文的。比如字符串代码中使用了一个变量$_GET,如果把这个字符串代码传到fpm中,而$_GET变量并没有传过去,那代码还是没办法正常运行。
  • 5:include能不能直接操作字符串
    好吧,前面的4种方法好像都不太满意,那就深挖一下这个思路吧

    首先,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");

好吧,以上提供的大部分都是思路,希望思路对你有用

时间: 2024-08-03 17:21:19

如何执行字符串的PHP代码的相关文章

9_任意代码执行(字符串转换成代码执行)

一.背景介绍 当应用在调用一些能将字符串转化为代码的函数(如php中的eval)时,没有考虑用户是否能控制这个字符串,将造成代码注入漏洞.狭义的代码注入通常指将可执行代码注入到当前页面中,如php的eval函数,可以将字符串代表的代码作为php代码执行,当用户能够控制这段字符串时,将产生代码注入代码注入漏洞(也称命令执行).广义上的代码注入,可以覆盖大半安全漏洞的分类. 二.漏洞成因 几种常用语言,都有将字符串转化成代码去执行的相关函数. PHP:eval assert Python:exec

C#动态执行字符串(动态创建代码)

在编写C#程序的时候,有时我们需要动态生成一些代码并执行.然而C#不像JavaScript有一个Eval函数,可以动态的执行代码.所有这些功能都要我们自己去完成.如下是实例. 动态创建代码: using System; using System.Data; using System.Configuration; using System.Text; using System.CodeDom.Compiler; using Microsoft.CSharp; using System.Reflec

执行字符串或注释代码段的方法

eval:计算字符串中的表达式exec:执行字符串中的语句execfile:用来执行一个文件 需注意的是,exec是一个语句,而eval()和execfile()则是内建built-in函数. 1 2 3 4 5 6 7 8 Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits

Effective JavaScript Item 27 使用闭包而不是字符串来封装代码

本系列作为Effective JavaScript的读书笔记. 对于代码封装,在JavaScript中有两种方式可以办到.第一种就是使用function,第二种则是利用eval()函数,传入到该函数的字符串参数可以是一段代码. 当对使用哪种方式犹豫不决时,使用function.因为使用字符串的一个重要缺点是,传入的字符串并不是一个闭包,而function则可以代表一个闭包.关于闭包的特点,在Item 11中进行了描述. 下面是一段使用字符串来封装代码的例子: function repeat(n,

python中执行字符串形式的语句和字符串形式的表达式方法(即exec和eval方法)

前阵子一直在思考一个问题,就是如何让用户在图形界面上输入的代码(输入的代码为字符串),成为代码的一部分而运行起来,恰逢看python爬虫的视频教程的时候,看到了使用eval函数,之后查找到了该文章,解决了我思考的问题. @文章来源:https://my.oschina.net/duhaizhang/blog/66048 Python有时需要动态的创造Python代码,然后将其作为语句执行  或  作为表达式计算. exec用于执行存储在字符串中的Python代码.   1. 语句与表达式的区别:

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

Java执行字符串中的运算公式

在实现执行字符串中的运算公式时,采用了如下所示的代码: public static String StringfinalResult (String original) { try { String temp = (String)jse.eval(original); return temp; } catch (Exception t) { return null; } } 调用该函数后控制台输出为null 应修改为如下所示的代码: public static String Stringfina

也谈C#之Json,从Json字符串到类代码

原文:也谈C#之Json,从Json字符串到类代码  阅读目录 json转类对象 逆思考 从json字符串自动生成C#类  json转类对象 自从.net 4.0开始,微软提供了一整套的针对json进行处理的方案.其中,就有如何把json字符串转化成C#类对象,其实这段代码很多人都清楚,大家也都认识,我就不多说,先贴代码. 1.添加引用 System.Web.Extensions 2.测试一下代码 1 static class Program 2 { 3 /// <summary> 4 ///

编程算法 - 把字符串转换为整数 代码(C)

把字符串转换为整数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 写一个函数StrToInt, 模拟atoi的功能, 把字符串转换为整数. 须要考虑异常处理, 正负数, 还有Int的最大值(0x7FFFFFFF)和最小值(0x80000000)等情况. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spike */ #include <stdio.h> #include &l