Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11656
Последний выпуск: 19.06.2015

Эмуляция директивы register_globals on

Руслан Курепин
http://kurepin.ru/

Есть в PHP такая интересная директива, под названием register_globals, определенная в php.ini. Директива указывает компилятору, что значения входящих (глобальных) переменных следует изъять из их системных массивов и представить в виде самостоятельных переменных. К таким данным относится все, что передается в скрипт "снаружи": данные из форм, данные из URL, cookie и так далее. Лично мне эта директива нравится, ибо она экономит время написания скриптов и делает их более читаемыми. Сравните сами, что выглядит приятнее и удобнее для глаза:

Здравствуйте, уважаемый <?=$_COOKIE['username']>>, мы рады вам!

Здравствуйте, уважаемый <?=$username?>, мы рады вам!

Вообще, лично я люблю PHP в основном за его удобочитаемость и быстрое написание.

Тем не менее, в каждой удобной фишке обязательно таится какая-нибудь гадость. Не обошлось без неприятностей и с регистрацией глобальных переменных. Невнимательные программисты оставляли в своих скриптах дыры, которые можно было обнаружить и использовать со стороны пользователя. Проще говоря, если переменная внутри скрипта участвовала в работе, но не устанавливалась этим же скриптом, ее можно было установить "снаружи", передав ее имя и значение в скрипт через URL, cookie или еще как-нибудь.

Эта дыра, которую записали в разряд "дыр в PHP" лично я считаю дырой в программировании, а не в языке, вынудила разработчиков PHP рекомендовать отключение register_globals. Что тут же было воспринято общественность как руководство к действию: все стали выключать регистрацию глобальных переменных на своих серверах.

Может быть это и не так уж плохо, судить не буду, ведь ради безопасности иногда возводят и городят гораздо больше, чем код самой задачи.

Но повальный отказ от регистрации глобальных переменных привело к новой проблеме - многие скрипты надо переписывать чуть ли не с нуля, ибо надо проверить каждую строку, найти все используемые переменные и поменять их на "защищенные" аналоги.

Насколько я понимаю, подобная задача, в конце концов, сводится к тому, чтобы в начале работы скрипта присвоить привычным переменным их значения из глобальных массивов $_REQUEST, $_POST, $_GET, $_COOKIE, $_SERVER и т.д.

Так к чему же я веду. А вот к чему... Нормальный программист не должен допускать дыр в своих скриптах, подобных дырам на основе автоматической регистрации глобальных переменных, но разве это будет волновать администратора сервера, на котором решено разместить код? Нет, это его не волнует и он по-своему прав.

Поэтому, если вы написали на заказ программу с использованием глобальных переменных, а заказчик решил установить ее на сервере, где запрещена их регистрация, то ничего работать не будет - у вас проблемы.

Если вы решили перенести все свои проекты на новый хостинг, а провайдер запрещает использовать регистрацию глобальных переменных - у вас проблемы.

Как быть? Не вычитывать же десятки, сотни, а иногда и тысячи страниц кода в поисках использования глобальных переменных.

Я предлагаю следующее решение. Надо просто эмулировать работу register_globals в одном отдельно взятом скрипте или в начале объектно-ориентированной стркутуры.

Как это сделать. Да не очень уж и сложно. Давайте рассуждать логически: имена переменных и их значения содержатся в соответствующих глобальных массивах. Как правило, используется массив $_REQUEST, который объединяет в себе все переменных GET, POST и COOKIE. Т.е. все, что передается скрипту из браузера, то, с чем работают скрипты.

Значит, надо извлечь из массива имена переменных, значения переменных и присвоить первому - второе. Извлечь - не проблема, для этого подойдет функция перебора всех ячеек массива foreach(), но как присвоить? Если у нас в $_REQUEST[username] содержится "atos", то как программно создать переменную $username со значением "atos"? Мы же не можем заранее знать, какие имена переменных будут в массиве $_REQUEST.

