0

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?.

Ilya Chalov
  • 149
  • 2
  • 9
  • Do ```header("Content-type: text/html; charset=utf-8");``` in your PHP code before the first actual content output? https://www.php.net/manual/en/function.header.php – Hartmut Holzgraefe Oct 07 '22 at 19:59
  • @Hartmut-Holzgraefe I didn't write about it, but I tried it. This does not work for me in this case. How can this work in case of a [fatal exception error](https://en.wikipedia.org/wiki/Fatal_exception_error)? – Ilya Chalov Oct 07 '22 at 21:00
  • Does this help? https://maideveloper.com/blog/how-to-set-default-encoding-in-iis – Jacob Mulquin Oct 08 '22 at 05:26
  • Подключение ... is Mojibake for Подключение... -- You were expecting Cyrillic? See Mojibake in https://stackoverflow.com/questions/38363566/trouble-with-utf8-characters-what-i-see-is-not-what-i-stored – Rick James Oct 08 '22 at 05:49
  • @IlyaChalov you don't really need it. Fatal errors are **not intended to be shown on-screen** in the first place. In case of a fatal error a generic "Temporary maintenance" banner must be shown without any particular details. – Your Common Sense Oct 08 '22 at 06:12
  • @RickJames the problem here is different. The encoding is all right. The header is wrong. I made a mistake editing the title, and reverted it back. – Your Common Sense Oct 08 '22 at 07:34
  • @JacobMulquin It doesn't work for me. Isn't `system.web` a legacy for IIS 6? I didn't find such an element in the [Configuration Reference](https://learn.microsoft.com/en-us/iis/configuration/). – Ilya Chalov Oct 08 '22 at 14:17
  • @RickJames You haven't read my question to the end. Below is a sample of the correct output of this message when I used the `try-catch` construct. My question is not a duplicate, I ask you to remove the remark about the duplicate. – Ilya Chalov Oct 08 '22 at 14:22
  • @YourCommonSense I have given an error message from the PHP interpreter in my question. This message was displayed by my browser. It says, quote: `PHP Fatal error: Uncaught mysqli_sql_exception:`. The error is not caught by the program, so it is handled by the interpreter (so it seems to me). Therefore, it is called 'fatal'. – Ilya Chalov Oct 08 '22 at 14:34
  • @YourCommonSense I'm not going to show this message to end users, I need to see this message in the correct encoding for debugging. – Ilya Chalov Oct 08 '22 at 14:49
  • 1
    Speaking of this particular kind of fatal errors, you simply have to have an **exception handler.** [Like this](https://phpdelusions.net/articles/error_reporting#function). So it won't become a fatal error anymore. While speaking of proper fatal errors, you will need a handler for them as well. It can be found in the same article below – Your Common Sense Oct 08 '22 at 17:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/248660/discussion-between-ilya-chalov-and-your-common-sense). – Ilya Chalov Oct 08 '22 at 17:48

0 Answers0