Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

dnes nový podtitulek!

PHP triky: generování JavaScriptu

Výstupem PHP skriptu bývá nejčastěji HTML stránka. S jejím generováním na úrovni značek může pomoci třeba knihovna NHtml. Ale ať už výstup generujete jakkoliv, je třeba mít na paměti, že každý řetězec se musí ošetřit funkcí htmlSpecialChars. To ji staví do pozice téměř nejdůležitější funkce, škoda proto, že nemá kratší název. Ačkoliv i to se dá napravit:

function h($s) {
    return htmlSpecialChars($s, ENT_QUOTES);
}

Nojo, ale co když potřebujeme ve stránce vygenerovat JavaScriptový kód? Jakou funkcí v něm ošetříme řetězce?

Je to s podivem, ale až do verze PHP 5.2.0 s touto eventualitou tvůrci nepočítali. Žádnou funkci pro „escapování“ řetězců jazyk nenabízel. Jako náhrada se občas používá addSlashes, jenže ta nevkládá lomítka na všechna potřebná místa a navíc je závislá na nastavení direktivy magic_quotes_sybase. Teprve s příchodem verze 5.2 přišla spása nazvaná json_encode.

$foo = ...;  // libovolný řetězec v UTF-8
echo '<script type="text/javascript">';
echo 'var foo = ', json_encode((string) $foo), ';';
echo 'alert(foo);';
echo '</script>';

Poznámka: pokud píšete v XHTML a obsah skriptu uzavíráte mezi značky <![CDATA[ a ]]>, je třeba ještě zajistit, aby se v textu skriptu neobjevila koncová značka. Ale lepší spíš bude se těmto Xvěcem vyhnout.

Sice za několik dní už žádného správného vývojáře verze nižší než 5.2.0 zajímat nebudou ;-), než k tomu však dojde, podělím se s vámi o alternativní řešení. To umí nejen sanitizovat řetězce, ale je plnohodnotnou náhradu funkce json_encode (potřebujete-li ošetřit pouze řetězce, stačí vám část za if (is_string($val))):

if (!function_exists('json_encode')) { // since PHP 5.2.0

    /**
     * JSON encode
     *
     * @author     David Grudl
     * @copyright  Copyright (c) 2007 David Grudl
     */
    function json_encode($val)
    {
        // indexed array
        if (is_array($val) && (!$val
            || array_keys($val) === range(0, count($val) - 1))) {
            return '[' . implode(',', array_map('json_encode', $val)) . ']';
        }

        // associative array
        if (is_array($val) || is_object($val)) {
            $tmp = array();
            foreach ($val as $k => $v) {
                $tmp[] = json_encode((string) $k) . ':' . json_encode($v);
            }
            return '{' . implode(',', $tmp) . '}';
        }

        if (is_string($val)) {
            $val = addslashes($val); // ' " \ NUL - due to bug #40915
            return '"' . addcslashes($val, "\x8..\xA\xC\xD/") . '"';
        }

        if (is_int($val) || is_float($val)) {
            return (string) $val;
        }

        if (is_bool($val)) {
            return $val ? 'true' : 'false';
        }

        return 'null';
    }
}

Tato funkce se oproti předloze liší v tom, že neodhalí rekurzivně zanořené pole nebo objekty. V případě polí by se jednalo o docela netriviální úkol a tudíž nejlepším řešením je ho neřešit vůbec.

Karma body: 15. Líbil se vám článek?

Komentáře » přidat

  1. [1] Jakub Vrána: nový

    JavaScriptové řetězce se dají ošetřit funkcí addcslashes. Viz můj článek.

    Posláno 16. 11. 2007 v 11.23 | Odpovědět
    Na komentář reagoval [2] David Grudl
  2. avatar [2] David Grudl: nový

    [1] Jakub Vrána: addcslashes používám také, ale nemyslím si, že jsi zvolil správný výčet znaků. Také bacha na bug #40915.

    Posláno 16. 11. 2007 v 11.35 | Odpovědět
  3. [3] filer: nový

    Ta rekurzia cez volanie callback funkcie v array_map je elegantna.

    Posláno 18. 11. 2007 ve 3.22 | Odpovědět
  4. [4] v6ak: nový

    Pokud vím, tak do JS to takt jde, ale když je JS v HTML, tak to může být problém…

    Posláno 18. 11. 2007 ve 13.57 | Odpovědět

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře ani hlasovat

Výtah na začátek článku na první komentář

Názory čtenářů v diskusích nejsou názory provozovatele webu, a ten za jejich obsah neodpovídá.

La Trine © 2004, 2008 David Grudl – o webu
provozuje Pachollini.

Jakékoliv užití obsahu, včetně převzetí článků nebo jejich částí, je bez předchozího písemného svolení autora zakázáno.

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.