Начало: «
Windows 10: связываем IIS и PHP с СУБД MySQL».
В предыдущем посте я описал запуск скрипта на языке PHP на локальном веб-сервере IIS из браузера по адресу localhost/testdb.php. Этот скрипт создает соединение с сервером СУБД «MySQL» для возможного получения данных из указанной базы данных:
// mysqli
$mysqli = new mysqli("localhost", "root", "password", "testdb");
$result = $mysqli->query("SELECT 'Привет, дорогой пользователь MySQL!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);
У меня при отключенном сервере «mysqld.exe» СУБД «MySQL» этот скрипт возвращает для отображения в браузер следующее сообщение об ошибке:
PHP Fatal error: Uncaught mysqli_sql_exception: Подключение не уÑтановлено, Ñ‚.к. конечный компьютер отверг Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подключение in C:\inetpub\wwwroot\testdb.php:3
Stack trace:
#0 C:\inetpub\wwwroot\testdb.php(3): mysqli->__construct('localhost', 'root', 'password', 'testdb')
#1 {main}
thrown in C:\inetpub\wwwroot\testdb.php on line 3
Видно, что сообщение об ошибке браузер отобразил в неправильной кодировке, из-за чего часть сообщения отобразилась кракозябрами (по-английски «
mojibake»). В данном случае тело HTTP-ответа пришло в кодировке UTF-8, а браузер отобразил его в кодировке
Windows-1252.
Я использую браузер «Microsoft Edge» (на движке «Chromium»), но дело тут не совсем в браузере (хотя и в нем тоже). Тут дело в том, что в данном случае в HTTP-ответе отсутствует HTTP-заголовок «Content-Type», на который обычно ориентируются браузеры при определении кодировки полученного текста. Например, для HTML-страниц этот HTTP-заголовок должен содержать (в большинстве случаев) значение text/html; charset=UTF-8, тогда браузер отобразит полученную HTML-страницу в кодировке UTF-8. (Еще в коде HTML-страниц рекомендуют использовать HTML-элемент , а самое правильное, чтобы и обеспечивался указанный HTTP-заголовок в HTTP-ответе со стороны веб-сервера, и указанный HTML-элемент на передаваемой HTML-странице, то есть оба способа сразу.)
В принципе, сегодня от браузера стоит ожидать, чтобы он по умолчанию (если он не получил ни указанного HTTP-заголовка в HTTP-ответе, ни HTML-элемента на HTML-странице) отображал тексты в кодировке UTF-8, самой распространенной в вебе (
97,9 % веб-сайтов на сегодня используют кодировку UTF-8). Но в операционных системах «Windows», к сожалению, до сих пор во главе угла находятся устаревшие кодировки Windows-1251, Windows-1252 и так далее. Так что в отображении вышеприведенных кракозябр есть и вина браузера тоже.
Я несколько дней думал, можно ли как-то добавить в описанном случае в HTTP-ответ нужный HTTP-заголовок со стороны веб-сервера IIS. Перебрал множество возможных способов, но так ничего и не придумал. (Даже
написал вопрос на сайте «Stack Overflow», может, кто-нибудь там сможет что-то мне подсказать по этому поводу.)
Можно подойти к этой проблеме немного с другой стороны. В программировании считается неправильным оставлять неотловленные ошибки в программе. В данном случае у нас, как раз, неотловленная (по-английски «uncaught») неустранимая (
fatal) ошибка. Такие ошибки обычно отлавливают с помощью известной во многих языках программирования конструкции try..catch, которая
есть и в языке PHP. Меняем код:
// mysqli
try {
$mysqli = new mysqli("localhost", "root", "password", "testdb");
$result = $mysqli->query("SELECT 'Привет, дорогой пользователь MySQL!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);
} catch (Exception $e) {
echo "
", $e, "";
}
Теперь ошибка отловлена, ход выполнения программы находится у нас под контролем. При этом вывод в браузер ошибки происходит не аварийным, а прописанным в скрипте способом, поэтому используется обычный для языка PHP вывод, при котором в HTTP-ответ вставляется HTTP-заголовок, настраиваемый в файле настроек «php.ini»:
...
default_mimetype = "text/html"
...
default_charset = "UTF-8"
...
То есть нужный HTTP-заголовок Content-Type: text/html; charset=UTF-8 будет сформирован.
Результат в браузере:
mysqli_sql_exception: Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение in C:\inetpub\wwwroot\testdb.php:4
Stack trace:
#0 C:\inetpub\wwwroot\testdb.php(4): mysqli->__construct('localhost', 'root', 'password', 'testdb')
#1 {main}
Видно, что теперь русские буквы выведены корректно. Браузер отобразил текст в нужной кодировке UTF-8.