奇怪而令人困惑的PHP语法

4
我将接手维护一个旧网站,发现了这个我从未见过的处理表单的语法,让我感到困惑,我也不确定它具体是干什么的:
foreach (array('address','comments','country','email','mail_content','name','title') as $vuln) 
{
    isset($_REQUEST[$vuln]) and $_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
    isset($_GET[$vuln]) and $_GET[$vuln] = htmlentities($_GET[$vuln]);
    isset($_POST[$vuln]) and $_POST[$vuln] = htmlentities($_POST[$vuln]);
    isset($$vuln) and $$vuln = htmlentities($$vuln);
}

让我有点困惑的是其中的 "and" - 我把它理解为 "如果变量已经设置,将其转换为html实体,但是为什么还需要一个 'and'?

最后一行代码是做什么用的呢?

isset($$vuln) and $$vuln = htmlentities($$vuln);

1
我不知道开发者为什么要使用 REQUESTGETPOST$$vuln 是一个变量变量。请参考 http://php.net/manual/zh/language.variables.variable.php。 - chris85
感谢大家的快速和详细的回答 - 很想接受你们所有人的答案,但不行... - BigMac66
4个回答

7
它以一种不寻常的方式使用了 PHP 的运算符优先级规则。
如果你有一个and语句,PHP 会在左侧为假时停止处理它 - 没有必要检查右侧,因为它对最终结果没有影响。(同样适用于or语句,如果左侧为真。)
所以编写此代码的程序员将其用作简写:
if (isset($_REQUEST[$vuln])) {
    $_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
}

他们节省了一些打字的时间,但代价是使代码稍微难以阅读。使用isset来确保在使用数组值之前已经设置它们是一个好习惯,这就是为什么要进行检查的原因。
至于最后一行; 逻辑上,它与上面的代码相同,但使用了variable variable。第一次通过,$vuln将被设置为数组中的第一个项目,即address - 最后一行代码正在检查是否有名为$address的变量,如果有,则将其值设置为htmlentities($address)
这就是代码在做什么。至于为什么要检查REQUEST、GET和POST,我不知道。

2
isset($var) and <statement goes here that uses $var>;

如果在and之前的语句(在这种情况下是isset($var))评估为true,则基本上只执行<statement ...>。这是因为如果在and之前有任何错误,就没有必要评估(或执行)其余部分。这类似于:

if (false && condition) { ... }
condition永远不会被评估,因为无论其值评估为何,if条件始终将评估为false
第一个示例的更易读的替代方案:
if (isset($var)) {
   <statement goes here that uses $var>;
}

正如@chris85在评论中指出的,可以参考$$variable

变量变量的一个例子:

$vuln = 'abc';  /* Regular variable assignment */
$$vuln = 'def'; /* This is "equivalent" to $abc = 'def'
                 * because $$vuln expands to $<contents of $vuln>,
                 * therefore $abc is assigned with 'def'.
                 */

/* $abc is now a variable with 'def' as its value */

2

嗨,这些都是缩写形式。

 isset($_REQUEST[$vuln]) and $_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);

上面一行的意思是:

if(isset($_REQUEST[$vuln])){
$_REQUEST[$vuln] = htmlentities($_REQUEST[$vuln]);
}

此外,$$vuln 是一个 引用 变量,它检查相同的内容,即如果引用 变量 已经设置,则将其赋值。


2
以下是更易理解的方式,针对数组的第一次迭代:
<?php

if(isset($_REQUEST['address'])) {
    $_REQUEST['address'] = htmlentities($_REQUEST['address']);
}
if(isset($_GET['address'])) {
    $_GET['address'] = htmlentities($_GET['address']);
}
if(isset($_POST['address'])) {
    $_POST['address'] = htmlentities($_POST['address']);
}
if(isset($address)) {
    $address = htmlentities($address);
}

我认为这是遗留代码,可能是在“register globals”开启时替代(或者是另外一种方式)“魔术引号”的。很可能是为了在数据库插入和页面输出之前对变量进行伪转义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接