双美元符+{}:${${variable}}是一种比较常见的用法,但是它的实现原理是什么呢?今天来探究一下:

提及这种用法,还得先说一下PHP的String类型
php.net上指出,一个字符串可以用4种方式表达:单引号,双引号,heredoc语法结构,nowdoc语法结构
这里heredoc语法结构和双引号形式类似,同样nowdoc结构对应单引号

单引号:单引号包围起来的字符串中,单引号必须转义才能使用(\'),否则会报语法错误;而用于转义的反斜线自身,则要用两个反斜线(\\),即也需要转义. 文档说"其他任何形式的反斜线都被当成反斜线本身:也就是说如果想使用其它转义序列例如 \r 或者 \n,并不代表任何特殊含义,就单纯是这两个字符本身",这就是说单引号包围起来的其他转义序列根本没有实现转义.

反过来说,\是可以直接作为反斜线使用的,因此单引号包围的字符串中\\和\其实都能表示反斜线本身,验证实例如下:

<?php
echo 'You deleted C:\\*.*?';
echo 'You deleted C:\*.*?';
echo 'This will not expand: \n a newline';
echo 'Variables do not $expand $either';
?>

双引号:当字符串包围在双引号中,PHP会对一些特殊字符解析,这里\n,\r,\t都正常解析为转义符,而且反斜线、美元符、双引号都需要转义:\\, \$, \"

heredoc和nowdoc不如引号用起来方便,但是可以实现相同的目的

再说变量解析,文档的说法是当字符串遇到双引号或heredoc结构定义时,其中的变量将会被解析;变量解析有两种语法规则,简单的和复杂的,其中复杂规则的显著标记是用花括号包围的表达式;

对于简单规则而言,当 PHP 解析器遇到一个美元符号($)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。可以用花括号来明确变量名的界线。

<?php
$juice = "apple";
echo "He drank some juice made of ${juice}s.";
?>

复杂语法:复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。

任何具有 string 表达的标量变量,数组单元或对象属性都可使用此语法。只需简单地像在 string 以外的地方那样写出表达式,然后用花括号 { 和 } 把它括起来即可。由于 { 无法被转义,只有 $ 紧挨着 { 时才会被识别。可以用 {\$ 来表达 {$。

<?php
$great = 'fantastic'; // 无效,输出: This is { fantastic}
echo "This is { $great}"; // 有效,输出: This is fantastic
echo "This is {$great}";
echo "This is ${great}";
echo "This is the value of the var named $name: {${$name}}";
?>

测试得到以上两条echo变量great的语句输出同样的结果,所以{${$name}}其实和${${name}}也是一样的

另外,php.net的文档中给出了Note:

"函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在 {$} 中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({}) 无法处理从函数或方法的返回值或者类常量以及类静态变量的值。"

这里说的很清楚,只有单一{}无法处理返回值等,因为像${name}只是得到变量的名字,告诉我们这是变量name,即得到一个$name,假如我需要$name的值,那我就得对他再解析一次
所以像:

<!--
#GOAL: gather some phpinfo(); $str=@(string)$_GET['str'];
eval('$str="'.addslashes($str).'";');
-->

实现的方法是传入参数:str=${${phpinfo()}}
这里如果直接上phpinfo(),由于有addslashes的作用会出现\"的情况使得命令无法执行
${phpinfo()}告诉我们最里面这个是变量,名为phpinfo(),接下来的一层花括号将其解析为字符串"phpinfo()"
另外,{}有时候也可以当[]使用,文档中有说明:"Note: string 也可用花括号访问,比如 $str{42}",这里$str{42}==$str[42]

在《白帽子讲web安全》一书中也提到了同样的应用:
”PHP的curly systax能导致代码执行,它将执行花括号间的代码,并将结果替换回去,如下例:
<?php $var = "I was innocent until ${`ls`}" appeared here; ?>"
ls得到执行,列出本地目录并将结果返回

随机推荐

  1. Azure PowerShell (1) PowerShell整理

    <Windows Azure Platform 系列文章目录> 把之前Azure ASM的PowerShell都整理好了. https://github.com/leizhang1984/ ...

  2. 用Latex写学术论文:作者(Author)&摘要(Abstract)

    标题&作者 1.标题 \title{} "Line breaks (\\) may be used to equalize the length of the title lines ...

  3. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

  4. 实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法

    废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namesp ...

  5. ASP.NET Core 发布至Linux生产环境 Ubuntu 系统

    ASP.NET Core 发布至Linux生产环境 Ubuntu 系统,之前跟大家讲解了 dotnet publish 发布,而没有将整个系统串起来. 今天就跟大家综合的讲一下ASP.NET Core ...

  6. Web端权限管理新增实用功能:批量增加操作,简单方便快速!

    扩展了吉日嘎拉的Web端权限管理功能后,每次添加菜单倒没啥问题,毕竟菜单的数量有限,可是每增加一个模块.功能或者说权限控制点,就得针对各种常规操作,新增很多遍. 浪费时间,还容易出错.新增了一个字典表 ...

  7. Eclipse设置风格

    如果觉得Eclipse的颜色太刺眼,可以修改背景与字体颜色,方法如下: (1)到http://eclipsecolorthemes.org/下载主题文件,可以选择xml文件或者epf文件: (2)Ec ...

  8. 【Java每日一题】20161019

    20161018问题解析请点击今日问题下方的"[Java每日一题]20161019"查看 package Oct2016; import java.util.List; publi ...

  9. 内存只有4G的MBP要怎么破

    开发工具包括浏览器都是极占内存的,没有个8G根本不行啊. 怎一个慢字了得? 补记: 放弃谷歌浏览器是正道

  10. Java--关于计算表达式中赋值的细节问题

    public class Test { public static void main(String[] args) { int t = 0; int p = 0; int q = 0; int ta ...