Minule jsem vám prozradil, jak ochránit kontaktní formulář přes posíláním jednoho e-mailu na několik adres a dnes si povíme, jak od tohoto formuláře odlákat roboty úplně. V druhé části článku dokonce naleznete hotové řešení dokonalého kontaktního formuláře !
Robota si můžete představit jako aplikaci nebo nějaký skript, který
projíždí stránky a slídí, kde by našel nějaký formulář a mohl ho
zběsile vyplnit nějakou reklamou a odeslat. Přičemž si prohlíží HTML
stránky čistě textově – nezobrazuje si grafiku nebo kaskádové styly,
jenom kouká na HTML tagy a jakmile uvidí <input type="text"
name="email" />, tak mu začnou kapat sliny. Ihned vyplní všechny
pole formuláře a zmáčkne všechny tlačítka, které odesílají formulář,
aby měl jistotu, že nedal třeba jenom náhled.
Takto jednoduše si lze představit robota – bohužel, tyto potvůrky se neustále vylepšují, takže některé si dokonce poradí s obrázkem, ze kterého musíte opsat znaky – tzv. CAPTCHA. I když vytvoříte speciální pole jenom pro roboty a skryjete ho pomocí CSS v domnění, že bude robot tak hloupý a vyplní ho taky, i zde můžete narazit. Avšak nepropadejme panice, řešení existuje !
Dobře nachytat robota lze na kontrolní otázce, na kterou nemá šanci znát odpověď. Může to být matematický příklad (3 + 4), doplnění do věty (skákal ___ přes oves) a podobně. Tato metoda je účinná, avšak obtěžuje uživatele – musí kvůli nám přemýšlet.
I když jsem mluvil o tom, že někteří roboti opravdu umí rozpoznat tyto obrázky, není jich tolik, a proto se dá využít i toto řešení. Já bych ho však nedoporučoval – rozhodně není přístupné a znechucuje uživatele ještě více než kontrolní otázka. Já je přímo nesnáším – někdy jsou tak šílené, že se na ten obrázek opravdu musíte dívat nejmíň půl minuty, abyste odtušili nakreslené znaky.
Na tomto blogu mám u přidávání komentářů pouze tlačítko „Náhled“. Odeslat příspěvek lze tedy až poté, co si ho prohlédnete. Věřte nebo ne, pouze toto stačí k odstrašení robotů (a doufám, že mi to ještě nějakou dobu vydrží). Bohužel je takovéto řešení použitelné jen v některých případech – nejčastěji v diskusích.
I když ty potvůrky umí všelicos, JavaScript ještě ne
Tedy proč toho
nevyužít – dělá se to tak, že pokud uživatel nemá JavaScript nebo ho
má vypnutý, tak se standardně nabízí nějaká kontrolní otázka a pokud je
JavaScript k dispozici, tak výsledek této otázky vloží do formuláře
pomocí <input type="hidden" ... /> a otázka samotná se
již nezobrazí a uživatele neobtěžuje.
Připravil jsem kontaktní formulář, který využívá poslední pasti na
roboty a to JavaScriptu. Jelikož dneska letí XHTML, tak jsem si nemohl dovolit
pouhé document.write, jelikož to specifikace nedovoluje. Proto je
vkládání JavaScriptem řešeno elegantněji pomocí DOM.
Kdyby se vám ve formuláři pozastavoval zrak nad tagem
<label>, tak vězte, že to je svázání popisku
s příslušným polem. Po kliknutí na popisek se kurzor přemístí do pole,
které k tomuto popisku patří. Každý přístupný formulář musí tento
tag obsahovat.
Celé řešení se skládá ze dvou souborů – samotný formulář a třída, která pracuje s daty, které jsou přes tento formulář odeslány.
napiste-nam.php
<?php
require_once "./MailForm.php";
$showForm = true;
if ( $_POST ) {
$form = new MailForm( $_POST[ "email" ], $_POST[ "text" ], $_POST[ "spamCheck" ],
$_POST[ "numbers" ] );
echo "<p>";
if ( $form->isValid( ) ) {
$showForm = false;
$form->sendMail( );
}
else {
$form->printErrors( );
}
echo "</p>\n";
}
if ( $showForm ) {
$first = rand( 0, 9 );
$second = rand( 0, 9 );
?>
<h2>Napište nám</h2>
<form action="napiste-nam.php" method="post">
<div id="myform">
<label>
Váš e-mail:
<input type="text" name="email" size="40"<?php
if ( !empty( $_POST[ "email" ] ) ) {
echo " value=\"".$_POST[ "email" ]."\"";
} ?> />
</label><br />
(není povinný, vyplňte pokud chcete dostat odpověď)
<br /><br />
<label>
Text e-mailu:<br />
<textarea name="text" cols="42" rows="10"><?php
if ( !empty( $_POST[ "text" ] ) ) {
echo $_POST[ "text" ];
}
?></textarea>
</label>
<br /><br />
<noscript>
<label title="Vyplňte výsledek součtu těchto dvou čísel (ochrana před roboty)">
Kolik je <?php echo $first." + ".$second ?>:
<input type="text" name="spamCheck" size="10" />
</label>
<br /><br />
</noscript>
<script type="text/javascript">
/* <![CDATA[ */
spamcheck = document.createElement( 'input' );
spamcheck.setAttribute( 'type', 'hidden' );
spamcheck.setAttribute( 'name', 'spamCheck' );
spamcheck.setAttribute( 'value', <?php echo $first ?> + <?php echo $second ?> );
document.getElementById( 'myform' ).appendChild( spamcheck );
/* ]]> */
</script>
<input type="hidden" name="numbers" value="<?php echo $first.$second ?>" />
<input type="submit" name="btn" value="Odeslat" />
</div>
</form>
<?php
}
?>
MailForm.php
<?php
class MailForm {
private $mail;
private $text;
private $spamCheck;
private $numbers;
private $errors;
public function __construct( $mail, $text, $spamCheck, $numbers ) {
$this->mail = $mail;
$this->text = $text;
$this->spamCheck = $spamCheck;
$this->numbers = $numbers;
$errors = array();
}
public function isValid( ) {
if ( empty( $this->mail ) ) {
$this->mail = "robot@domena.cz";
}
elseif ( !ereg( "^[_a-zA-Z0-9\.\-]+@[_a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,4}$",
$this->mail ) ) {
$this->errors[] = "E-mail byl vyplněn ve špatném formátu !";
}
if ( empty( $this->text ) ) {
$this->errors[] = "Nebyl vyplněn text e-mailu !";
}
if ( empty( $this->spamCheck ) ) {
$this->errors[] = "Nebyla vyplněna kontrolní otázka !";
}
elseif ( $this->spamCheck != ( $this->numbers[ 0 ] + $this->numbers[ 1 ] ) ) {
$this->errors[] = "Nebyla správně zodpovězena kontrolní otázka !";
}
if ( empty( $this->errors ) ) {
return true;
}
else {
return false;
}
}
public function sendMail( ) {
$obsah = iconv( "utf-8", "iso-8859-2", $this->text );
if ( mail( "info@domena.cz", "E-mail z webu", $obsah, "From: ".
$this->mail."\nContent-Type: text/plain; charset=iso-8859-2\n" ) ) {
echo "E-mail byl odeslán.";
}
else {
echo "E-mail se nepodařilo odeslat !";
}
}
public function printErrors( ) {
for ( $i = 0; $i < count( $this->errors ); $i++ ) {
echo $this->errors[ $i ]."<br />\n";
}
}
}
?>
Kódování e-mailu převádím z utf-8 na iso-8859–2, protože jsem zjistil, že některé webmaily si s unicode neporadí.
| Vloženo: 20. 6. 2007 14.15 | RSS komentářů tohoto článku |
| [1] Radek Tomášek | 20. 6. 2007 14.42 |
Skvělý článek, díky.. Věřím, že se to bude čas od času hodit
…
| [2] Petr Tichý | 24. 6. 2007 08.52 |
Jsi si jistý, že používáš element „label“ správně?
Nic se s ním neobaluje, ale umísťuje se většinou nad políčko a musí obsahovat atribut „for“ s hodnotou stejnou jako má atribut „name“ u dotyčného popsaného pole.
Navíc se popisek píše klasicky mezi počáteční a koncovou značku. Nikoliv jako atribut title.
Jinak pěkný článek, ale slyšel jsem, že si někteří roboti stahují už vygenerovanou stránku včetně výpisů JS. Je to možné?
| [3] Martin Grames (martin.grames@chapadlo.cz) | 24. 6. 2007 12.20 |
[2] Petr Tichý: Ano, element label používám správně – má totiž dvojí použití:
<label for="jmeno">Jméno: </label><input id="jmeno" type="text" name="jmeno" />
<label>Jméno: <input type="text" name="jmeno" /></label>
První verze se hodí spíše ke složitějším formulářům.
K druhému dotazu – je to možné, ale řešení JavaScriptem je zatím nejúčinnější.
| [4] Petr Tichý | 24. 6. 2007 13.55 |
[3] Martin Grames: To jsem nevěděl. Děkuji za informaci.
| [5] dsm (dysmusax@centrum.cz) | 21. 8. 2007 13.11 |
Co říkáte na tenhle způsob?
| [6] Martin Grames (martin.grames@chapadlo.cz) | 21. 8. 2007 17.29 |
[5] dsm: Tahle metoda mi příjde lepší, než testovat text na známé slova, které používají roboti. To pak příjdete zkrátka, i když budete do formuláře chtít napsat, že jsme včera hráli poker.
| [7] noname | 20. 4. 2008 01.32 |
Ahoj, co je v tom skriptu tohle: $this->mail = „robot@domena.cz“; tam mám zadat svůj mejl na kterej to chci ?
| [8] Martin Grames (martin.grames@chapadlo.cz) | 22. 5. 2008 12.57 |
[7] noname: Ne, to je e-mail odesílatele, který se použije pokud uživatel nevyplní svůj e-mail.
Adresa, kam se má e-mail posílat je uvedena v metodě sendMail.
| [9] dd | 1. 9. 2008 09.21 |
Jak by vypadal kod pro PHP 444? Nedari se mi ten zdrojak prepsat tak, aby fungoval. Diky
| [10] Martin Grames (martin.grames@chapadlo.cz) | 16. 9. 2008 20.25 |
[9] dd: Pro PHP 4 stačí v definici proměnných
nahradit private za var (private $mail
→ var $mail) a smazat klíčové slovo public před
definicí funkcí (public function isValid → function
isValid). Nakonec je třeba přejmenovat konstruktor na jméno třídy,
tedy __construct → MailForm. Pokud budete i nadále
tápat, zkuste použít nějaký nástroj na převod PHP 5 na
PHP 4.
| [11] Anonym | 13. 12. 2008 16.03 |
Hezký článek, jsem si jistý že jej využiji
| [12] Martin (martin.stanik@gmail.com) | 10. 1. 2010 21.56 |
Dobrý script má jen jednu chybku nefunguje když je zpráva s diakritikou, nevíte v čem je chyba? Díky
| [13] Martin Grames (martin.grames@chapadlo.cz) | 14. 2. 2010 14.51 |
[12] Martin: A máte skript uložen v kódování UTF-8 ?
| [14] marek | 24. 7. 2010 00.26 |
Úžasný script, už jej láduju na web
Mám jeden malý
dotaz – jak bych musel script upravit, aby pole email bylo povinné? Stačila
by jen nějaká drobná úprava, nebo by bylo nutné script z větší části
přepsat? Díky za odpověď