Největším problémem webových diskusních fór jsou obvykle jejich přispěvatelé. Tedy přesněji malá, ale hlučná menšina, která zamořuje stránky vulgaritami či nemravnostmi. Pokud nechceme nebo nemůžeme každý došlý příspěvek podrobit „ruční“ kontrole, nezbývá než se spolehnout na služby nějakého automatu. Po článku o filtrování příspěvků v PHP tento představuje jednu z nejjednodušších variant řešení, kontrolu pomocí JavaScriptu.

V následujícím příkladě (zdroj) je jednoduchý formulář na odeslání jednořádkového diskusního příspěvku. Protože je však majitel stránek zapřísáhlým odpůrcem domácích zvířat, zejména psů a koček, filtruje odesílané příspěvky na výskyt slov „pes“ a „kočka“, případně jejich jazykových variant. Po stisku tlačítka „odeslat“ je zobrazena krátká zpráva s výsledkem filtrace.

Popis řešení

Celý skript je založen na využití objektu RegExp (regular expression). Tento nástroj prokazuje mnohým programátorům cenné služby, zejména při nevděčné a zdlouhavé manipulaci s řetězci a dekódováním uživatelského vstupu. Zde využijeme pouze malou část totiž vyhledávání určitého řetězce v řetězci jiném, s využitím zástupných znaků pro koncovky a podobnou češtinářskou „havěť“.

Nejdříve ze všeho je třeba definovat data, popisující „nevhodná slova“. Protože míra neslušnosti různých slov je různá, a protože také nechceme omylem vyřadit nezávadný příspěvek s jednou podezřelou formulací, je každému slovnímu základu přiřazena jeho váha. Skript samotný pak sčítá váhy nevhodných slov nalezených v textu a pokud celkové skóre přestoupí určitou hranici, odeslání příspěvku nepovolí. Je to jednoduchý princip, na vyřazení nejhorších příspěvků však docela stačí.

Databáze nevhodných slov je realizována jako dvourozměrné pole, v prvním sloupci je zapsáno příslušné slovo v konvenci pro regular expression. Pro naše účely postačí použití dvou zástupných znaků ze široké nabídky objektu RegExp, a to tečky pro nahrazení jednoho znaku a sekvence \\w* znamenající několik znaků. V druhém sloupci pole je uložena váha slova. Zároveň do proměnné treshold uložíme nejvyšší možné skóre, které je ještě akceptovatelné.

var keywords = [
    [ „pes“, 5 ],
    [ „ps.“, 3 ],
    [ „pejs\\w*“, 2 ],
    [ „kočk\\w*“, 3 ],
    [ „kočič\\w*“, 2 ]
];
var treshold=2;

Hlavní částí skriptu je pak funkce Validate, která zjistí hodnotu textového formulářového pole na vstupu, provede výpočet celkového skóre testovaného textu (viz popis v předchozím odstavci) a dle výsledku provede nějakou akci, tedy například zobrazení varovné zprávy, odeslání či neodeslání formuláře:

function Validate(theField) {
var re,i,ret;
    var score=0;
    for( i=0; i<keywords.length; i++ ) {
        re = new RegExp( „\\s“+keywords[i][0]+“\\s“,“i“);
        if(re.test(“ „+theField.value+“ „)) score += keywords[i][1]
    }
    txt = „Dosažené skóre filtrovaných slov je “ + score + „\nMaximální povolené skóre je “ + treshold + „\n“;
    if(score>treshold) {
        txt += „NEPOVOLENO“;
        ret=false;
    } else {
        txt += „ODESLÁNO“;
        ret=true;
    }
    var uavg = UserAverage(score);
    if(uavg > (treshold * 0.75) ) {
        txt += „\nUzivatel je znamy milovnik zvirat, prumerne skore ma „+uavg+“\nDODATECNE NEPOVOLENO“;
        ret=false;
    }
    alert(txt);
    return false;
}

Velký bratr se dívá

Těsně před koncem funkce najdete jednu anomálii: volání funkce UserAverage. Jde o drobné vylepšení kódu, spočívající v tom, že do uživatelova počítače (tedy do cookies, kam také jinam) ukládáme průměrné skóre všech příspěvků, které dotyčný odeslal. Tuto informaci pak můžeme využít k dodatečné rozhodovací akci. Jedná-li se o, dámy prominou, starého sprosťáka, jenž zřejmě omylem odeslal příspěvek, který prošel prvním sítem, můžeme jej přesto z diskuze vyřadit. Funkce UserAverage dělá z těchto činností dvě: ukládá skóre do cookie a vrací volajícímu průměrné skóre. Rozhodování zůstává na bedrech funkce Validate:

function UserAverage(theScore) {
    // Ziskame stare skore
    var oldScore = 1* MyCookie.Read(„filtering_score“);
    var oldCount = 1* MyCookie.Read(„filtering_count“);
    // inkrementujeme
    oldScore += theScore;
    oldCount++;
    // Ulozime zpet
    MyCookie.Write(„filtering_score“,oldScore,365);
    MyCookie.Write(„filtering_count“,oldCount,365);
    return Math.round(oldScore/oldCount);
}

Funkce je psána nadmíru „instruktážně“, v rámci úspory místa a velikosti lze, a je jistě i vhodnější, zhustit ji na dva sofistikované řádky.

Pro úplnost chybí uvést kód pomocné funkce MyCookie…

var MyCookie = {
    Write:function(name,value,days) {
        var D = new Date();
        D.setTime(D.getTime()+86400000*days)
        document.cookie = escape(name)+“=“+escape(value)+
        ((days == null)?““:(„;expires=“+D.toGMTString()))
        return (this.Read(name) == value);
    },
    Read:function(name) {
        var EN=escape(name)
        var F=‘ ‚+document.cookie+‘;‘, S=F.indexOf(‚ ‚+EN);
        return S==-1 ? null : unescape( F.substring(EN=S+EN.length+2,F.indexOf(‚;‘,EN)) );
    }
}

…a HTML kód formuláře, použitého v příkladu:

<form onSubmit=“return Validate(this.t)“>
    Zde napište text: <input type=“text“ name=“t“> <input type=“submit“ value=“Odeslat“ name=“x“>
</form>

Z uvedeného je zřejmé, že jako žádné strojové řešení, ani tento kód není rozhodně stoprocentní. Inteligentní uživatel si lehce najde způsob, jak uvedené filtry obejít. Protože však obvykle vulgarita příspěvku bývá nepřímo úměrná inteligenci jeho pisatele, dá se říci, že skript svou cílovou skupinu zasahuje.

Problematičtější je přesné vyvážení váhy jednotlivých slov a mezních hodnot, při kterých příspěvek vyřadit. Zde lze pravděpodobně doporučit nějakou dobu zkušebního provozu.

Asi by nebylo vhodné zamořovat stránky Intervalu výčtem různých částí lidského těla, zaměstnání či hovězího dobytka, proto si seznam „nevhodných“ slov můžete vyžádat mailem jako přílohu k již v úvodu zmíněnému článku. Bohužel se mi nepodařilo na internetu najít v češtině volně přístupnou další databázi podobných dat. Možná o ní budou vědět někteří ze čtenářů a podělí se o své znalosti s ostatními v připojené diskusi.

Žádný příspěvek v diskuzi

Odpovědět