Meta (PHP, htmlspecialchars)

Ennek a derék függvénynek az első paramétere egy string, amit feldolgoz, egy további paramétere pedig egy olyan string, ami az első string kódolását tartalmazza, hogy pl. 'UTF-8'. Megkérdeztem, hogy mivel csak ASCII karakaterekkel dolgozik a függvény, minek ez a további paraméter.

Azt mondták, ez azért jó, mert lehet [egy esetleges jövőbeli állapotban], hogy az első string nem is ASCII-kompatibilis [mint amilyen az ISO-8859-x vagy az UTF-8]. Namostan azt mondja meg valaki őszintén, hogy ha ez egy valós opció, akkor nem kellene-e egy mégtovábbi paraméter, ami a második paraméter kódolását tartalmazza? És persze így tovább a végtelenségig.

Na jó, elmondom a poént: a btmlspecialchars pont olyan, mint a htmlentities, csak mást csinál, ezért kell egyforma legyen a paraméterezésük (na brávó! mondja ilyenkor a süket főherceg a Sissy-ben).

A htmlentities-nek tényleg tudnia kell a kódolást, hiszen minden nem-ASCII karaktert &-szekvenciává alakít, ehhez tudnia kell, hogy milyen byte-sorozat milyen karaktert reprezentál.

Hozzászólások

Szerkesztve: 2024. 12. 05., cs – 10:40

 Megkérdeztem, hogy mivel csak ASCII karakaterekkel dolgozik a függvény, minek ez a további paraméter.

Ezt nem igazán értem. Ha megnézed az $encoding paraméter lehetséges értékeit, egyáltalán nem csak ASCII-kompatibilis string lehet a függvény bemenete.

Lehet azon Big5 kódolású string is, vagy éppen GB2312. Ezekben a karakterkészletekben/karakterkódolásokban is értelmezve vannak a HTML számára jelentéssel bíró, ezért escape-elendő karakterek, az az 5, aminek az escape-lését a htmlspecialchars csinálja.

ha ez egy valós opció, akkor nem kellene-e egy mégtovábbi paraméter, ami a második paraméter kódolását tartalmazza? 

Miért kéne? A forrásfájl kódolását meg lehet adni a declare(encoding=) függvény meghívásával, meg persze a php.ini-ben is, a zend.script_encoding beállításával globálisan.

> Lehet azon Big5 kódolású string is, vagy éppen GB2312.

Ebben igazságod van; kompromisszumként legfeljebb annyit mondhatok, hogy ezt a $string paramétert ne string tipusúnak terkintsük, hanem byte-array tipusúnak, szemben a $encoding paraméterrel, ami tényleg string. Ebben az esetben azt mondhatnánk, hogy ami az előre definiált encoding-ben van, az string, amihez viszont külön meg kell adni a kódolást, az a byte-array.

> Miért kéne? A forrásfájl kódolását meg lehet adni a declare(encoding=) függvény meghívásával,

Azért ezt még nem értem pontosan: ha a forrásfájl nem ASCII-kompatibilis, akkor hogy fogja az értelmező megérteni a benne lévő declare(encoding)-ot, amiből megtudná, hogy a forrásfájl nem ASCII-kompatibilis?

Azért ezt még nem értem pontosan: ha a forrásfájl nem ASCII-kompatibilis, akkor hogy fogja az értelmező megérteni a benne lévő declare(encoding)-ot, amiből megtudná, hogy a forrásfájl nem ASCII-kompatibilis?

Úgy, hogy beállítod a zend.script_encodingot, kötelezően jól (kiemelés tőlem): 

zend.script_encoding string

This value will be used unless a declare(encoding=...) directive appears at the top of the script. When ISO-8859-1 incompatible encoding is used, both zend.multibyte and zend.script_encoding must be used.

Literal strings will be transliterated from zend.script_encoding to mbstring.internal_encoding, as if mb_convert_encoding() would have been called.

 

 

>> Lehet azon Big5 kódolású string is, vagy éppen GB2312.

igen ezzel en is szopodtam a html parseremnel, hogy a CJK kodolasok hasznaljak a > jelet is, tehat eloszor dekodolnod kell unicode-ra aztan tudod html-parsolni csak...

> ezt a $string paramétert ne string tipusúnak terkintsük, hanem byte-array tipusúnak, szemben a $encoding paraméterrel, ami tényleg string

