我的网站上有一些PHP代码,它从文件和echo
那一行读取一行。在其中一个cade行中,我以{$varname}
的形式放置了一个变量连接,但最终结果它实际上是echos {$ varname}而不是用变量切换它。
该行显示:
<p>Today's date (at the server) is {$date}.</p>
用于回显该行的代码为:
$line = fgets($posts);
echo $line;
该代码的输出为:&#39;今天的日期(在服务器上)为{$ date}。&#39;
变量$date
在代码中先前声明。我想知道是否有一些特殊的方法可以为文件中的行做这个,或者我是不是这样做了?
编辑:输出也可在http://codegamecentral.grn.cc/main/?pageNumber=2获得。
另一个编辑:此代码通过while循环运行,直到它到达文件末尾,逐行读取。这应该是一个快速的解决方案,当与不包含{$date}
的字符串一起使用时不会引起问题。
答案 0 :(得分:3)
string_replace()
怎么样?
echo str_replace('{$date}', $date, $line);
答案 1 :(得分:2)
这就是你可以做你想做的事情:
eval("\$line = \"$line\";");
echo $line;
警告:强>
虽然这可以完成这项工作,但我强烈建议你不要这样做,除非你100%确定只有你或者可信赖的人才能生成将以这种方式评估的文件,因为eval()
可以在里面运行任何PHP代码。变量。
答案 2 :(得分:1)
您正在以文本形式阅读一行,除非针对代码完成,否则PHP替换将无效。
您需要一些更复杂的处理(或者告诉PHP将该文本视为代码,使用eval
;出于安全原因,强烈建议不要这样做,并且可能无法在任何地方使用{{1出于同样的安全原因,网站管理员有时会禁用此功能。
最强大的替代方法是使用eval
识别preg_replace_callback
等文本序列,并将其替换为{$varname}
。当然,$varname
需要定义或检查是否存在:
$varname
输出:
function expandVariables($text, $allowedVariables) {
return preg_replace_callback('#{\$([a-z][a-z_0-9]*)}#i',
function($replace) use ($allowedVariables) {
if (array_key_exists($replace[1], $allowedVariables)) {
return $allowedVariables[$replace[1]];
}
return "NO '{$replace[1]} VARIABLE HERE.";
},
$text
);
}
$date = date('Y-m-d H:i:s');
$line = '<p>Now (at the server) is {$date}.</p>';
$vars = get_defined_vars(); // LOTS of memory :-(
// better:
// $vars = array ( 'date' => $date, ... ); // Only allowed variables.
$eval = expandVariables($line, $vars);
print "The line is {$line}\nand becomes:\n{$eval}";
这个实现比直接The line is <p>Now (at the server) is {$date}.</p>
and becomes:
<p>Now (at the server) is 2014-10-12 18:36:16.</p>
更安全,它将执行在读取行中找到的所有的任何PHP代码。 但它仍可用于输出任何已定义变量的内容,前提是攻击者知道其名称并允许其请求;一个公认的不切实际的例子是eval()
。
为了更安全,尽管以牺牲灵活性为代价,我赞同Viktor Svensson的解决方案,该解决方案只允许设置非常具体的变量,并且既简单又快捷:
<p>Hello, {$adminPassword}!</p>
此外,您可能有兴趣查看一些模板解决方案,例如Smarty。
要处理整个文件,如果内存不是对象,则在两种情况下(preg和str_)都可以将整个文件作为一个行数组加载:
// Remember to use 'single quotes' for '{$variables}', because you DO NOT
// want expanded them in here, but in the replaced text!
$text = str_replace(array('{$date}', '{$time}' /*, ...more... */),
array(date('Y-m-d'), date('H:i:s') /*, ...more... */),
$text);
并使用$file = file($fileName);
作为替换的主题。然后你可以迭代结果:
$file
人们通常不会欣赏的是正则表达式快速。我不知道文本匹配算法// replaceVariables receives a string and returns a string
// or receives an array of strings and returns the same.
$text = replaceVariables($file, $variables);
foreach ($text as $line) {
// Do something with $line, where variables have already been replaced.
}
采用了什么(我认为 Boyer-Moore's),但preg具有Perlishly数组感知的优势。它具有较重的设置(在字典大小上呈线性),但随后在更换时间内“缩放”得更好,而str_replace
是常量设置,在替换时间内线性缩放。这意味着str_replace
将在大规模替代中节省大量时间;在更简单的背景下,情况会更糟。
非常大致,运行时间为(S + R L V)* V(V =变量数,L =行数)其中preg_replace具有可检测性S和可忽略不计的R,而str则相反。使用较大的V值时,您确实需要最小的R,即使代价是设置时间S增加。
preg_replace
当然,可维护性也是一个问题 - Dependency on Variable N.. ? variables, 18 lines, keylen 5, vallen 20
v preg advantage
5 -82%
15 -55%
25 -2%
35 14%
45 65%
55 41%
65 51%
75 197%
85 134%
95 338%
Dependency on File length. 32 variables, ? lines, keylen 5, vallen 20
l preg advantage
5 -31%
15 -33%
25 14%
35 80%
45 116%
在一个代码行中执行,并且函数本身由PHP团队维护。围绕str_replace
构建的函数需要多达15行。当然,经过测试,您不需要再修改它,只需将它传递给字典。
最后,您可能希望使用变量引用其他变量。在这种情况下,preg和str_都不会可靠地工作,你必须实现自己的循环:
preg_replace
输出结果为:
<?php
$file = "This is a {\$test}. And {\$another}. And {\$yet_another}.\n";
$vars = array(
"test" => "test",
"another" => "another {\$test}",
"yet_another" => "yet {\$another} {\$test}",
);
$text = preg_replace_callback('#{\$([a-z][a-z_0-9]*)}#i',
function($replace) use ($vars) {
if (array_key_exists($replace[1], $vars)) {
return $vars[$replace[1]];
}
return "NO '{$replace[1]} VARIABLE HERE.";
},
$file
);
$keys = array_map(function($k){ return "{\${$k}}"; }, array_keys($vars));
$vals = array_values($vars);
$text2 = str_replace($keys, $vals, $file);
$text3 = $file;
do {
$prev = $text3;
$text3 = str_replace($keys, $vals, $text3);
} while ($text3 != $prev);
print "PREG: {$text}\nSTR_: {$text2}\nLOOP: {$text3}\n";