I use a stack of technologies Windows 10, web server IIS 10, RDBMS 'MySQL' 8.0, PHP 8.1.10.
My question was considered a duplicate of the following question: 'Trouble with UTF-8 characters; what I see is not what I stored'. Here are my objections. I don't have a problem with UTF-8 encoding: 'MySQL' returns the response in the correct encoding, PHP + web-server IIS transmits this data correctly to the browser.
My problem is that the web server IIS does not transmit the HTTP 'Content-Type' header in the HTTP response (in case of a PHP fatal error), which is why the browser displays the correct data in the wrong encoding. Thus my question is not a duplicate.
I took the script from the PHP manual, changed it to fit my parameters:
<?php
// mysqli
$mysqli = new mysqli("localhost", "root", "password", "testdb");
$result = $mysqli->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);
and put it in a file C:\inetpub\wwwroot\testdb.php
. In the browser ('Microsoft Edge' on 'Chromium' engine) at the address localhost/testdb.php
I received the desired response:
Hello, dear MySQL user!
In the browser developer tools, I made sure that there is a header Content-Type: text/html; charset=UTF-8
in the HTTP response. In the php.ini
file I have the settings:
default_mimetype = "text/html"
default_charset = "UTF-8"
After that I initiated 'PHP Fatal error' by stopping the RDBMS server mysqld.exe
. In the browser at the address localhost/testdb.php
I received the following:
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
In the browser developer tools, I saw that there is no header Content-Type: text/html; charset=UTF-8
in the HTTP response. Because of this, the browser displayed the body of the HTTP response in encoding 'Windows-1252' instead of 'UTF-8'. Because of this, part of the error message was displayed with mojibake.
My question is: how to add a header Content-Type: text/html; charset=UTF-8
to an HTTP response with 'PHP fatal error' in IIS? (So that the error message is displayed in the browser in the correct encoding 'UTF-8'.)
I know that it is possible to use the construction try-catch
:
<?php
// mysqli
try {
$mysqli = new mysqli("localhost", "root", "password", "testdb");
$result = $mysqli->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);
} catch (Exception $e) {
echo "<pre>", $e, "</pre>";
}
and then the browser will receive an HTTP response with the header 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}
But I'm wondering if it's possible to add a header Content-Type: text/html; charset=UTF-8
specifically to an HTTP response with 'PHP fatal error'.
You can also change the encoding in the php.ini
file using the setting:
default_charset = "Windows-1251"
In this case, PHP will return an error message to the browser in the encoding 'Windows-1251' and the browser will display the message correctly in this encoding. But I want to work with text in encoding 'UTF-8' since encoding 'Windows-1251' is legacy.
I also tried to configure C:\inetpub\wwwroot\web.config
:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<remove fileExtension=".js" />
<remove fileExtension=".css" />
<remove fileExtension=".html" />
<remove fileExtension=".htm" />
<mimeMap fileExtension=".html" mimeType="text/html; charset=utf-8" />
<mimeMap fileExtension=".css" mimeType="text/css; charset=utf-8" />
<mimeMap fileExtension=".js" mimeType="application/javascript; charset=utf-8" />
<mimeMap fileExtension=".htm" mimeType="text/html; charset=utf-8" />
<mimeMap fileExtension=".php" mimeType="text/html; charset=utf-8" />
</staticContent>
<caching enabled="true" enableKernelCache="true" />
</system.webServer>
</configuration>
The header Content-Type: text/html; charset=UTF-8
did not appear in the HTTP response with 'PHP fatal error'.
I used the error handling method suggested by @YourCommonSense:
<?php
include 'error_handling.php';
// mysqli
$mysqli = new mysqli("localhost", "root", "password", "testdb");
$result = $mysqli->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);
File error_handling.php
:
<?php
function exception_handler(Throwable $exception) {
echo "<pre>", $exception, "</pre>";
}
set_exception_handler('exception_handler');
The result in the browser (the same as with the method try-catch
):
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}
Yes, it improves the beauty of the code and makes error handling easier. This is a workaround to solve my problem, I will use it. But this is still not the answer to my original question. And my question is not a duplicate of the question How do I catch a PHP fatal (E_ERROR
) error?.