python3-ban ez igy is mukodik. py2-ben meg str volt mind2 :(

hat 2 eve irtam a parserem mar nem emlexem a reszletekre, a forrasban ezt talaltam, igy workaroundoltam:

 

        if charset and (charset.startswith("iso-2022") or charset.startswith("csiso2022")):  # https://en.wikipedia.org/wiki/ISO/IEC_2022
            data=data.decode(charset,errors="ignore").encode("utf-8")  # japan/koreai, 7 bitbe kodolt tobb byteos karakterkodok, ESC-el stb, a html parser nem birja :)
            charset="utf-8"

itt egy pelda html ilyen kodolassal, lathato hogy a sok < es > miatt igy nem parsolhato html-kent:

https://pastebin.com/3hm3Z2Ly

> ha ez egy valós opció, akkor nem kellene-e egy mégtovábbi paraméter, ami a második paraméter kódolását tartalmazza? 

Nem, mert ezt a paramétert a legtöbb esetben statikus konstansként adodd meg a forráson belül. Ha végiggondolod, a függvényhívás meg sem történik, ha nem tudjuk felolvasni az encodingot (amennyiben string literálként adod át paraméterben). Persze, lehet más forrásból is a paraméter értéke, de nagyon ritkán -> nem készültek ilyen edge case-re.

Illetve szerintem a PHP-ban van valamennyi beleértett kompatiiblitás is, pl lehet, hogy képes a Windows-os UTF-16 formátumú forrásfájlok megfelelő felolvasására is, azonban ez az encofing nem tejlesen ASCII-kompatibilis, mivel minden karakter 2 byte-on van tárolva, az is, ami amúgy beleesik az ASCII 32-128 intervallumba. És nem lenne jó, ha emiatt nem találná meg a kacsacsőrt, mert bezavart neki az előtte-utána levő CHR$(0). 

Blog | @hron84

valahol egy üzemeltetőmaci most mérgesen toppant a lábával 

via @snq-

> ezt a paramétert a legtöbb esetben statikus konstansként adod meg a forráson belül.

Hát bocsánat, a "legtöbb esetben"-t nem tudom érvként elfogadni.

Egyébként azt gondolnám, hogy van egy fordítási fázis a tényleges futás előtt, melynek során a literálok [feltehetőleg] konvertálódhatnak "source encoding"-ról "default encoding"-ra. (Esetleg végzek némi kutatást, és az eredményt bepasztázom az EkezetesFaq-ba.)

Azért nem minden papsajt; ha mondjuk teszünk egy ilyen a script-be:

<?php
    declare(encoding='iso-8859-16');
    ini_set('zend.multibyte', true);
    $s= '1.§ árvíztřrő tükörfúrógép';
?>

akkor lesz egy ilyen hibánk:

declare(encoding=...) ignored because Zend multibyte feature is turned off by settings

de ha ilyenre javítjuk:

<?php
    ini_set('zend.multibyte', true);
    declare(encoding='iso-8859-16');
    $s= '1.§ árvíztřrő tükörfúrógép';
?>

akkor lesz egy másik hibánk:

Encoding declaration pragma must be the very first statement in the script

Azt mondanám, hogy ezt engedjük el, nem nekünk való.

Röviden és tömören: a zend.multibyte beállítása ini_set által egy értelmezhetetlen dolog.

Két eset van ugyanis: a script vagy ISO-8859-1 kompatibilis, vagy nem ISO-8859-1 kompatibilis.

Első esetben nincs szükség így a zend.multibyte-ra, de akkor meg ini_set-nek és a declare(encoding)-nak sincs értelme, ignorálható.

Második esetben szükség van a zend.multibyte-ra és a declare(encoding)-ra, de akkor már a scriptben lévő BÁRMILYEN más utasítás értelmezése előtt szükséges tudni a karakteródolását a scriptnek - azaz minden utasítás (így az ini_set is) értelmetlen declare(encoding) előtt.

 

Arra meg szerintem nem érdemes felkészülni, hogy a script egy része ilyen, másik része olyan kódolásban van. Például az első 80 karaktere ISO-8859-2, a maradék 800 meg UTF-16. Az egy programozói balfaszság, arra felesleges készülni.

Nem véletlenül írja ezt a dokumentáció: This value will be used unless a declare(encoding=...) directive appears at the top of the scriptWhen ISO-8859-1 incompatible encoding is used, both zend.multibyte and zend.script_encoding must be used.

Épp ezt mondom: ad-hoc próbálgatáshoz, egyedi játszódáshoz akár a php.ini piszkálása is oké, de a termelésben, valós használatban szó sem lehet róla. (Különösen, ha nem is standalone, hanem httpd-modul php-ról van szó.)

(Az összehasonlítás kedvéért képzeljük el, hogy pl. a `javac` program `-encoding` opcióját megszüntetjük, helyette valahol a $JAVA_HOME/jre/lib-ben kell valamit matatni.)