[PHP — пользовательские данные]материал подготовил: Дмитрий Турецкий 25.05.2004
Каждый веб-сайт по роду своей деятельности должен принимать и обрабатывать данные от пользователей, и чем более динамическим сайт становится, тем больше «чужих» данных он использует в своей работе. Но нередко случается так, что посетители, умышленно или неумышленно, передают сайту совсем не те данные, которые он ожидает, что порой может приводить к весьма неприятным последствиям… И сегодня мы поговорим об основных приемах работы с пользовательскими данными в PHP-скриптах…
Самое главное правило заключается в том, что чужим данным нельзя доверять. Перед тем как вы будете вынуждены их использовать, обязательно проверьте соответствие переданных данных ожидаемому типу и диапазону значений.
Рассмотрим простой пример: пользователь запрашивает страницу сайта, передавая в качестве GET-параметра идентификатор статьи, а ваш сервер делает запрос к базе данных и «вытаскивает» эту статью. То есть адрес выглядит как:
http://www.mysite.ru/page.php?id=3
а запрос к базе в скрипте выполняется в виде:
$SQL = «SELECT * FROM articles WHERE id=$_GET[id]»;
Такой пример будет замечательно работать, до тех пор пока кто-то не запросит страницу без параметров — в этом случае переменная $_GET[id] окажется пустой, и запрос к базе выдаст ошибку. Предположим, что вы эту ошибку решите исправить и напишете что-то вроде:
if ($_GET[‘id’]) $SQL = «SELECT * FROM articles WHERE id=$_GET[id]»; else $SQL = «SELECT * FROM articles ORDER BY random() LIMIT 1»;
Такой скрипт действительно корректно обработает пустой запрос — выдаст случайную статью — но что если посетитель запросит адрес:
http://www.mysite.ru/page.php?id=vasya
Снова база отрапортует об ошибке — несоответствие типа данных. Поэтому надо проверять еще и тип. Практика показывает, что удобнее всего бывает вынести в начало скрипта блок кода, занимающийся инициализацией и проверкой переменных, а в самом скрипте уже использовать только их. Например:
$id = (isset($_GET[‘id’])) ? (int) $_GET[‘id’] : 0; if ($id) $SQL = «SELECT * FROM articles WHERE id=$id» else $SQL = «SELECT * FROM articles ORDER BY random() LIMIT 1»;
Необходимо проверять и тип и диапазон разрешенных значений данных
Такая конструкция гарантирует, что переменная $id у вас инициализирована и является целочисленной. Разумеется, она может выходить за пределы имеющихся статей, но тут уже после запроса к базе будет достаточно проверить количество полученных записей — это проще и менее ресурсоемко, чем при каждом вызове страницы проверять, есть ли в базе соответствующая запись.
Однако в некоторых случаях проверка разрешенного диапазона значений является необходимой. Предположим, что у вас есть скрипт, который, в зависимости от переданного пользователем параметра, читает и выдает в браузер какой-то файл:
if (file_exists($_GET[‘page’])) readfile($_GET[‘page’]); else readfile(‘default.html’);
Переменные надо инициализировать перед использованием
Казалось бы, здесь защита предусмотрена — вы честно проверили, что запрошенный файл существует. Но на самом деле подобная конструкция является одной из наиболее типичных «уязвимостей». Дело в том, что по умолчанию PHP разрешает использовать в файло