Боремся с Magic Quotes

Владимир | | Hosting, htaccess, PHP, Web разработка.

php_magic_quotes

На днях я столкнулся с довольно неприятной ситуацией. Скрипт, который прекрасно работал на локальном сервере начал выдавать ошибки на сервере хостера.

Проблема оказалась мелкой и я все быстро исправил, но эта ситуация напомнила мне о законе подлости. Как только забываешь о тестировании – скрипты сразу перестают работать. Не зависимо от того, насколько они простые. 😉

В данном случае дело было во включенных Magic Quotes (волшебных кавычках, хорошее название, появляются как по волшебству там, где не надо 🙂 ).

Вообще-то, использование Magic Quotes не рекомендуемая практика.

В соответствующем разделе PHP manual ясно об этом сказано.

Warning

This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged.

Предупреждение

Эта возможность считается устаревшей начиная с PHP 5.3.0 и будет удалена начиная с PHP 6.0.0. Рассчитывать на эту возможность крайне не рекомендуется.

Кратко поясню смысл этой функции. Она перехватывает данные, которые получает скрипт (массивы $_POST, $_GET и т.д.) и экранирует в них специальные символы.

Была разработана для защиты от хакерских атак вроде SQL Injection.

Но на практике от нее больше проблем, чем пользы.

Во-первых, 100% защиты она не обеспечивает. Т.е. вам все равно нужно самостоятельно проверять полученные данные (их тип, диапазон допустимых значений и т.п.). К тому же экранирование символов выполняется автоматически практически всеми библиотеками для работы с БД.

Во-вторых, часто нужны не экранированные данные.

Например, в моем случае ситуация была такой.

1) Клиент (браузер) передавал строку в формате json.
2) PHP при включенной Magic Quotes экранировал спец. символы.
3) функция json_decode возвращала NULL. 🙂

Почему хостеры включают Magic Quotes – вопрос отдельный. Может быть, хотят немного подстраховаться от начинающих разработчиков 😉 Или есть какие-то другие причины. Но в любом случае, вы можете легко ее отключить.

Посмотреть текущие настройки можно с помощью phpinfo(). (если Magic Quotes включена, в разделе Configure Command будет строка --enable-magic-quotes).

Для отключения создаем в папке со скриптами файл .htaccess с одной строчкой.

php_flag magic_quotes_gpc Off

Отключает Magic quotes для входящих данных из массивов GET/POST/Cookie.

Или добавляем эту же строчку в существующий .htaccess.

Примечание. Естественно, Magic Quotes можно отключить и в php.ini, но на shared хостинге у вас к нему доступа нет.

Подробнее об отключении Magic quotes можно почитать в PHP Manual.

Кстати, в нем есть пример функции, которая выполняет обратную операцию (удаляет слеши) — это на случай если хостер отключил поддержку .htaccess. Но, честно говоря, в такой ситуации я бы подумал о смене хостера.

