Кодирование специальных символов для Web

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

Решение
Используйте методы, предлагаемые используемым API для выполнения кодирования HTML и URL.

Обсуждение
HTML – это язык разметки, он использует определенные символы как маркеры, имеющие специальное значение. Для того чтобы включить в страницу литеральные экземпляры таких символов, необходимо закодировать их, чтобы они не интерпретировались как специальные. Например, < нужно представить как < для того, чтобы броузер не интерпретировал его как начало тега. В зависимости от того, в каком контексте используется символ, возможны два способа кодирования. Один из них используется для общего текста HTML, а второй – для текста, входящего в состав URL в гиперссылке.

Сценарии вывода списка таблиц MySQL представляют собой простые примеры формирования веб-страниц при помощи программ. Но (с одним исключением) у всех этих сценариев есть слабое место – они не занимаются кодированием специальных символов, встречающихся в данных, извлекаемых с сервера MySQL.


(Исключением является версия на JSP; использованный в ней тег автоматически выполняет кодирование, о чем мы еще вскорости поговорим.)

Я сознательно выбрал для отображения такую информацию, которая вряд ли может содержать специальные символы, так что сценарии будут работать корректно и без кодирования. Однако в общем случае не стоит надеяться на то, что результат запроса не будет содержать специальных символов, поэтому будьте готовы их кодировать. В противном случае сценарии могут формировать некорректно отображаемые HTML-страницы.

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

Общие принципы кодирования
Один из видов кодирования применяется для символов, используемых при написании конструкций HTML, а второй – для текста, включаемого в URL. Важно понимать это отличие и применять соответствующий способ.


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

Кодирование специальных символов в HTML
Разметка HTML использует символы < и > для начала и завершения тега, & – для начала наименований сущностей (таких как   для обозначения неразрывного пробела) и " для заключения в кавычки значений атрибутов в тегах (например,

). Поэтому для буквального отображения таких символов необходимо закодировать их в сущности HTML, с тем чтобы броузеры и другие клиенты поняли ваше намерение. Для этого преобразуем<, >, & и " в соответствующие сущности HTML < (меньше, чем), > (больше, чем), & (амперсанд) и " (кавычка).

Предположим, что вы хотите буквально вывести в веб-странице следующую строку:

Paragraphs begin and end with

&

tags.

Если отправить этот текст броузеру в том виде, в котором он записан сейчас, броузер не сможет интерпретировать его корректно. (Теги

и

будут восприняты как указатели абзаца, а & – вероятно, как начало сущности HTML.)

Чтобы вывести строку именно так, как хотелось бы, необходимо преобразовать специальные символы в сущности <, > и &:

Paragraphs begin and end with <p> & </p> tags.

Этот же принцип кодирования текста применяется и внутри тегов.


Например, значения атрибутов тегов HTML часто заключаются в двойные кавычки, поэтому необходимо выполнить HTML-кодирование значений атрибутов. Предположим, что вы хотите включить в форму поле ввода текста, при этом указав его начальное значение – Rich "Goose" Gossage. Нельзя просто написать это значение в теге:



Получается, что атрибут value, заключенный в двойные кавычки, содержит внутренние двойные кавычки, в результате чего тег оказывается некорректно сформированным. Необходимо закодировать двойные кавычки:



Когда броузер получит такой текст, он преобразует " обратно в символы " и сможет правильно интерпретировать значение атрибута value.

Кодирование специальных символов в URL
URL гиперссылок, встречающиеся в HTML-страницах, имеют собственный синтаксис и собственный способ кодирования, который применяется к атрибутам нескольких тегов:

(a href="URL")

Многие символы имеют специальное значение в URL (:, /, ?, =, & и ;).


Следующий URL содержит некоторые из них:

http://apache.snake.net/myscript.php?id=428&name=Gandalf

Символы : и / разбивают URL на составляющие, символ ? указывает на наличие параметров, а символы & разделяют параметры, каждый из которых представлен парой имя=значение. (Символ ; не входит в данный URL, но часто используется вместо & для разделения параметров.) Если вы хотите включить какие-то из этих символов в URL как литералы, необходимо закодировать их, чтобы броузер не интерпретировал их как специальные. Специальной обработки требуют и другие символы, такие как пробелы. Пробелы внутри URL не разрешены, так что, если вы хотите сослаться на страницу my home page.html с сайта apache.snake.net, то URL в гиперссылке нельзя записывать так:

(a href="http://apache.snake.net/my home page.html")My Home Page(/a)

