Rulez un serviciu mic pe PHP 8.2, Alpine, container de 512 MB, care primește webhook-uri JSON de la un partener. Volumele nu sunt mari: 3–4 req/s, dar payload-urile variază între 200 KB și 2,3 MB. La un moment dat, cam 1 din 40 de request-uri intra pe ramura de eroare cu json_decode returnând null, deși partenerul jura că trimite JSON valid. Nu era nici timeout, nici body gol.
Primul pas a fost să nu mai ghicesc, ci să măsor. Am adăugat temporar un log care scrie json_last_error_msg() și lungimea body-ului, plus memory_get_peak_usage(true):
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
error_log(sprintf('json=%s len=%d peak=%d', json_last_error_msg(), strlen($raw), memory_get_peak_usage(true)));
}
Rezultatul a fost clar după două zile: Maximum stack depth exceeded pe payload-urile mari, nu Syntax error. Partenerul avea un array imbricat generat dintr-un export de arbore de categorii, cu adâncime peste 512. json_decode are implicit depth = 512 și, când îl depășește, întoarce null fără să arunce excepție dacă nu folosești flag-ul potrivit.
Am schimbat apelul:
$data = json_decode($raw, true, 2048, JSON_THROW_ON_ERROR);
Și am prins JsonException în controller, ca eroarea să ajungă în log cu context, nu într-un 500 mut. Am urcat și memory_limit la 256M, pentru că la 2,3 MB de JSON cu obiecte mari, reprezentarea internă a array-urilor asociative consumă de câteva ori mai mult decât textul brut.
De ce funcționează: adâncimea e o limită de siguranță împotriva recursivității, nu o caracteristică a formatului. Dacă o ridici, accepți că parserul poate consuma stivă și memorie proporțional cu structura, deci trebuie să ai o limită de body la nivel de server (eu am client_max_body_size 4m în nginx) și un timeout. Altfel muți problema din json_decode în OOM killer.
Unde se strică: dacă partenerul trimite array-uri mai adânci de 2048, ești în aceeași situație, doar cu un număr mai mare. Și dacă activezi JSON_THROW_ON_ERROR global într-un cod vechi care se baza pe null, începi să arunci excepții în locuri care nu le prind. Am pățit-o într-un job de import care verifica doar if (!$data).
Voi ce limită de adâncime folosiți în producție și ați văzut vreodată un payload legitim care să o depășească?


0 条评论
还没有评论,写下第一条。