{progz}

Véletlen idézet AJAX-szal: XMLHttpRequest, egy PHP végpont és az IE gyorsítótára

Tavaly az oldal egyik legnépszerűbb aloldala egy viccgyűjtemény volt, egy hosszú lista az ismert akciószínészről szóló „tényekkel”. Most egy kis dobozzá alakult át, amely gombnyomásra új véletlen idézetet tölt be, az oldal újratöltése nélkül. Ehhez nem kell semmilyen keretrendszer, és jó gyakorlófeladat az AJAX megértéséhez.

A végpont

Az idézetek egy egyszerű szövegfájlban vannak, soronként egy. A PHP ebből választ egyet:

<?php
// idezet.php
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

$sorok = file('idezetek.txt');
$sorok = array_filter(array_map('trim', $sorok));
echo $sorok[array_rand($sorok)];

A két gyorsítótár-fejléc nem véletlen, erről lent lesz szó.

A kérés

function ujKeres() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();           // Firefox, Opera, Safari, IE7
    }
    if (window.ActiveXObject) {
        return new ActiveXObject("Microsoft.XMLHTTP");   // IE6
    }
    return null;
}

function ujIdezet() {
    var xhr = ujKeres();
    if (!xhr) { return true; }                 // marad a sima link

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            document.getElementById("idezet").innerHTML = "";
            document.getElementById("idezet")
                .appendChild(document.createTextNode(xhr.responseText));
        }
    };
    xhr.open("GET", "idezet.php?t=" + new Date().getTime(), true);
    xhr.send(null);
    return false;
}
<blockquote id="idezet"><?php echo htmlspecialchars($elsoIdezet); ?></blockquote>
<a href="idezetek.php" onclick="return ujIdezet();">Másikat!</a>

Néhány részlet:

  • createTextNode, nem innerHTML. A válasz szövegként kerül az oldalra. Ha egy idézetben < jel van, az nem fogja szétszedni az oldalt.
  • return false. Ha az AJAX sikerült, a link nem nyílik meg. Ha nincs JavaScript vagy XMLHttpRequest, a link egy rendes PHP oldalra visz, amely szintén véletlen idézetet mutat. Mindenki kap tartalmat.
  • readyState == 4. A kérés kész. A status == 200 nélkül egy 404-es hibaoldal szövege is bekerülne a dobozba.

Az IE gyorsítótára

Az első változat Firefoxban tökéletesen működött, Internet Explorerben viszont mindig ugyanazt az idézetet hozta. Az IE az azonos URL-re érkező GET kérések válaszát gyorsítótárazza, és ez az XMLHttpRequest kérésekre is vonatkozik. Két védelem van, és én mindkettőt használom: a szerver no-cache és régi Expires fejlécet küld, a kliens pedig az URL végére tesz egy időbélyeget (?t=...), így minden kérés más címre megy.

jQuery-vel

A januárban megjelent jQuery 1.1-gyel ugyanez egyetlen sor:

$("#idezet").load("idezet.php?t=" + new Date().getTime());

Ez kényelmes, és a böngészők közötti különbségeket is elrejti. Mégis érdemes egyszer kézzel megírni, mert amikor valami nem működik, tudni fogod, mi történik a háttérben.