2014-10-12 3 views
0

У меня есть код PHP на моем сайте, который читает строку из файла и echo с этой строкой. В одной из этих строк cade я поместил переменную конкатенацию в виде {$varname}, но в конечном итоге это фактически echos {$ varname} вместо ее переключения с переменной.Перемещение переменной PHP внутри строки файла

Линия гласит:

<p>Today's date (at the server) is {$date}.</p>

Код, используемый для эха линии гласит:

$line = fgets($posts);
echo $line;

И выход из этого кода: «Текущая дата (на сервере) - {$ date}. '

И переменная $date заявлена ​​ранее в коде. Мне интересно, есть ли какой-то особый способ сделать это для строк в файле, или если я не буду делать это правильно?

EDIT: Выходной сигнал также доступен по цене http://codegamecentral.grn.cc/main/?pageNumber=2.

ДРУГОЙ РЕДАКТИРОВАНИЕ: этот код запускается через цикл while, пока не дойдет до конца файла, прочитайте строку за строкой. Это предпочтительно должно быть быстрым решением, которое не вызовет проблем при использовании со строкой, которая не содержит {$date}.

+0

'{}. Это может помочь –

+0

. Ответы ниже, как представляется, дают хорошее решение, но, не видя слишком много кода, если '{$ date}' «предполагается» заменяться в коде уже, но isn ' t, то проблема, вероятно, в том, что вы используете одиночные кавычки '' ', а не двойные кавычки' '' в строке. PHP интерпретирует '' {$ var} ''как литеральную строку в сравнении с' "{$ var}" 'как переменная. –

ответ

1

Вы читаете строку в виде текста, и PHP замена не будет работать, если это не сделано против кода.

Вам нужна более сложная обработка (или, чтобы сказать PHP, чтобы рассмотреть этот текст так, как если бы это был код, с использованием eval), который сильно обескуражен по соображениям безопасности и может не работать повсюду, поскольку функция 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> 

Предостережения

Эта реализация является более безопасным, чем прямо eval(), который будет выполнять любой PHP код вообще он должен был найти в строке для чтения. Но он все еще может использоваться для вывода содержимого любой определенной переменной, если злоумышленник знает свое имя и ему разрешено запрашивать его; предположительно нереалистичным примером будет <p>Hello, {$adminPassword}!</p>.

Чтобы быть более безопасными по-прежнему, хотя и за счет гибкости, я бы одобрить решение Виктора Свенссон, который позволяет только очень специфические переменные, которые будут установлены, и проще и быстрее:

// 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); 

Кроме того, вам может быть интересно проверить некоторые шаблонные решения, такие как Smarty.

Обработка весь файл

Чтобы обработать весь файл, если память не является объектом, вы можете в обоих случаях (препрега и str_) загрузить весь файл в массив строк:

$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. 
} 

Скорость

Что-то один не часто ценят то, что регулярные выражения быстро. Я не знаю, какой алгоритм сопоставления текста str_replace использует (I думаю Boyer-Moore's), но preg имеет то преимущество, что Perlishly поддерживает массив. Он имеет более тяжелую настройку (линейную по размеру словаря), но затем она «масштабируется» лучше во время замены, а str_replace - постоянная установка, линейно масштабируется в течение времени замены. Это означает, что preg_replace будет экономить огромное количество раз в массовых заменах; это намного хуже в более простых контекстах.

Очень примерно, время выполнения является (S + R L V) * V (V = число переменных, L = число строк), где preg_replace имеет детектируемого S и незначительное R, в то время ул есть наоборот. При больших значениях V вы действительно хотите наименьшее R вы можете получить, даже за счет увеличения времени установки S.

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% 

Конечно, ремонтопригодность также является проблемой - str_replace делает это в одна строка, а сама функция поддерживается командой PHP. Для функции, построенной вокруг preg_replace, требуется до 15 строк. Конечно, после тестирования вам больше не нужно его изменять, просто передайте ему словарь.

Looping

Наконец, вы можете использовать переменные со ссылкой на другие переменные. В этом случае ни PREG, ни str_ будет надежно работать, и вы должны реализовать цикл самостоятельно:

<?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"; 

Выход:

PREG: This is a test. And another {$test}. And yet {$another} {$test}. 
STR_: This is a test. And another {$test}. And yet {$another} {$test}. 
LOOP: This is a test. And another test. And yet another test test. 
+0

Меньший скрипт внизу выглядит лучше для меня, поскольку он зацикливается на 'while' (так что чем быстрее, тем лучше), но мне было интересно, приведет ли это к нежелательным побочным эффектам, эффекты, если они используются в строке, в которой нет '{$ date}'? – MineAndCraft12

+0

Не следует. Конечно же, маркеры, которые там не действуют, не имеют никакого эффекта, кроме незначительной задержки обработки. Кроме того, возможно, вы можете обойтись без 'while'. – LSerni

+0

Ничего себе, это много усилий в этом! Я сомневаюсь, что я буду использовать несколько переменных в любой из строк, и размер строк (вероятно) не станет слишком большим, но я буду помнить об этом, потому что если я сделаю что-то, что им понадобится , Я думаю, что на данный момент я начну с меньшего 'str_replace', но позже может перейти к некоторым из этих других. Благодаря! (Я бы поднял это, но мой уровень недостаточно высок) – MineAndCraft12

2

Это, как вы можете сделать то, что вы хотите:

eval("\$line = \"$line\";"); 
echo $line; 

Предупреждение: Хотя это будет делать эту работу, я бы сильно препятствовать вам это делать, если у вас нет 100% уверенности, что только вы или доверенные люди могут генерировать файлы, которые будут оцениваться таким образом, потому что eval() может запускать любой PHP-код внутри переменной.

3

Как насчет string_replace()?

echo str_replace('{$date}', $date, $line); 
+0

+1 для простоты :-) – LSerni

+0

Конечно, изменил ее ...;) –

+1

Это часто бывает, как люди делают шаблоны, но чтобы избежать путаницы между переменной и своего рода« токеном », для замены они используют другой синтаксис, поэтому вместо '{$ date}' они будут использовать '% date%'. Если вы сделаете последнее, вы также можете написать функцию, которая делает: 'return str_replace («% {$ key}%», $ value, $ line); 'динамически над массивом, который построен, соответственно' $ key => $ value'. –

Смежные вопросы