Javascript: controllo di form con le espressioni regolari

Esempio di formL’esigenza era quella di trovare uno script client-side sintetico ed efficace nella validazione dei form HTML. Gli aggettivi sintetico ed efficace portano subito a pensare alle Espressioni regolari! Ora, sebbene devo dire che non sono certo un esperto di espressioni regolari, riconoscendo la loro potenza e la loro versatilità ho cercato di approfondire l’argomento.
Utilizzando questa sintassi, è possibile validare decine di campi di un form HTML, ricorrendo ad una sola funzione Javascript. E’ sufficiente, in un’altra funzione, passare come parametro il giusto pattern per ogni campo del form.
Per utilizzare le Espressioni regolari in Javascript ci sono due modi:

  1. Assegnazione letterale: var regExpression = /pattern/;
  2. Assegnazione mediante costruttore: var regExpression = new RegExp("pattern");/code>

In questo script ho utilizzato il primo metodo, anche se in effetti sarebbe preferibile il secondo che permette di risparmiare ulteriore codice in quanto il pattern può essere passato come stringa.
I metodi dell’oggetto RegExp sono 2:

  1. test(string) : esegue un test sulla stringa in base al pattern fornito e ritorna TRUE o FALSE se trova o meno la corrispondenza
  2. exec(string) : esegue una ricerca sulla stringa in base al pattern fornito e ritorna NULL se non c’è corrispondenza, oppure un array che contiene i risultati.

Per la costruzione del pattern, è necessario conoscere alcuni rudimenti delle Espressioni regolari. Vediamo un breve sommario:

Principali metacaratteri (caratteri speciali)

  • . indica qualsiasi carattere (escluso un a capo)
  • * indica zero o più occorrenze (di un carattere o di un gruppo di caratteri)
  • ? indica zero o una occorrenza (di un carattere o di un gruppo di caratteri)
  • {} (parentesi graffe): indicano il numero esatto, o minimo, o massimo, o l’intervallo di occorrenze (di un carattere o di un gruppo di caratteri)
  • + indica una o più occorrenze (di un carattere o di un gruppo di caratteri)
  • ^ indica l’inizio della stringa (o, se all’interno di una classe di caratteri, la negazione della stessa)
  • $ indica la fine della stringa
  • | indica l’operatore OR
  • \ carattere di escape dei caratteri speciali
  • () parentesi tonde, destinate a contenere una sottostringa
  • [] parentesi quadre, destinate a contenere una ‘classe’ di caratteri

Conoscendo il significato di questi metacaratteri, e con l’aiuto dei numerosi tutorial disponibili in rete (vedi sezione Riferimenti ed approfondimenti), è possibile almeno capire e modificare a nostro uso, i pattern già pronti per il controllo dei più comuni campi che possono essere presenti in un form.

Lo script che propongo utilizza pattern integralmente presi o leggermente modificati, tratti da questo documento

i campi sottoposti a verifica che ho preso in considerazione, e le regole per l’immissione dei dati sono:

CampoRegolaPattern
Utentelettere, numeri, e i segni . _ –/^([a-zA-Z0-9\.\_\-])+$/
Passwordmin 6, max 12 di caratteri, numeri, _ * – + ! ? , : ; . e lettere accentate/^[a-zA-Z0-9\_\*\-\+\!\?\,\:\;\.\xE0\xE8\xE9\xF9\xF2\xEC\x27]{6,12}/
Nomecaratteri, lettere accentate apostrofo e un solo spazio fra le parole/^([a-zA-Z\xE0\xE8\xE9\xF9\xF2\xEC\x27]\s?)+$/
C.A.P.5 numeri/^\d{5}$/
E-mailcaratteri e . _ % – + @ + caratteri compreso . + . + min 2, max 4 caratteri/^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
Dataformato mm/gg/aaaa o mm-gg-aaaa o mm.gg.aaaa/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[-/.](19|20)\d\d/
Codice fiscalevedi regole su Wikipedia/^[a-zA-Z]{6}\d\d[a-zA-Z]\d\d[a-zA-Z]\d\d\d[a-zA-Z]/

