Počet přečtení článku
Ve skupinách na Facebooku se nově zobrazuje (možná ještě ne všem) počet přečtení jednotlivých zpráv. Jak něco takového realizovat na svém webu?
Pastva pro roboty
Trivialita, řeknete si: mysql_query("UPDATE article SET reads = reads + 1 WHERE id = $id")
. Toto řešení ale má dva problémy:
- Nesleduje, kolik lidí si článek přečetlo, ale kolikrát byla navštívená stránka.
- Přístup započte všem, i robotům.
Důkladné řešení
V první řadě musíme zamezit vložení do (skrytého) rámu. Toho dosáhneme posláním hlavičky X-Frame-Options: deny
.
Dále se potřebujeme bránit proti CSRF. Abychom to mohli udělat, tak potřebujeme uživatele nějak identifikovat, zbytek článku tedy bude počítat s nastavenými proměnnými $_SESSION["user_id"]
a $_SESSION["csrf_token"]
.
Článek se má označit jako přečtený automaticky, takže se u takto jednoduchého problému kupodivu neobejdeme bez JavaScriptu:
<script type="text/javascript">
jQuery.post('read-article.php?id=<?php echo $id; ?>', {
csrf_token: '<?php echo $_SESSION["csrf_token"]; ?>'
});
</script>
Volání si můžeme ušetřit, pokud při zobrazování zjistíme, že aktuální uživatel už článek dříve četl.
Na straně serveru pak čtenáře uložíme (nad dvojicí cloupců article_id, user_id
je unikátní klíč):
<?php // read-article.php if ($_SESSION["csrf_token"] == $_POST["csrf_token"]) { mysql_query(" INSERT IGNORE INTO article_reads (article_id, user_id) VALUES (" . intval($_GET["id"]) . ", $_SESSION[user_id]) "); } ?>
Uložení až po dočtení
Pokud je článek delší, tak ho můžeme chtít za přečtený označit až po nějaké době od focusu okna. Pokud si uživatel otevře odkaz do panelu na pozadí (což osobně dělám často), tak se článek jako přečtený zatím neoznačí:
<script type="text/javascript">
jQuery(window).one('focus', function () {
setTimeout(function () {
jQuery.post('read-article.php?id=<?php echo $id; ?>', {
csrf_token: '<?php echo $_SESSION["csrf_token"]; ?>'
});
}, 10000);
});
</script>
Přečtení se dá taky spustit po dojetí na konec článku. K tomu bych nejspíš využil nějaký jQuery plugin.
Diskuse
Rudolf:
Chybí tady G+ abych mohl dát článku +1 ;-) Takže aspoň v podobě komentáře. Hezky a jasně napsáno, díky, přesně co jsem chtěl za pár dní řešit, takže přišlo i vhod.
starenka
:
Proc X-Frame-Options: Deny? Nestaci Same-Origin?

Jakub Vrána
:
Stačí.


Peter:
A čím je dosiahnuté, že roboti sa nezapočítajú? Len tým, že to ide cez jQuery?
Jakub Vrána
:
I když by robot spustil JavaScript, tak nejspíš nespustí událost focus. I když by ji spustil, tak nejspíš nebude čekat 10 sekund na timeout. A pak taky samozřejmě záleží na tom, kdy a jak naplníme $_SESSION["user_id"].


Vopičák:
A zároveň se nezapočítají uživatelé bez JS...
Michal Gebauer:
Těch je málo a většina, co nemá povolený javascript chce být anonymní.

Petr Jirásek:
Velice vhodné. Právě tohle jsem hledal. +1

Diskuse je zrušena z důvodu spamu.

