PHP è un linguaggio server side molto potente, e molte delle primitive incluse nativamente (specialmente in ambiente Linux) sono sfruttabili per le più comuni operazioni: tra queste, potremmo citare la possibilità di verificare, direttamente dal vostro sito, se un dominio sia libero oppure no, facendo in modo di comunicarlo in output all’utente, e prestandosi così all’uso all’interno di moltissime applicazioni web. Si tratta di un qualcosa che consideriamo di primaria importanza per determinati tipi di siti, e personalizzando con un po’ di fantasia questo tipo di applicazioni è possibile creare applicativi web utili, possibilmente originali e creativi. La cosa essenziale è testare questo codice preventivamente in locale, avendo la connessione ad internet attiva ed evitando di pubblicarlo su siti online prima di averne controllato ogni minimo dettaglio: questo, ovviamente, per evitare di compromettere la sicurezza del server che ci ospita. Divideremo per comodità l’operazione di verificare lato PHP un dominio per controllare se è libero oppure no in tre fasi:
- validazione dell’input utente;
- check con diversi metodi del dominio inserito,e restituzione del risultato del controllo
#1 Validazione dell’input utente
La validazione è utile per verificare che l’utente non abbia inserito dati errati in maniera involontaria, ed ancor più per evitare eventuali rischi di code-injection, SQL-injection ed altri rischi per la sicurezza. È consigliabile effettuare questi controlli lato javascript o PHP anche se, di fatto, non è obbligatorio farlo: questo perchè utenti malintenzionati o maliziosi potrebbero immaginare come è stato scritto il nostro codice PHP e sfruttarne le debolezze (specie in fase di sviluppo iniziale) per manipolare o iniettare dati scorretti o arbitrari nel nostro sito. Al fine di evitare rischi, dunque prenderemo almeno uno dei seguenti accorgimenti: la validazione dell’input è intesa, infatti, per prevenire l’inserimento di dati poco sicuri nel sito, e permette di filtrare adeguatamente i contenuti ragionando nella logica di limitare le possibilità per l’utente, e ridurle al minimo indispensabile. Da un punto di vista logico faremo in modo di verificare che il nome non inizi e non finisca con un trattino (-), che la lunghezza del nome sia inferiore ai 63 caratteri e che siano incluse in essa anche le nuove estensioni (eventualmente superiori a 3 caratteri, non superiori a 63 comunque). La funzione di check della correttezza del dominio potrebbe essere, in PHP:
<?php function is_valid_domain_name( $domain_name ) { //check char + lunghezza return ( preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) ); } ?>
Fatto questo, avremo escluso qualsiasi altra stringa che non corrisponda ad uno dei domini riportati di seguito, proteggendoci contro eventuali inclusioni di codice o SQL (0 corrisponde a nomi non validi, 1 a nomi validi).
is_valid_domain_name? [a] 1 is_valid_domain_name? [0] 1 is_valid_domain_name? [a.b] 1 is_valid_domain_name? [localhost] 1 is_valid_domain_name? [google.com] 1 is_valid_domain_name? [news.google.co.uk] 1 is_valid_domain_name? [xn--fsqu00a.xn--0zwm56d] 1 is_valid_domain_name? [goo gle.com] 0 is_valid_domain_name? [google..com] 0 is_valid_domain_name? [google.com ] 0 is_valid_domain_name? [google-.com] 0 is_valid_domain_name? [.google.com] 0 is_valid_domain_name? [<script] 0 is_valid_domain_name? [alert(] 0 is_valid_domain_name? [.] 0 is_valid_domain_name? [..] 0 is_valid_domain_name? [ ] N is_valid_domain_name? [-] N is_valid_domain_name? [] N
L’unico problema di questo approccio, come si vede, è che considera 0 oppure a.b come nomi validi quando in realtà non lo sono: per questo motivo è opportuno validare diversamente il codice. Ad esempio w3lessons suggerisce qualcosa del genere (va bene anche per i domini con le nuove estensioni, anche in questo caso):
<?php function is_valid_domain_extension($domain) { return preg_match('/^([a-z0-9]([-a-z0-9]*[a-z0-9])?\\.)+((a[cdefgilmnoqrstuwxz]|aero|arpa)|(b[abdefghijmnorstvwyz]|biz)|(c[acdfghiklmnorsuvxyz]|cat|com|coop)|d[ejkmoz]|(e[ceghrstu]|edu)|f[ijkmor]|(g[abdefghilmnpqrstuwy]|gov)|h[kmnrtu]|(i[delmnoqrst]|info|int)|(j[emop]|jobs)|k[eghimnprwyz]|l[abcikrstuvy]|(m[acdghklmnopqrstuvwxyz]|mil|mobi|museum)|(n[acefgilopruz]|name|net)|(om|org)|(p[aefghklmnrstwy]|pro)|qa|r[eouw]|s[abcdeghijklmnortvyz]|(t[cdfghjklmnoprtvwz]|travel)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])$/i',$domain); } ?>
#2 Check del dominio e restituzione risultato
Per controllare in PHP se un dominio esiste o meno ci sono diversi metodi: l’applicazione potrebbe variare a seconda dell’estensione considerata, nella pratica, per cui è opportuno testare quello più idoneo al proprio caso. Il metodo base per avere questo genere di informazioni è legato a funzioni che verificano il settaggio dei record DNS del dominio stesso, ma questo metodo è soggetto ad errore in certi casi. Tantomeno è possibile utilizzare la verifica della risoluzione del DNS su un IP perchè in molti casi tale informazione non fornisce una risposta alla domanda richiesta (ci sono domini parcheggiati che rispondono ad un IP ma non sono di fatto disponibili). La risposta è utilizzare la libreria di PHP phpWhois, che si scarica gratis e che si usa in questo modo.
include_once('whois.main.php'); include_once('whois.utils.php'); $whois = new Whois(); $whois->deep_whois = empty($_GET['fast']); //opzionale, più veloce ma meno preciso $whois->UseServer('uk','whois.nic.uk:1043?{hname} {ip} {query}'); //opzionale per query su domini .uk $whois->UseServer('au','whois-check.ausregistry.net.au'); //opzionale per query su domini .au $whois->non_icann = true;// abilita il supporto per domini non-ICANN $result = $whois->Lookup($query);
A seconda delle risposte del server di WHOIS si vanno quindi a differenziare i case, tenendo conto che mostreremo le informazioni che ci vengono fornite in modo dinamico, cioè caso per caso, ed alla peggio mostreremo all’utente il contenuto della risposta in modo “grezzo” (raw):
switch ($output) { case 'object': if ($whois->Query['status'] < 0) { $winfo = implode($whois->Query['errstr'],"\n "); } else { $utils = new utils; $winfo = $utils->showObject($result); } break; case 'nice': if (!empty($result['rawdata'])) { $utils = new utils; $winfo = $utils->showHTML($result); } else { if (isset($whois->Query['errstr'])) $winfo = implode($whois->Query['errstr'],"\n "); else $winfo = 'Unexpected error'; } break; case 'proxy': if ($allowproxy) exit(serialize($result)); default: if(!empty($result['rawdata'])) { $winfo .= '<pre>'.implode($result['rawdata'],"\n").'</pre>'; } else { $winfo = implode($whois->Query['errstr'],"\n"); } } $resout = str_replace('{result}', $winfo, $resout);
Ricordiamo che la documentazione all’interno del file riporta ulteriori dettagli, e che phpWhois richiede di PHP versione 4.3 con, se possibile, supporto ad SSL: solo in questo modo sarà possibile effettuare query a domini che possiedono un WHOIS basato su HTTPS. Per maggiori informazioni in merito a queste tecnologie si vedano i piani KeliCMS e KeliSSL e la FAQ che abbiamo recentemente caricato sul sito.