Ecco il codice dello script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// JavaScript Document
//------------------------------------------------------------------------
// checkForm : checks each field for a given pattern of chars
function checkForm(frm){
  var pattern;
  // Utente (lettere, numeri, e i segni . _ -)
  pattern = /^([a-zA-Z0-9\.\_\-])+$/;
  if(!checkPatternChars('Utente',frm.user.value,pattern,true))
  {
   frm.user.focus();
   return false;
  }
  // Password (min 6, max 12 di caratteri, numeri, _ * - + ! ? , : ; .
  // e lettere accentate)
  pattern = /^[a-zA-Z0-9\_\*\-\+\!\?\,\:\;\.\xE0\xE8\xE9\xF9\xF2\xEC\x27]{6,12}/;
  if(!checkPatternChars('Password',frm.password.value,pattern,true))
  {
   frm.password.focus();
   return false;
  }
  // Nome (caratteri, lettere accentate apostrofo e un solo spazio fra le parole)
  pattern = /^([a-zA-Z\xE0\xE8\xE9\xF9\xF2\xEC\x27]\s?)+$/;
  if(!checkPatternChars('Nome',frm.name.value,pattern))
  {
   frm.name.focus();
   return false;
  }
  // C.A.P.  (5 numeri)
  pattern = /^\d{5}$/;
  if(!checkPatternChars('CAP',frm.cap.value,pattern))
  {
   frm.cap.focus();
   return false;
  }
  // E-mail
  pattern = /^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
  if(!checkPatternChars('E-mail',frm.email.value,pattern,true))
  {
   frm.email.focus();
   return false;
  }
  // Data formato mm/gg/aaaa o mm-gg-aaaa o mm.gg.aaaa
  pattern = /^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[-/.](19|20)\d\d/;
  if(!checkPatternChars('Data',frm.data.value,pattern))
  {
   frm.data.focus();
   return false;
  }
  // Codice fiscale
  pattern = /^[a-zA-Z]{6}\d\d[a-zA-Z]\d\d[a-zA-Z]\d\d\d[a-zA-Z]/;
  if(!checkPatternChars('Codice fiscale',frm.cf.value,pattern))
  {
   frm.cf.focus();
   return false;
  }
  return true;
}
//------------------------------------------------------------------------
// checkPatternChars : checks a specific pattern of typed chars
function checkPatternChars(nm,vlu,pattern,required){
  if ( required === undefined ) {
      required = false;
   } 
  if(!required && vlu==""){
    return true;
  }
  if (!pattern.test(vlu)){
    alert("Il campo "+nm+" non e\' valido!");
    return false;
  }
  else { 
    return true; 
  }
}

Un esempio è visibile qui il pacchetto è scaricabile qui

Conclusioni:

L’accoppiata javascript – Espressioni regolari fornisce un ottimo strumento di verifica client-side dei dati immessi dagli utenti. La verifica lato client, però, ha dei limiti e serve più che altro ad aiutare l’utente alla compilazione del form. Se si vuole essere davvero sicuri di avere dati corretti da passare alla query, è obbligatorio ripetere il controllo server-side, utilizzando magari gli stessi pattern e le corrispondenti funzioni PHP: ereg() ed eregi()

Riferimenti ed approfondimenti:

PHP: un semplice datagrid per applicazioni web

Esempio di datagridE’ piuttosto frequente, quando si sviluppano applicazioni web, di dover presentare i dati di una query in un datagrid, ovvero in una tabella HTML. In tutti questi casi, può essere comodo avere già pronta una classe che formatta i dati nella tabella e scrive per noi il codice HTML. Questa classe che ho scritto, pur essendo molto semplice e spartana, presenta alcune caratteristiche interessanti:

  • Il codice generato è XHTML valido
  • La presentazione è gestita da fogli stile CSS, quindi facilmente personalizzabile
  • E’ possibile, tramite il passaggio di parametri, creare una colonna aggiuntiva di link per azioni tipo “modifica”, o “dettaglio”
  • E’ possibile visualizzare o nascondere la colonna contenente la chiave primaria
  • Aspetto gradevole e alternanza di colorazione delle singole righe per una più facile lettura dei dati