URL-кодирование специальных и зарезервированных символов выполняется путем преобразования каждого такого символа в его ASCII-код (две шестнадцатеричные цифры), перед которым нужно поставить знак %. Например, ASCII-код символа пробела равен 32 в десятичной системе счисления или 20 в шестнадцатеричной, так что предыдущую гиперссылку следует записать так:

(a href="http://apache.snake.net/my%20home%20page.html")My Home Page(/a)

Иногда вы можете встретить пробелы, закодированные в URL как +.


Это тоже разрешено.

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

Тогда термин будет как параметром в URL, так и текстом HTML, заключенным в теги (a) и (/a). Если поиск совпадений ведется для термина «cats & dogs», то незакодированная ссылка будет выглядеть так:

(a href="/cgi-bin/myscript?term=cats & dogs")cats & dogs(/a)

Но такая запись не корректна, поскольку & является специальным символом как для HTML, так и для URL, пробелы тоже относятся к специальным символам URL. Ссылку следует изменить так:

(a href="/cgi-bin/myscript?term=cats%20%26%20dogs")cats & dogs (/a)

В данном случае & закодирован в HTML как & для заголовка ссылки, а в URL он уже закодирован как %26, при этом пробелы в URL тоже закодированы как %20.

Конечно, не слишком приятно кодировать весь текст перед записью в веб-страницу, и иногда у вас имеется достаточно информации о значении, чтобы не кодировать его (см. примечание «Всегда ли необходимо кодировать вывод веб-страницы?»). Однако надежнее все же постоянно использовать кодирование. К счастью, большинство API предоставляют функции, которые сделают эту работу за вас. Поэтому вам необязательно знать все специальные символы для заданного контекста. Нужно лишь знать, какой вид кодирования надо использовать, и вызывать соответствующую функцию для получения желаемого результата.Кодирование специальных символов при помощи веб-API

Приведенные далее примеры показывают, как извлечь значения из MySQL и выполнить их HTML- и URL-кодирование для формирования гиперссылки. Все примеры читают таблицу phrase, где хранятся короткие фразы, используют ее содержимое для построения гиперссылок, указывающих на (гипотетический) сценарий, который осуществляет поиск вхождений этих фраз в какую-то другую таблицу. Таблица выглядит так:

mysql> SELECT phrase_val FROM phrase ORDER BY phrase_val;

+--------------------------+
| phrase_val |
+--------------------------+
| are we "there" yet? |
| cats & dogs |
| rhinoceros |
| the whole > sum of parts |
+--------------------------+

Наша цель – сформировать список гиперссылок, в котором каждая фраза будет использоваться как в заголовке гиперссылки (то есть потребуется HTML-кодирование), так и в качестве параметра сценария (потребуется URL-кодирование). В результате ссылки будут такими:

(a href="/cgi-bin/mysearch.pl?phrase=are%20we%20%22there%22%20yet%3F")
are we "there" yet?(/a)
(a href="/cgi-bin/mysearch.pl?phrase=cats%20%26%20dogs")
cats & dogs(/a)
(a href="/cgi-bin/mysearch.pl?phrase=rhinoceros">rhinoceros(/a)
(a href="/cgi-bin/mysearch.pl?phrase=the%20whole%20%3E%20sum%20of%20parts"> the whole > sum of parts(/a)

Ссылки, формируемые некоторыми API, будут немного отличаться от представленных, так как они кодируют пробелы как +, а не %20.

Perl
Модуль Perl CGI.pm предлагает два метода, escapeHTML() и escape(), которые занимаются HTML- и URL-кодированием. Есть три способа использования этих методов для кодирования строки $str:

• Вызвать escapeHTML() и escape() как методы класса CGI, используя префикс CGI:::

use CGI;
printf "%s\n%s\n", CGI::escape ($str), CGI::escapeHTML ($str);

• Создать объект CGI и вызвать escapeHTML() и escape() как методы объекта:

use CGI;
my $cgi = new CGI;
printf "%s\n%s\n", $cgi->escape ($str), $cgi->escapeHTML ($str);

• Явно импортировать имена в пространство имен вашего сценария. Тогда не будет необходимости ни в объекте CGI, ни в префиксе CGI::, и можно будет вызывать методы как автономные функции. Следующий пример импортирует имена двух методов как дополнение к множеству стандартных имен:

use CGI qw(:standard escape escapeHTML);
printf "%s\n%s\n", escape ($str), escapeHTML ($str);

Я предпочитаю последний способ, так как он согласуется с функциональным интерфейсом CGI.pm, который мы используем для обращения к другим импортированным методам. Не забудьте включить имена методов кодирования в предложение use CGI любого сценария Perl, которому они требуются, иначе при запуске сценария возникнет ошибка типа «undefined subroutine».

Следующий код считывает содержимое таблицы phrase и формирует из него гиперссылки при помощи escapeHTML() и escape():

my $query = "SELECT phrase_val FROM phrase ORDER BY phrase_val";
my $sth = $dbh->prepare ($query);
$sth->execute ();
while (my ($phrase) = $sth->fetchrow_array ())
{
# URL-кодирование значения phrase для использования в URL
# HTML-кодирование значения phrase для использования в тексте ссылки
my $url = "/cgi-bin/mysearch.pl?phrase=" . escape ($phrase);
my $label = escapeHTML ($phrase);
print a ({-href => $url}, $label) . br () . "\n";
}PHP

В PHP HTML- и URL-кодированием занимаются функции htmlspecialchars() и urlencode(), которые используются так:

$query = "SELECT phrase_val FROM phrase ORDER BY phrase_val";
$result_id = mysql_query ($query, $conn_id);
if ($result_id)
{
while (list ($phrase) = mysql_fetch_row ($result_id))
{
# URL-кодирование значения phrase для использования в URL
# HTML-кодирование значения phrase для использования в тексте ссылки
$url = "/mcb/mysearch.php?phrase=" . urlencode ($phrase);
$label = htmlspecialchars ($phrase);
printf ("%s
\n", $url, $label);
}
mysql_free_result ($result_id);
}

Python
В Python модули cgi и urllib содержат соответствующие методы кодирования: cgi.escape() выполняет HTML-кодирование, а urllib.quote() – URL-кодирование:

import cgi
import urllib
query = "SELECT phrase_val FROM phrase ORDER BY phrase_val"
cursor = conn.cursor ()
cursor.execute (query)
for (phrase,) in cursor.fetchall ():
# URL-кодирование значения phrase для использования в URL
# HTML-кодирование значения phrase для использования в тексте ссылки
url = "/cgi-bin/mysearch.py?phrase=" + urllib.quote (phrase)
label = cgi.escape (phrase, 1)
print "(a href=\"%s\")%s(/a)
" % (url, label)
cursor.close ()

Первым аргументом cgi.escape() является строка, которую нужно закодировать для HTML. По умолчанию эта функция преобразует символы <, > и & в соответствующие им сущности HTML. Чтобы указать cgi.escape() на необходимость дополнительно преобразовывать двойные кавычки в ", передайте второй аргумент, равный 1, как показано в примере. Это особенно важно, если вы кодируете значения, которые будут помещаться в атрибуты тегов, заключенные в двойные кавычки.

Java
Тег JSTL автоматически выполняет HTML-кодирование страниц JSP. (Строго говоря, он выполняет XML-кодирование, но здесь речь идет о наборе символов <, >, &, " и ', включающем все необходимые для HTML-кодирова-ния символы.) Используя для отображения текста на веб-странице, не стоит даже задумываться о преобразовании специальных символов в объекты HTML. Если по какой-то причине вы хотите отменить кодирование, вызовите так:



Для URL-кодирования параметров, включаемых в URL, используйте тег . Задайте строку URL в атрибуте тега value, а все имена и значения параметров – в тегах в теле тега . Значение параметра можно указывать в атрибуте value тега или в его теле:


sky blue


Значения параметров id и color URL-кодируются и добавляются в конец URL. Результат помещается в объект urlStr, который можно отобразить так:



Тег не кодирует такие специальные символы, как пробелы, в строке, записанной в атрибуте value. Их следует кодировать самостоятельно, так что, вероятно, разумнее просто избегать создания страниц с пробелами в названиях, чтобы не пришлось впоследствии ссылаться на такие страницы.

Записи таблицы phrase при помощи тегов и можно вывести так:

SELECT phrase_val FROM phrase ORDER BY phrase_val

# URL-кодирование значения phrase для использования в URL
# HTML-кодирование значения phrase для использования в тексте ссылки


(a href="")
(/a)




Оцените статью: (0 голосов)
0 5 0

Статьи из раздела MySQL на эту тему:
Запуск веб-сценариев на сервере Apache
Запуск веб-сценариев на сервере Tomcat
Основы формирования веб-страницы

Вернуться в раздел: MySQL / 16. Знакомство с MySQL для Web