双美元符+{}:${${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. JS实现弹出层对话框

    点击按钮后,弹出层对话框,可交互,点击关闭后才关闭掉对话框. 效果图: 源码: <!doctype html> <html> <head> <meta cha ...

  2. Lagrange插值公式

    朋友@耗子突然问起我一个 Lagrange 插值公式的问题,发现几年没碰差不多要忘干净了,于是找了本教科书来翻了翻,顺便把几个要点整理成文,以备日后查阅. 作者: peghoty 出处: http:/ ...

  3. 用原生JS读写CSS样式的方法总结

    为了日后方便查询,本人翻阅了一些资料总结了以下方法,仅限原生JS,如有不对的地方欢迎指出!只求大家看完觉得有学到点什么就OK了!   一.可以通过DOM节点对象的style对象(即CSSStyleDe ...

  4. Python语言特性之2:元类

    问题:Python中的元类(metaclasses)是什么?一般使用它干什么? 原地址:http://stackoverflow.com/questions/100003/what-is-a-meta ...

  5. JS的跳转

    需要在下面的button中实现跳转,之前直接写了个<a>标签,但是在手机上的效果太差了,这是老大写的 js跳转.记下来,要学会贯通. <div class="ps-lt&q ...

  6. 从C#到Objective-C,循序渐进学习苹果开发(3)--分类(category)和协议Protocal的理解

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本文继续上一篇随笔<从 ...

  7. EF生成 类型“System.Data.Entity.DbContext”在未被引用的程序集中定义

    错误描述: 1 类型“System.Data.Entity.DbContext”在未被引用的程序集中定义.必须添加对程序集“EntityFramework, Version=5.0.0.0, Cult ...

  8. Swift 值类型和引用类型

    Swift中的类型分为两类:一,值类型(value types),每个值类型的实例都拥有各自唯一的数据,通常它们是结构体,枚举或元组:二,引用类型(reference types),引用类型的实例共享 ...

  9. 第三讲:WCF介绍(3)

    代码 https://yunpan.cn/cPns5DkGnRGNs   密码:3913   前面我们通过一个小的例子,大概了解的WCF. 这里我们补充下  EndPoint 配置  A,B,C  中 ...

  10. 以Unix之名

    即便有了MBP,有时,还是想把MBP装上一个Linux发行版,因为习惯了Linux下的折腾. 但每次想要动手安装时,都会告诉自己,MacOS是很纯正的Unix系统,这样,内心的冲动就可以再多压一压. ...