Il codice della classe è molto semplice ed autoesplicativo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class dataGrid
{
  var $tabData;
  var $pkField;
  var $pkIsVisible;
  var $summaryTable;
  var $linkPage;
  var $linkLabel;
 
 function dataGrid($tabData, $pkField,
          $pkIsVisible, $summaryTable,
          $linkPage, $linkLabel)
 {
    $this->arrData=$tabData;
    $this->pkId=$pkField;
    $this->pkIsVisible=$pkIsVisible;
    $this->summaryTable=$summaryTable;
    $this->linkPage=$linkPage;
    $this->linkLabel=$linkLabel;
 }
 
 function makeTable()
 {
  $rowStyle=true;
  $printTh = false;
  $printTd = false;
  print("<table class='datatable' cellspacing='0'
        summary='$this->summaryTable'>");
        print("<tr>");
  $fldCount = mysql_num_fields($this->arrData);
  for ($i=0; $i<$fldCount; $i++ ) {
   $fldName = mysql_field_name($this->arrData, $i);
   if($this->pkId!=$fldName){
    $printTh = true;
   }
   else{
    if($this->pkIsVisible){
     $printTh = true;
    }
   }
   if($printTh){
    print("<th scope='col'>");
    print($fldName);
    print("</th>");
    $printTh = false;
   }
  }
  print("</tr>");
  while($row=mysql_fetch_array($this->arrData)){
   print("<tr>");
   $rowStyle=!$rowStyle;
   for($i=0; $i<$fldCount; $i++) {
    if($rowStyle)
     $tdStyle="<td class='alt'>";
    else
     $tdStyle="<td>";
    $fldName = mysql_field_name($this->arrData, $i);
    if($this->pkId!=$fldName){
     $printTd = true;
    }
    else{
     if($this->pkIsVisible){
      $printTd = true;
     }
    }
    if($printTd){
     print($tdStyle);
     print($row[$i]);
     print("</td>");
     $printTd = false;
    }
   }
   if($this->linkPage!=NULL){
    print($tdStyle."[<a href=".$this->linkPage."?"
          .$this->pkId."=".$row[$this->pkId]
          ." title='".$this->linkLabel."'>"
          .$this->linkLabel
          ."</a>]</td>");
   }
   print("</tr>");
  }
  print("</table>");
 }
}

Come utilizzare la classe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//---------------------------------------------
// Database connection params
// Modify for your connection, db and query
$host = 'localhost';
$user = 'root';
$password = '';
$database = 'prova';
$query = 'select * from es_libri order by autori';
//---------------------------------------------
// open the connection to the db server
$link = mysql_connect($host,$user,$password);
// change to the right database
mysql_select_db($database);
// do the SQL query
$result = mysql_query($query);
include ('datagrid.class.php');
// Print HTML
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
echo '<html xmlns="http://www.w3.org/1999/xhtml">';
echo '<head>';
echo '<meta http-equiv="Content-Type" 
     content="text/html; charset=iso-8859-1" />';
echo '<title>CSS Tables</title>';
echo '<link href="styles.css" rel="stylesheet" 
     type="text/css" />';
echo '</head><body>';
// Use datagrid class with full options
$mydatagrid = & new datagrid($result,"ISBN",true,
           "Tabella","test.php","modifica");
$mydatagrid->makeTable();
echo '<hr />';
// Use datagrid class without showing primary key, 
//with link option
$result = mysql_query($query);
$mydatagrid = &amp; new datagrid($result,"ISBN",false,
           "Tabella","test.php","modifica");
$mydatagrid->makeTable();
echo '<hr />';
// Use datagrid class without link options
$result = mysql_query($query);
$mydatagrid = &amp; new datagrid($result,"ISBN",true,
           "Tabella",NULL,NULL);
$mydatagrid->makeTable();
echo '<hr />';
// Use datagrid class without showing primary key
$result = mysql_query($query);
$mydatagrid = &amp; new datagrid($result,"ISBN",false,
           "Tabella",NULL,NULL);
$mydatagrid->makeTable();
echo '</body></html>';

Per vedere l’esempio, cliccare qui.
Questo, invece è il pacchetto contenente la classe, il file di esempio, il foglio stile e l’sql per la creazione della tabella “es_libri”, (da creare in un db chiamato “prova”).

Note:

Il codice per questa classe viene fornito ‘as is’, senza controllo di errori, né prove efficaci in produzione.

Conclusioni:

Ogni programmatore di applicazioni web dovrebbe avere una buona scorta di classi di utilità generale, da tenere in serbo per l’occasione giusta. E’ un buon metodo per risparmiare molto tempo, credo che questa semplice classe possa far parte della collezione!

Riferimenti ed approfondimenti:

Come evolve il web: l’X/HTML 5

zuppa di tagNel futuro del web si profila una svolta simile a quella del 1999-2002.
All’epoca l’introduzione dell’XHTML 1.0 che applica le rigide regole dell’XML all’HTML 4.01, metteva a freno il dilagare di documenti web
compilati in maniera maldestra per non dire completamente errata. Il parsing dei documenti da parte del browser (allora non c’era molta scelta…) presentava comunque un documento leggibile,
perché la gestione degli errori da parte del browser era molto tollerante. L’evoluzione di internet e quindi l’utilizzo di differenti user agent che avevano comportamenti differenti nell’interpretazione delle pagine malformate, ha fatto si che si ponesse un freno tutto ciò. Oltre alla richiesta di correttezza formale dei documenti web, bisogna tenere in considerazione anche la spinta dovuta ad una maggiore sensibilità verso l’accessibilità che è fra i principi promotori dell’XHTML 1.0, l’introduzione del web semantico e degli altri aspetti del cosidetto Web 2.0 e l’esigenza di una migliore indicizzazione sui motori di ricerca (i crawler preferiscono documenti corretti).

Molti addetti ai lavori, particolamente gli sviluppatori web piuttosto che i grafici “fac-totum” del web, hanno aderito al progetto, sebbene ancora oggi a quasi 8 anni dalla nascita di XHTML si stima che il 95% delle pagine web non siano valide! Il problema è che finché i browser faranno il parsing di un documento come fosse una zuppa di tag (tag soup), gli autori dei minestroni saranno sempre tranquilli che gli utenti continueranno a cibarsene. Infatti, un documento ben formato e un minestrone di tag serviti al browser con un content-type di tipo “text-html” risulteranno agli occhi dell’utente, identici. D’altra parte, a tutt’oggi solo i browser più recenti sono in grado di effettuare il parsing di un documento XHTML servito come dovrebbe, cioè come “application/xhtml+xml”. Ad ogni modo chi ha scelto l’XHTML strict si è almeno messo sulla buona strada per non dover rifare tutto in futuro (oltre a stare in pace con la propria coscienza di professionista del web).

Cosa è e cosa si propone di fare l’X/HTML 5?

La definizione, dalle parole di Ian Hickson

“E’ una nuova versione di HTML che ambisce a rimpiazzare HTML4 e XHTML1”

per ora in fase di bozza lo sviluppo viene curato da WHATWG

in maniera totalmente aperto, chiunque può partecipare. Uno degli aspetti più interessanti di questo progetto è senza dubbio l’idea che si possa finalmente avere un comportamento omogeneo dei browser, in virtù del fatto che i maggiori produttori (Mozilla, Apple, Opera software) sono già coinvolti e sembra che anche la Microsoft sia interessata all’iniziativa. Se poi questi produttori ne terranno conto davvero o meno, questa è un’altra storia.

Vediamo ora alcune novità:

  • Ampio supporto alle applicazioni web
  • Correzione degli errori dell’HTML4
  • Semplificazione del web rispetto al futuro XHTML2
  • Fusione dei modelli di Web applications 1.0, Web forms 2.0, Web controls 1.0 proposti da Mozilla, Apple ed Opera software
  • Nuova e razionale gestione della struttura del documento mediante nuovi tag: article, nav, header, footer. Sezioni logiche del documento divise in: contenuto, menù di navigazione, intestazione, piede di pagina. Vantaggi per i browser per palmari che potranno visualizzare solo la sezione che interessa
  • Limitazione all’utilizzo di javascript per il controllo dei forms, che sarà integrato nell’HTML
  • Introduzione dell’elemento canvas per la costruzione di immagini bitmap (tipo Yahoo pipes)
  • Specifico supporto per applicazioni web tipo Google Gear: implementazione di un sistema di salvataggio dati sul proprio sistema, editing negli elementi dei documenti, supporto al drag’n’drop
  • Introduzione di tag video e audio
  • Introduzione dell’elemento progress (barra di avanzamento), datagrid (griglia per tabelle)
  • Introduzione all’elemento dialog (supporto a chat)

Conclusioni:

l’X/HTML5 sarà molto probabilmente il futuro del web, gli sviluppatori troveranno uno strumento molto più potente di quelli che hanno avuto in passato, verranno corretti molti errori di forma e di sostanza sull’impronta della qualità dell’applicazione. l’XHTML2 d’altra parte ha troppi problemi di retrocompatibilità con i vecchi browser perché ha intrapreso una strada troppo rigida, peraltro inevitabile, per abbracciare in pieno la logica XML.
Ma l’X/HTML 5 rimarrà sostanzialmente un linguaggio markup strettamente legato ai browser, se un programmatore si vuole evolvere davvero, dovrebbe orientarsi verso piattaforme più ad alto livello, quali quelle che integrano XML, UML e paradigmi orientati agli oggetti

Riferimenti ed approfondimenti: