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-кодом \
Иногда приходится решать обратную задачу - экранировать "опасные" символы обратными слэшами. Добавить бэкслеши при выключенной настройке 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-сущности".
<
, >
и т.д. Сделала это стандартная функция 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 просмотра]