БлогNot. PHP: ещё раз про кавычки, удаление пробелов и константы PHP_INI_*

PHP: ещё раз про кавычки, удаление пробелов и константы PHP_INI_*

В PHP7 большинство описанных в статье проблем уже не актуально, переходите на новые версии!

Типовая задача исключения из ввода пользователя лишних пробелов и/или тегов решается практически в каждом профессиональном скрипте на PHP.

Удалить теги легко стандартной функцией strip_tags, а вот чтобы удалить все лишние пробелы (в том числе, между словами), нам недостаточно стандартной trim, как минимум, нужно использовать регулярное выражение:

function trimall($string) { 
 return trim(preg_replace("/\s+/"," ",$string));
}

(или альтернативное выражение, как вот здесь).

Нерешённой останется только проблема с кавычками. Увы, при настройках PHP по умолчанию (в том числе, и в текущей версии 5.3.1), кавычки из строк, переданных методом POST или GET после ввода пользователя, при выводе их на экран могут "экранироваться", то есть, символ " в коде превратится в \":

<?php
 $text='';
 if (isset ($_POST['text'])) {
  $text=strip_tags(trimall($_POST['text']));
  echo $text;
 }
?>

<form method="post">
 <input type="text" name="text" value="<?php echo $text; ?>">
 <input type="submit" value="OK">
</form>

Ввод "слово1" даст на выходе \"слово1\". За настройки кавычек в PHP 4-5 версий отвечают аж 3 переменных, в будущей 6 версии их обещают убрать.

magic_quotes_gpc - если директива включена, все символы ', ", \ и NUL (байт с нулевым кодом) будут автоматически экранироваться бэкслешем \. С версии 5.3.0 опция объявлена устаревшей, будет исключена в PHP 6.0.0. Не меняется программно в версиях старше 4.2.3. По умолчанию включена, именно эта настройка "виновата" в том, что у нас произошло со словом.

magic_quotes_runtime - если включена, то большинство функций, которые возвращают данные из базы или текстовых файлов, будут возвращать заэкранированные теми же бэкслешами двойные и одинарные кавычки. Но это ещё не всё! Если дополнительно включена директива magic_quotes_sybase, то экранируются только одинарные кавычки, причем не обратным слэшем, а такой же одинарной кавычкой! К счастью, этой директивой можно управлять программно, по умолчанию она выключена, в версии 5.3.0 объявлена устаревшей, а в 6.0.0 будет упразднена.

magic_quotes_sybase - как уже сказано, если эта опция включена, то меняется правило экранирования одинарной кавычки, она записывается с дополнительной одинарной кавычкой вместо обратной косой черты, если magic_quotes_gpc или magic_quotes_runtime разрешены. Директивой можно управлять программно, по умолчанию выключена. Нигде не написано, что она объявлена устаревшей, но в PHP 6.0.0 директива также должна быть упразднена.

Как от всего этого не сойти с ума и обеспечить корректную обработку кавычек?

Я не раз уже приводил код функции magic, которая разбирается с этой проблемой, в последнее время она стала вот такой:

function magic ($path) {
 @ini_set('magic_quotes_runtime', '0');
 @ini_set('magic_quotes_sybase', '0');
 //magic_quotes_gpc не меняется программно - см. доки
 if (@get_magic_quotes_gpc()=='1') $path=stripslashes($path);
 return $path;
}

То есть, 2 директивы, которые можно поставить программно, так и ставятся (с удалением контроля ошибок оператором "@" - для будущих версий), третья директива проверяется и при необходимости обрабатываются "лишние" бэкслеши. Последнее выполняется стандартной функцией stripslashes, хотя можно было бы и "ручными" заменами, как я делал раньше:

if (@get_magic_quotes_gpc()=='1') { 
 $path= str_replace ('\\"','"',$path);
 $path= str_replace ("\\'","'",$path);
 $path= str_replace ("\\\\","\\",$path);
}

Функцию get_magic_quotes_gpc также можно бы было не вызывать, ограничившись стандартной ini_get:

if (@ini_get('magic_quotes_gpc')=='1') $path=stripslashes($path);

P.S. При таком подходе функция stripslashes удалит сочетание символов \" даже там, где оно нужно, например, в этом предложении. Как быть? Я просто в таких случаях заменяю символ "\" его HTML-кодом &#92;

Иногда приходится решать обратную задачу - экранировать "опасные" символы обратными слэшами. Добавить бэкслеши при выключенной настройке magic_quotes_gpc можно стандартной функцией addslashes. А вот если magic_quotes_gpc включена, делать addslashes не нужно - получится двойное экранирование... ведь тогда функция addslashes и так автоматически применяется ко всем данным GET, POST, и COOKIE.

Теперь полный код примера, удаляющего из ввода теги, все лишние пробелы между лексемами, не зависящего от настроек кавычек и возвращающего кавычки в форму, стал таким:

<?php
 function trimall($string) { 
  return trim(preg_replace("/\s+/"," ",$string));
 }

 function magic ($path) {
  @ini_set('magic_quotes_runtime', '0');
  @ini_set('magic_quotes_sybase', '0');
  if (@ini_get('magic_quotes_gpc')=='1') $path=stripslashes($path);
  return $path;
 }

 $text='';
 if (isset ($_POST['text'])) {
  $text=strip_tags(trimall(magic($_POST['text'])));
  echo $text;
 }
?>

<form method="post">
 <input type="text" name="text" value="<?php echo htmlspecialchars($text); ?>">
 <input type="submit" value="OK">
</form>

(в примере не хватает открывающих и закрывающих тегов HTML). Как видите, перед тем как выдать в теге <form> текст в качестве значения поля ввода <input> (по стандарту HTML здесь нужен синтаксис value="значение в двойных кавычках"), мы заменили "критичные" для PHP символы <, >, ", ' и & на соответствующие "HTML-сущности". &lt;, &gt; и т.д. Сделала это стандартная функция htmlspecialchars. Вообще говоря, так нужно делать всегда, независимо от настроек кавычек.

Заодно отметим ещё один важный приём, о котором начинающие тоже часто забывают. Перед использованием любой строки в коде формируемого скриптом SQL-запроса не забудьте после соединения с базой применить к этой строке функцию mysql_real_escape_string - в статье стандартной справки по этой функции всё очень хорошо расписано, зачем и почему :)

Наконец, узнать о том, какие директивы файла php.ini какими способами можно менять, легко из так называемых "констант PHP_INI_*", в справке рядом с каждой директивой в столбце Changeable написано одно из 4 значений:

Определение констант PHP_INI_*

PHP_INI_USER - директива может быть установлена в пользовательских скриптах методом ini_set или в реестре Windows;

PHP_INI_PERDIR - директива может быть установлена в файле php.ini, .htaccess или httpd.conf;

PHP_INI_SYSTEM - директива может быть установлена в файле php.ini или httpd.conf;

PHP_INI_ALL - директива может быть установлена где угодно.

 Окончание и самое короткое решение всех проблем с кавычками - на сайте :)

14.06.2011, 17:32 [15463 просмотра]


теги: php программирование

К этой статье пока нет комментариев, Ваш будет первым