mbstring.http_input is ignored in subsequent requests after changing default_charset
Mantenedores costumam responder em até 1 dia
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 1-2 dias
- Facilidade para iniciantes
- 48/100
- Tipo de issue
- Bug
- Clareza
- Claramente especificada
- Status de atividade
- Ativa
- Domínio
- backend, internationalization
Direção de pesquisa
Start by reading PHP_RSHUTDOWN_FUNCTION(mbstring) and mbstring_internal_encoding_changed_hook(), introduced in the linked commit, then trace how INI settings are restored between requests. Reproduce the issue with the supplied php.ini and two sequential requests handled by one server process. Done means the second request retains the configured HTTP input candidates and converts the UTF-8 POST data correctly.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Description
With mbstring.http_input=auto explicitly configured, calling ini_set('default_charset', 'UTF-8') in one request causes the effective HTTP input encoding candidates to change for subsequent requests handled by the same process.
The INI value remains auto, but mb_http_input('I') returns only EUC-JP, and UTF-8 POST data is corrupted.
Reproduction
PHP must have mbstring enabled.
Save the following configuration as php.ini:
default_charset = EUC-JP
input_encoding = ""
mbstring.language = Japanese
mbstring.encoding_translation = On
mbstring.http_input = auto
mbstring.internal_encoding = EUC-JP
display_errors = stderr
error_reporting = E_ALL & ~E_DEPRECATED
Save the following code as index.php:
<?php
header('Content-Type: application/json; charset=UTF-8');
echo json_encode([
'pid' => getmypid(),
'default_charset' => ini_get('default_charset'),
'http_input_ini' => ini_get('mbstring.http_input'),
'candidates' => mb_http_input('I'),
'detected_post' => mb_http_input('P'),
'post_hex' => bin2hex($_POST['text'] ?? ''),
], JSON_UNESCAPED_SLASHES), "\n";
if (isset($_GET['change'])) {
ini_set('default_charset', 'UTF-8');
}
Start a fresh built-in server from the directory containing these files:
unset PHP_CLI_SERVER_WORKERS
php -c ./php.ini -S 127.0.0.1:18983 -t .
In another terminal, send the following two requests in order. Both send the same UTF-8 string, 日本語テスト. The first request changes default_charset after printing the initial state.
body='text=%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%83%86%E3%82%B9%E3%83%88'
curl --data "$body" 'http://127.0.0.1:18983/index.php?change=1'
curl --data "$body" 'http://127.0.0.1:18983/index.php'
Actual output
{"pid":7,"default_charset":"EUC-JP","http_input_ini":"auto","candidates":["ASCII","JIS","UTF-8","EUC-JP","SJIS"],"detected_post":"UTF-8","post_hex":"c6fccbdcb8eca5c6a5b9a5c8"}
{"pid":7,"default_charset":"EUC-JP","http_input_ini":"auto","candidates":["EUC-JP"],"detected_post":"EUC-JP","post_hex":"3fa5e63f3f3f3f3f3fb9e33f3f"}
PID values may differ, but both requests must be handled by the same PID.
The second request has the original default_charset and still reports mbstring.http_input=auto. However, its effective candidate list contains only EUC-JP. The converted POST value contains replacement characters (3f, or ?).
Expected output
The second request should retain the explicitly configured input candidates and convert the POST value correctly, just as the first request does:
{"pid":7,"default_charset":"EUC-JP","http_input_ini":"auto","candidates":["ASCII","JIS","UTF-8","EUC-JP","SJIS"],"detected_post":"UTF-8","post_hex":"c6fccbdcb8eca5c6a5b9a5c8"}
Additional verification
The same behavior was reproduced in Docker with:
- PHP 8.2.35, 8.3.36, 8.4.27, and 8.5.12, using both the built-in server and FPM with a single worker.
- PHP 7.4.0, using the built-in server.
It was not reproduced with PHP 7.3.33 using the built-in server.
Adding input_encoding=auto to php.ini prevents the corruption in these tests. Explicitly listing the five encodings in mbstring.http_input does not prevent it.
Suspected cause
The relevant hook and flags were introduced in commit:
https://github.com/php/php-src/commit/f73f190c3f97479f735b97c22a8e4885344edca1
PHP_RSHUTDOWN_FUNCTION(mbstring) clears http_input_set before modified INI settings are restored. Restoring default_charset then invokes mbstring_internal_encoding_changed_hook(), which rebuilds the persistent HTTP input list from php_get_input_encoding().
With an empty input_encoding, this returns EUC-JP.
The next request does not restore the explicitly configured mbstring.http_input candidate list.
This reproducer requires sequential HTTP requests handled by the same process, rather than a single CLI execution.
PHP Version
PHP Version
PHP 8.5.12 (cli) (built: Oct 21 2026 15:48:53) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.12, Copyright (c) Zend Technologies
with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies
Operating System
Debian GNU/Linux 13 (trixie), Docker image php:8.5.12-cli, x86_64d
- Linguagem predominante
- C
- Estrelas
- 40.7k
- Forks
- 8.3k
- Merge médio
- 2d 17h
- PRs com merge (30d)
- 159
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de php/php-src
-
`openssl_pkcs7_read()` / `openssl_cms_read()`: CRLs overwrite certificates in the output arrayAbertaBug Status: Needs Triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
Mantenedores costumam responder em até 1 dia
-
ext/mbstring: mb_regex_substitute() reads past the replacement string's end on a truncated trailing multibyte lead byteTalvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 74/100
php/php-src#24769 · 3 comentários ·
Mantenedores costumam responder em até 1 dia
-
zend_set_local_var() overwrites existing compiled variable (CV) zval without calling zval_ptr_dtor()Talvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. AbertaBug Status: Needs Triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 1 dia
-
master: part of the mbstring bailout fix got lost in a mergeTalvez já em andamento @lazerg assumiu há 6 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 1 dia
-
Bug Status: Needs Triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 64/100
Mantenedores costumam responder em até 1 dia
Todas as issues de php/php-src
Issues semelhantes
-
mcp: a projectPath naming a file inside a project returns isError ("Path is not a directory")Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
colbymchenry/codegraph#2982 ·
Mantenedores costumam responder em até 1 dia
-
area/build-framework kind/new-feature
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
yugabyte/yugabyte-db#36023 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 77/100
Mantenedores costumam responder em até 1 dia
-
Add masked GPIO pull configuration APIsTalvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
raspberrypi/pico-sdk#3279 ·
Mantenedores costumam responder em até 3 dias
-
documentation
Dificuldade 1/5 1-3 horas Facilidade para iniciantes 91/100
Mantenedores costumam responder em até 1 dia