Вот тут нам поможет изумительная функция eval(), которая редко используется в обычном программировании, но буквально незаменима в некоторых случаях. О самой функции стоит написать отдельно, поэтому скажу только пару слов для тех, кто с ней не знаком.

Функция eval() заставляет PHP рассматривать обыкновенный текст, содержащийся в переменной, как фрагмент PHP-кода. Говоря языком примеров, результаты работы строк

echo 'Hello, User!';

и

eval("echo \'Hello, User!\';")

будет идентичными.

Вот eval() и поможет нам объявить все переменные из массива $_REQUEST. Выглядит это совсем коротко:

foreach($_REQUEST as $k=>$v)
{
 eval("\$$k='$v';");
}

Вставьте этот цикл в самом начале вашего скрипта; он переберет массив глобальных переменных и объявит их не хуже register_globals. А может быть даже и лучше, т.к. глобальных массивов много, а вытаскивать переменные не обязательно из всех. Как правило, данных из массива $_REQUEST - вполне достаточно.

Однако, не стоит забывать и о безопасности вашего кода. Обратите внимание на специфику работы функции eval() - она обработает весь код, переданный ей в качестве параметра. Будьте осторожны, примите меры безопастности, чтобы злоумышленник не подсунул в качестве названия или содержимого переменной кусок своего php-кода или просто неверные данные, способные вызвать ошибку (например, имя переменной, начинающее с цифры или другого неразрешенного символа).

09.02.2003

P.S. После опубликования этой заметки, на форуме не один раз высказывались мысли о том, что вариант с eval() - не самый лучший. Лично я предпочитаю оставлять для себя "путь к отступлению", и eval() как раз привлекателен тем, что позволяет полностью контролировать процесс, добавляя необходимые проверки и ограничения в процедуру или наоборот - расширяя возможности кода. Например, можно добавить логирование регистрации отдельных переменных, чтобы знать - кто, куда, откуда, зачем, или четко запретить к регистрации определенные имена переменных или другие данные.

Впрочем, у каждого метода есть свои плюсы и свои минусы - думайте сами, решайте сами - как поется в известной песне.

Метод "переменные переменных".

foreach($_REQUEST as $k=>$v)
{
 $$k=$v;
}

Как видите, тоже простой метод, основанный на том, что значение переменной $k используется в качестве имени новой переменной. Удобно. Отличается автоматической регистрацией не только переменных, но и массивов. В случае с методом eval() придется проверять каждую переменную на is_array() и разворачивать (регистрировать) ее дополнительно, если такой массив вам нужен.

И самый простой метод - extract().

Весь код нашего примера будет выглядеть так:

extract($_REQUEST);

Это самый "тупой" метод, "разворачивающий" в переменные все, что содержится в массиве $_REQUEST. Нет абсолютно никакой гибкости в этом подходе - повлиять на регистрацию переменных или ввести какой-либо контроль вы не сможете, но выглядит очень лаконично.

И, наконец, не забывайте о том, что register_globals можно активировать не только в конфигурационном файле Apache, но и в файле .htaccess вашего сайта.

Удачи вам, и не пишите дырявых скриптов!

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
52K
29 августа 2009 года
ArNic
0 / / 29.08.2009
Мне нравитсяМне не нравится
1 июня 2010, 13:04:44
Не уверен, что данная статья стимулирует к качеству работы.
Сейчас мы пишем оду register_globals завтра будем поддерживать прямое обращение к htaccess - ну что в самом деле такого?

Ведь просто директивы. И никому они не навредят. А при правильном(!) программировании, сайт не взломают даже зная директивы прописанные в данном файле. И зачем нам такие вещи как DiretoryIndex. Пусть все видят что в папке. Неважно. Мы программируем без дыр!

Мне кажется это бред. Обращение автору:

Вы программировали на C ? Вы там тоже отказывались от фиксированного размера переменной - говоря - максимальный размер это круто. А в MySQL вероятно всегда используете LIKE и не используете индексы (считая что индексы используют только люди, которые не умеют проектировать правильно БД, а значит стараются ускорить работу БД хотя бы этим методом.).