До встречи!

  • Спасибо, такая ностальгия началась 🙂 Тоже сталкивался в свое время с Magic Quotes. А советы и рекомендации — ни добавить, ни убавить — все просто отлично приготовлено и подано, имхо.

    • Спасибо. Решения длиной в одну строку практически всегда отличными получаются 🙂

  • Спасибо, такая ностальгия началась 🙂 Тоже сталкивался в свое время с Magic Quotes. А советы и рекомендации — ни добавить, ни убавить — все просто отлично приготовлено и подано, имхо.

    • Спасибо. Решения длиной в одну строку практически всегда отличными получаются 🙂

  • Все ок. Только перевод некорректный, смысл получается неверный.

    This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0.

    Эта возможность считается устаревшей начиная с PHP 5.3.0 и будет удалена начиная с PHP 6.0.0.

    Так будет корректнее. DEPRECATED — это не запрещенное, это вполне дееспособное, только устаревшее, что предупреждает разработчика о том, что его программа не будет работать с новыми версиями языка, где устаревшие элементы уже будут убраны.

    К слову сказать DEPRECATED методы порой еще по 5 лет остаются рабочими, прежде, чем их выкинут. Взять Java — с 2004-го года там многие классы и методы обозначены как DEPRECATED, но работают до сих пор, хотя уже 2010 — 6 лет прошло и в последнем обновлении они все до сих пор благополучно работают. Поэтому не надо все же читать УСТАРЕВШИЙ как ЗАПРЕЩЕННЫЙ. Просто лучше этим не пользоваться, если не хочешь потом конкретно замучиться.

    • Большое спасибо!
      Я исправил на ваш вариант. Он действительно лучше!

      Действительно «запрещенный» — «forbidden».

      Вообще проблема с переводом сильно надоела. То, что по английски можно сказать одним словом, по-русски нужно объяснять с помощью абзаца текста.
      Еще раз спасибо!

  • Все ок. Только перевод некорректный, смысл получается неверный.

    This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0.

    Эта возможность считается устаревшей начиная с PHP 5.3.0 и будет удалена начиная с PHP 6.0.0.

    Так будет корректнее. DEPRECATED — это не запрещенное, это вполне дееспособное, только устаревшее, что предупреждает разработчика о том, что его программа не будет работать с новыми версиями языка, где устаревшие элементы уже будут убраны.

    К слову сказать DEPRECATED методы порой еще по 5 лет остаются рабочими, прежде, чем их выкинут. Взять Java — с 2004-го года там многие классы и методы обозначены как DEPRECATED, но работают до сих пор, хотя уже 2010 — 6 лет прошло и в последнем обновлении они все до сих пор благополучно работают. Поэтому не надо все же читать УСТАРЕВШИЙ как ЗАПРЕЩЕННЫЙ. Просто лучше этим не пользоваться, если не хочешь потом конкретно замучиться.

    • Большое спасибо!
      Я исправил на ваш вариант. Он действительно лучше!

      Действительно «запрещенный» — «forbidden».

      Вообще проблема с переводом сильно надоела. То, что по английски можно сказать одним словом, по-русски нужно объяснять с помощью абзаца текста.
      Еще раз спасибо!

  • Я конечно могу ошибаться, но, по моему, php_flag в .htaccess работать будет только тогда когда php работает как модуль апача, а когда в cgi режиме — хрен.

    • Абсолютно верно, php_flag в .htaccess будет работать только в том случае, если PHP работает как модуль Apache.

    • DeadLy

      если php как cgi, то хостеры предоставляют редакировать php.ini во всяком случае у меня так

  • Я конечно могу ошибаться, но, по моему, php_flag в .htaccess работать будет только тогда когда php работает как модуль апача, а когда в cgi режиме — хрен.

    • Абсолютно верно, php_flag в .htaccess будет работать только в том случае, если PHP работает как модуль Apache.

    • DeadLy

      если php как cgi, то хостеры предоставляют редакировать php.ini во всяком случае у меня так

  • Есть еще такая «хорошая» вещь, как register_globals. Ее тоже лучше отключать сразу.

    • Сергей

      Ну это уже и хостеры поняли. Обычно уже отключено.

  • Есть еще такая «хорошая» вещь, как register_globals. Ее тоже лучше отключать сразу.

    • Сергей

      Ну это уже и хостеры поняли. Обычно уже отключено.

  • Евгений

    Всё же классическая и более широкая
    статья по экранированию тут.

  • Евгений

    Всё же классическая и более широкая
    статья по экранированию тут.

  • Big_Shark

    Еще вариант
    set_magic_quotes_runtime(0); // Kill magic quotes
    и вариант проверки
    if (get_magic_quotes_gpc())
    {
    $str = stripslashes($str);
    }
    Взято из исходников CI

    • Согласен, вариант. Кстати на php.net тоже есть пример соответствующей функции, но лишний php код — не очень красивое решение.

      • Big_Shark

        Не все серверы поддерживаю изменения директив.
        Если пишется скрипт который будет устанавливаться на разные сервера то лучше предусмотреть все возможности отключения данной дерективы или борьбы с ней.

        • Я согласен. Но при любой возможности стараюсь от лишнего кода избавляться 😉

  • Big_Shark

    Еще вариант
    set_magic_quotes_runtime(0); // Kill magic quotes
    и вариант проверки
    if (get_magic_quotes_gpc())
    {
    $str = stripslashes($str);
    }
    Взято из исходников CI

    • Согласен, вариант. Кстати на php.net тоже есть пример соответствующей функции, но лишний php код — не очень красивое решение.

      • Big_Shark

        Не все серверы поддерживаю изменения директив.
        Если пишется скрипт который будет устанавливаться на разные сервера то лучше предусмотреть все возможности отключения данной дерективы или борьбы с ней.

        • Я согласен. Но при любой возможности стараюсь от лишнего кода избавляться 😉

  • Roman

    спасибо за решение, два часа бодался с JSON. Не разбиралась строка + еще косяки были с кодировкой, но там они попроще решились.

  • Roman

    спасибо за решение, два часа бодался с JSON. Не разбиралась строка + еще косяки были с кодировкой, но там они попроще решились.

  • Как для меня, то все полностью сдесь устраивает.

  • Как для меня, то все полностью сдесь устраивает.

  • semenovyy

    Значит не у меня одного были такие заморочки. Да еще иногда хостеры не дают возможности изменения директив. у меня в скриптах проверки.

  • seventh

    Спасибо за подсказку

  • Guazzo.ru

    После переноса сайтов на VPS редактор страниц перестал сохранять странички, содержащие JS.
    Прочитал Вашу статью. Правда с выключенными 
    Magic Quotes не сработало. Но вот прописал php_flag magic_quotes_gpc on и все стало ГУД!) Спасибо!