Ostatnio spotkałem się z problemem uciążliwych spambotów uparcie zaśmiecających pilnowane przeze mnie forum (na skrypcie Przema). Co jakiś czas pojawiały się posty anonimowych użytkowników z Chin, Korei itp., zawierające treści pornograficzne. Na dłuższą metę rzecz dość irytująca i uciążliwa. Struktura, założenia i przeznaczenie tego konkretnego forum wymagały, by osoby niezalogowane mogły pisać i zakładać nowe tematy w kilku podforach, więc odpadała opcja “tylko dla zarejestrowanych”. Trzeba więc było wymyślić jakiś sposób na sprawdzenie, czy niezalogowany gość nie jest botem.

Wcześniej jednak odrobinę wzbogaciłem “mechanizm weryfikacyjny” (captcha) w formularzu rejestracyjnym. Po co i jak to zrobić – dowiesz się z tego wpisu na blogu tPython.com. Przydatne również wtedy, gdy konta aktywujesz samodzielnie – unikniesz niepotrzebnych wiadomości w skrzynce email.

Zanim jeszcze wrócę do głównego wątku, pragnę zaznaczyć, iż jestem leniwy, nie jestem programistą i nie znam się na php. ;-)

Do rzeczy. Wymyśliłem sobie, że w formularzu nowej notki pojawi się dodatkowe pole, w które trzeba wpisać jakiś konkretny ciąg znaków. Można ograniczyć się do podobnego rozwiązania jak w przypadku rejestracji, ale ja postanowiłem zaszaleć – w rzeczone pole trzeba po raz drugi wpisać nick. ;P
(Modyfikacje dotyczą wersji modified by Przemo, ale prawdopodobnie w czystym phpbb będzie podobnie.)

Dodatkowe pole

1. Najpierw plik posting.php. Szukamy tam fragmentu:

case 'newtopic':
case 'reply':

Pod case 'reply': wpisujemy:

if ( $userdata['user_id'] == ANONYMOUS ) {
$kluczyk = (!empty($HTTP_POST_VARS['kluczyk'])) ? $HTTP_POST_VARS['kluczyk'] : '';
}

Przechodzimy kilka linijek niżej, do

prepare_post($mode, $post_data, $bbcode_on, $html_on, $smilies_on, $error_msg, $username, $bbcode_uid, $subject, $subject_e, $message, $poll_title, $poll_options, $poll_length, $max_vote, $hide_vote, $tothide_vote, $forum_id);

i przed zamykającyn nawiasem dopisujemy: , $kluczyk
Końcówka będzie wyglądała tak:
$tothide_vote, $forum_id, $kluczyk);

W tym samym pliku znajdziemy linijkę zawierającą komentarz:

// Output the data to the template

Uzupełniamy kod pod komentarzem o linie zaznaczone jaśniejszym kolorem:

$template->assign_vars(array(
'L_KLUCZYK' => $lang['Kluczyk'],
'L_KLUCZYK_EXPLAIN' => $lang['Kluczyk_explain'],
'L_KLUCZYK_NOTE' => $lang['Kluczyk_note'],

'L_SUBJECT' => $lang['Subject'],
'L_SUBJECT_E' => $lang['Subject_e'],

2. Przechodzimy do includes/functions_post.php. Wyszukujemy linię zaczynającą się od function prepare_post i uzupełniamy o jaśniejszy fragment.

function prepare_post(&$mode, &$post_data, &$bbcode_on, &$html_on, &$smilies_on, &$error_msg, &$username, &$bbcode_uid, &$subject, &$subject_e, &$message, &$poll_title, &$poll_options, &$poll_length, &$max_vote, &$hide_vote, &$tothide_vote, $forum_id = '', $kluczyk = '')

Dalej, w obrębie funkcji prepare_post, znajduje się kilka “części” opisanych komentarzami: // Check username, // Check subject, // Check message i tak dalej. Poniższy fragment wpisałem między check subject a check message (pewnie można też w innym miejscu):

// Check kluczyk ;-)
if (!$userdata['session_logged_in'])
{
if ( empty($kluczyk) || $kluczyk != $username)
{
$error_msg .= ( !empty($error_msg) ) ? '<br />' . $lang['Kluczyk_empty'] : $lang['Kluczyk_empty'];
}
}

3. Następny plik, którym się zajmiemy, to jeden z plików stylu – posting_body.tpl (dla domyślnego subSilver będzie to templates/subSilver/posting_body.tpl). Ja umieściłem dodatkowe pole pod tym przeznaczonym na dodatkowy opis tematu, ale oczywiście można je wstawić gdzieś indziej. Pod linią zawierającą <!-- END topic_explain --> dopisz:

<!-- BEGIN switch_user_logged_out -->
<tr>
<td class="row1" valign="top"><span class="gen"><b>{L_KLUCZYK}</b></span></td>
<td class="row2" align="left"><span class="gensmall">{L_KLUCZYK_EXPLAIN}<br /><input type="text" name="kluczyk" class="post2" onFocus="Active(this)" onBlur="NotActive(this)" maxlength=”25″ size="25"></span><br /><span class="gensmall">{L_KLUCZYK_NOTE}</span></td>
</tr>
<!-- END switch_user_logged_out -->

4. Ostatni plik – lang_main.php. Dla porządku gdzieś w części Posting/Replying, dopisujemy:

$lang['Kluczyk'] = 'Uwierzytelnianie';
$lang['Kluczyk_empty'] = 'Błąd uwierzytelniania!';
$lang['Kluczyk_explain'] = 'Poniżej wpisz to samo, co w pierwszym polu';
$lang['Kluczyk_note'] = 'Zabezpieczenie przeciw spam-botom, przepraszamy za kłopot.';

W ostatnim kroku możesz wykazać się inwencją. ;)

I to by było na tyle. Co prawda nie wiem, czy bot domyślnie nie wpisuje we wszystkie krótkie pola tego samego tekstu. Zamiast nicka można sprawdzać dowolny ciąg znaków (uwzględniając parametr maxlength znacznika <input> w pliku szablonu), podstawiając w linijce if ( empty($kluczyk) || $kluczyk != $username) z punktu drugiego 'cokolwiek' zamiast $username.