Пожалуйста не баламутьте народ. Многие программисты(!), все внешние переменные обрабатывают в самом начале, не позволяя использовать их в функциях. Хотя бы(!) ради удобства. Поймите что используя внешние переменные в коде вы демонстрируете мувитон. Как следствие Ваш код очень неудобен для модификаций. Поработайте с MVC, прочитайте книги по оптимизации кода и Вы поймёте, что выложили здесь свои заблуждения(!). Я понимаю что прошло уже 6 лет. Но если эта статья попалась мне на глаза. То попадётся и другим людям. Таким образом плодя кривопишущих программистов. Очень надеюсь за 6 лет ваше мнение изменилось и вы подкорректируете эту статью.
2.
Аноним
Мне нравитсяМне не нравится
27 апреля 2006, 02:28:40
Да уж....
Пользуйтесь

foreach($_REQUEST as $k=>$v)
{
eval("\$$k='$v';");
}

и останетесь без сайта
3.
Аноним
Мне нравитсяМне не нравится
1 марта 2006, 09:59:02
Да, eval лучше не использовать, если не хотите чтобы на вашем сайте было много проблем.
В данном случае лучше использовать extract. Хоть это тоже не путь к совершенству, но все же по-спокой
4.
Аноним
Мне нравитсяМне не нравится
17 февраля 2006, 22:05:00
ПО-моему вся эта фигня с глобальными переменными не нужна попросту. ПОЛУЧАЙТЕ ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ВСЕГДА ИЗ СООТВЕТСТВЕННЫХ СУПЕРГЛОБАЛЬНЫХ МАССИВОВ! мой вам совет. и будет все ОК.
5.
Аноним
+0 / -1
Мне нравитсяМне не нравится
19 ноября 2004, 13:38:30
Может я и новичок, но я считаю, что вполне нормальная статья - мне очень помогла.
6.
Аноним
Мне нравитсяМне не нравится
15 ноября 2004, 03:52:51
function GlVar($VirName)

{

if(isset($_GET[$VirName])){

return $_GET[$VirName];

}

elseif(isset($_POST[$VirName])) {

return $_POST[$VirName];

}

elseif(isset($GLOBALS[$VirName])) {

return $GLOBALS[$VirName];

}

else

{

return 0;

}

}

test – переменная переданная, например запросом GET из формы



где-то в коде………………



<?

include_once ‘MainModul.php’;



if(GlVar(“test”)) { //true если переменная test существует и не является ‘’;

echo GlVar(“test”);

}



в противном случае можно написать:



if( isset($_GET[“test”]) and !empty($_GET[“test”]) ) {

echo $_GET[“test”];

}

?>

un-real.ru
7.
Аноним
Мне нравитсяМне не нравится
6 октября 2004, 07:34:48
Я использую вотэто:

for ($i=0; $i<count($_POST); $i++) {list($key,$val)=each($_POST);$$key=$val;};
for ($i=0; $i<count($_GET); $i++) {list($key,$val)=each($_GET);$$key=$val;};
8.
Аноним
+1 / -0
Мне нравитсяМне не нравится
4 октября 2004, 12:03:22
Да, eval лучше не использовать, если не хотите чтобы на вашем сайте было много проблем.
В данном случае лучше использовать extract. Хоть это тоже не путь к совершенству, но все же по-спокойней
9.
Аноним
+3 / -0
Мне нравитсяМне не нравится
12 июня 2004, 20:18:37
"Самая тупая" статья по пхп.
eval("\$$k='$v';");
- это дыра размером с озеро Байкал.

"Удачи вам, и не пишите дырявых скриптов!" в этом контексте смотрится издевкой.
Остальное хоть и мнее вредоносно, но тоже не блещет умом.

лучше не позориться, и снять эту статью вообще.


Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог