Archive for the ‘PHP’ Category

Classe per l’invio di file tramite il protocollo FTP in PHP

In questo articolo vedremo una classe creata per l’utilizzo delle funzioni php per il trasferimento di file attraverso il protocollo FTP (File Transfer Protocol). Ho cercato di semplificare la classe per far eseguire le funzioni elementari utili per lo scambio di file con un server FTP remoto, utilizzando anche meccanismi per la verifica dei file che controllino che il file sia già presente sul server o meno.

Come al solito posto tutto il codice e, successivamente, verrà commentato. Ho chiamato la classe simpleFtp.

<?php

class simpleFtp {

 //dati per l'accesso
 var $ftp_host = ''; //indirizzo server ftp
 var $username = ''; //nome utente per l'accesso ftp
 var $pwd = '';      //password per l'accesso ftp
 var $connect;
 var $login;
 var $source_file;
 var $destination_file;

 //nel costruttore effettuo connessione e login
 function simpleFtp(){
 //effettuo la connessione
 $this->connect = ftp_connect($this->ftp_host) or die("Si è verificato un errore durante la connessione al server ftp");

 //effettuo il login
 $this->login = ftp_login($this->connect, $this->username, $this->pwd) or die("Si è verificao un errore durante l'accesso al server ftp");

 }

 //funzione per il trasferimento dei file
 function trasferisci($sorgente, $destinazione){
 //file da trasferire
 $this->source_file = $sorgente;
 //va indicato il percorso e il nome del file
 $this->destination_file = $destinazione;
 //verifico che il file non esista già altrimenti modifico il nome
 $this->destination_file = $this->verificaFile($this->destination_file, 'put'); 

 ftp_put($this->connect, $this->destination_file, $this->source_file, FTP_BINARY) or die("Errore durante l'upload del file $source_file nel server ftp");

 }

 function preleva($destinazione, $sorgente){
 if($this->verificaEsistenza($sorgente)){
 //file da trasferire dal server remoto
 $this->source_file = $sorgente;
 //percorso e nome locale da dare al file
 $this->destination_file = $destinazione;
 //verifico che il file non esista già altrimenti modifico il nome
 $this->destination_file = $this->verificaFile($this->destination_file, 'get');        

 ftp_get($this->connect, $this->destination_file, $this->source_file, FTP_BINARY) or die("Errore durante il download del file $source_file nel server ftp");

 }else
 echo "File non trovato.";
 }

 //cancella un file sul server remoto
 function cancella($file){
 if($this->verificaEsistenza($file))
 ftp_delete($this->connect, $file) or die("Errore durante la cancellazione del file dal server ftp");
 else
 echo "File non trovato";
 }

 //cambia la directory sul server remoto
 function cambiaDirectory($dir){
 ftp_chdir($this->connect,$dir) or die('Errore durante il cambio di directory');
 }

 //restituisce la directory corrente
 function directoryCorrente(){
 return ftp_pwd($this->connect);
 }

 //cambia i permessi su un file, i permessi devono essere a 4 cifre. Es.: 0755
 function cambiaPermessiFile($permessi, $file){
 if($this->verificaEsistenza($file) && is_numeric($permessi))
 ftp_chmod($this->connect, $permessi, $file);
 else
 echo "File non trovato";
 }

 //rinomina un file sul server remoto
 function rinomina($old, $new){
 if($this->verificaEsistenza($old)){
 $new = $this->verificaFile($new, 'put');
 ftp_rename($this->connect, $old, $new);
 }
 else
 echo "File non trovato";
 }

 //restituisce un array con i nomi dei file nella directory passata
 function visualizzaFile($dir){
 $result = ftp_nlist($this->connect, $dir);
 return $result;
 }

 //crea una directory sul server remoto a partire dalla directory corrente
 function creaDirectory($dir){
 @ftp_mkdir($this->connect, $dir) or die('La directory esiste già o non hai i permessi per crearne una.');

 }

 //elimina una directory dal server remoto a partire dalla directory corrente
 function eliminaDirectory($dir){
 @ftp_rmdir($this->connect, $dir) or die('La directory non esiste o non hai i permessi per eliminarla.');

 }

 //chiudo la connessione
 function close(){
 ftp_quit($this->connect) or die("Si è verificato un errore durante la chiusura della connessione al server ftp");
 }

 //Verifico il tipo di file in base all'estensione
 function verificaFile($nomeFile, $tipo){
 $ext = explode('.', trim($nomeFile));
 $num = count($ext);
 if($ext[$num-1]=='jpg' || $ext[$num-1]=='pdf')
 if($tipo=='put')
 return $this->verifica($nomeFile, $ext[$num-1]);
 elseif($tipo=='get')
 return $this->verificaLocale($nomeFile, $ext[$num-1]);
 }

 //funzione che modifica i caratteri speciali e cambia il nome del file se dovesse già esistere sul server
 function verifica($nomeFile, $ext){
 $nomeFile=stripcslashes($nomeFile);
 $nomeFile=str_replace("'"," ",$nomeFile);
 $nomeFile=str_replace("`"," ",$nomeFile);
 $nomeFile=str_replace("\\"," ",$nomeFile);
 $nomeFile=str_replace("&"," ",$nomeFile);
 $nomeFile=str_replace("%"," ",$nomeFile);
 $nomeFile=str_replace("\""," ",$nomeFile);
 $nomeFile=str_replace("à","a",$nomeFile);
 $nomeFile=str_replace("è","e",$nomeFile);
 $nomeFile=str_replace("é","e",$nomeFile);
 $nomeFile=str_replace("ì","i",$nomeFile);
 $nomeFile=str_replace("ò","o",$nomeFile);
 $nomeFile=str_replace("ù","u",$nomeFile);

 if($this->verificaEsistenza($nomeFile)){
 $temp=substr($nomeFile, 0, -4);
 if($ext=='jpg'){
 $nomeFile=$temp.'_.jpg';
 }
 elseif($ext=='pdf'){
 $nomeFile=$temp.'_.pdf';
 }
 $nomeFile=$this->verifica($nomeFile, $ext);
 }
 return $nomeFile;

 }

 /*
 Verifico che un file esista già sul server a cui mi collego, la funzione ftp_size restituisce la dimensione del file se trova un file con quel nome nella directory indicata, altrimenti restituisce -1
 */
 function verificaEsistenza($file){
 $verifica = ftp_size($this->connect, $file);
 if($verifica==-1)
 return false;
 else
 return true;
 }

 //funzione che modifica i caratteri speciali e cambia il nome del file se dovesse già esistere in locale
 function verificaLocale($nomeFile, $ext){

 if(file_exists($nomeFile)){
 $temp=substr($nomeFile, 0, -4);
 if($ext=='jpg'){
 $nomeFile=$temp.'_.jpg';
 }
 elseif($ext=='pdf'){
 $nomeFile=$temp.'_.pdf';
 }
 $nomeFile=$this->verificaLocale($nomeFile, $ext);
 }
 return $nomeFile;

 }

}
?>

La classe utilizza le funzioni messe a disposizione da PHP per il trasferimento file utilizzando il protocollo FTP; in aggiunta, ho inserito delle funzioni per la verifica che un file si trovi già sul server (verificaEsistenza()) o, se stiamo prelevando dal server, se il file esiste in locale (verificaLocale()). Non utilizzando tali funzioni i file, se già esistenti, vengono sovrascritti senza alcun output per l’utente.
Inoltre, sono state implementate le funzioni verifica() e verificaFile() che hanno il compito di modificare il nome del file evitando i caratteri speciali e le lettere accentate e, se il file si trova già sul server, modificandone il nome inserendo degli underscore dopo il nome e prima dell’estensione. Naturalmente il bisogna conoscere il tipo di file, infatti la classe è impostata per il trasferimento di file immagini (jpg) e pdf. La classe gestisce questi 2 tipi di file ma è possibile adattarla facilmente per tipi di file qualsiasi in base alle necessità.

Gli unici parametri che vanno inseriti all’interno della classe sono i dati per l’accesso FTP al server remoto, tutto il resto verrà effettuato tramite funzioni d’accesso. Il costruttore simpleFtp() ha il compito di effettuare la connessione al server FTP e la relativa login. Seguono le funzioni principali per l’utilizzo della classe, ovvero trasferisci(), preleva() e cancella(). Tutte queste funzioni leggono il percorso del file sul server FTP a partire dalla root, quindi è necessario inserire il percorso completo al file oppure spostarsi, prima di tali operazioni, sulla directory di lavoro con la funzione cambiaDirectory().

Successivamente sono state implementate altre funzioni molto utili in alcuni ambiti, e sono la funzione cambiaPermessiFile() e rinomina(). La prima serve per modificare i permessi d’accesso al file, ad esempio si può impostare un file con i permessi 0777; la seconda serve per rinominare un fle remoto. Ovviamente, per entrambe le funzioni, si verifica prima se il file sul server esista.

La funzione directoryCorrente() restituisce il percorso della cartella del server su cui si sta lavorando mentre le funzioni creaDirectory() ed eliminaDirectory() sono utilizzate, rispettivamente, per creare ed eliminare cartelle sul server FTP; visualizzaFile(), invece, restituisce un array con la lista dei file presenti nella direcotory passata.
Infine, la funzione close() termina la connessione con il server FTP.

Per rendere maggiormente utilizzabile la classe è possibile modificarne il costruttore in modo da prendere dall’esterno i parametri per la connessione. In altri articoli, se ce ne sarà bisogno, integrerò la classe per l’utilizzo di connessioni cifrate per lo scambio di dati in FTP.

Script Php per ricerche fulltext con MySQL

Nel precedente articolo abbiamo visto la sintassi SQL per l’utilizzo degli indici fulltext nelle ricerche sul database. In questo articolo vedremo un semplice script per l’utilizzo pratico di tale ricerca utilizzando una classe appositamente scritta.

Supponiamo di avere un form con un campo di ricerca del tipo:

<form name="cerca" method="post" id="cerca" action="esito_ricerca.php">
<input type="text" name="campo" />
<input type="submit" name="invia" /></form>

Al submit si aprirà una nuova pagina php nella quale riprenderemo i valori passati ed eseguiremo le operazioni necessarie per la ricerca e la visualizzazione dei risultati. Per semplificare le cose utilizzeremo la seguente classe:

< ?php

class Ricerca
{
var $campi;
var $tabella;
var $key;
var $tuple;

function Ricerca($key, $tabella, $campi)
{
$this->key = $key;
if($tabella!="")
$this->tabella = $tabella;
if($campi!="")
$this->campi = $campi;
$this->pulisciStringa();
}

function Query()
{

$query = "SELECT *, MATCH($this->campi) AGAINST('$this->key' IN BOOLEAN MODE) AS attinenza FROM $this->tabella WHERE MATCH($this->campi) AGAINST('$this->key' IN BOOLEAN MODE) ORDER BY attinenza DESC";

$this->tuple = mysql_query($query);

}

function pulisciStringa()
{
$keyMod = strip_tags($this->key);
$keyMod = mysql_real_escape_string($keyMod);
$this->key = trim($keyMod);
}

function ricercaParole()
{
$word = explode(' ', trim($this->key));
$num = count($word);

$i=0;
while($i< $num){
$word[$i] = '+'.$word[$i];
$i++;
}
$this->key = implode(' ',$word);
}

function ricercaFrase()
{
$word = $this->key;
$word = '"'.$word.'"';
$this->key = $word;
}

}

?>

La classe è abbastanza semplice, la funzione Ricerca() ha il compito di inizializzare alcuni parametri necessari per l’esecuzione della ricerca, in particolare riceve in ingresso le chiavi di ricerca, la tabella su cui effettuare la query e i campi fulltext da analizzare.
La funzione Query() effettua la query vera e propria riportando i valori ordinati per attinenza. La funzione pulisciStringa() serve per ripulire il codice e aumentarne la sicurezza. In tale funzione si possono fare tutti i controlli e le sostituzioni di caratteri che si vogliono. Se all’interno del database i caratteri sono codificati nelle loro rispettive entità html (situazione che capita spesso se si usa un editor wysiwyg) allora è possibile utilizzare al posto di mysql_real_escape_string() la funzione htmlentities().
Ho inserito nella classe anche 2 funzioni che possono essere molto utili. La prima è ricercaParole() che ha il compito di inserire davanti a ogni parola il segno “+”. Utilizzare tale parametro equivale a effettuare una ricerca di “tutte le parole” passate, ovvero tra i risultati ci saranno soltanto tuple che contengono tutte le parole di ricerca passate. La seconda è, invece, ricercaFrase() che ha il compito di restituire tra i risultati solamente tuple che contengono la chiave di ricerca così com’è. E’ utile per ricercare una “frase esatta” all’interno dei campi e si attua inserendo la chiave di ricerca all’interno di doppi apici.

Vediamo come utilizzare la classe in una ricerca utilizzando il form precedente. Supponiamo che la connessione al database sia già stata effettuata, avremo:

$campo=$_POST['campo'];

$search = new Ricerca($campo, 'tabella', 'campo1, campo2');
$search->Query();
$cont = mysql_num_rows($search->tuple);

if($cont<1)
echo "Non vi sono risultati per la ricerca selezionata";
else{
while ($row = mysql_fetch_array($search->tuple))
{
echo $row['campo1'];
}
}

Si riprende il campo e si inizializza la classe attraverso il costruttore passandogli la chiave di ricerca, la tabella e i campi da analizzare. Successivamente effettuiamo la query e procediamo alla visualizzazione dei risultati.

Per avere tra i risultati della ricerca solo i risultati che contengono tutte le parole passate inseriamo prima della Query() la funzione ricercaParole():

$search = new Ricerca($campo, 'tabella', 'campo1, campo2');
$search->ricercaParole();
$search->Query();

mentre per ricercare una frase esatta:

$search = new Ricerca($campo, 'tabella', 'campo1, campo2');
$search->ricercaFrase();
$search->Query();

La classe vista finora è molto semplice e funzionale, può essere ampliata a piacimento per implementare funzioni che possono essere d’aiuto nel personalizzarla a seconda dei propri scopi.

Motore di ricerca per MySQL con indici fulltext

In questo articolo vedremo come creare un semplice motore di ricerca in php utilizzando gli indici fulltext di MySQL. Gli indici fulltext sono un meccanismo che consente di velocizzare le ricerche le quali risultano così molto più efficienti rispetto l’utilizzo del comando LIKE. Inoltre, con questo meccanismo, i risultati saranno visualizzati in ordine di attinenza con le chiavi di ricerca.
Affinché si possano utilizzare le ricerche fulltext bisogna prima preparare il database e, successivamente, il codice per effettuare le ricerche.

Preparazione del database
Condizione necessaria per l’utilizzo di questo tipo di ricerche è l’impostazione dei campi con indice fulltext. Tale impostazione può essere effettuata al momento della creazione della tabella o successivamente. Vediamo degli esempi.
Per impostare i campi fulltext alla creazione della tabella basta inserire nella query SQL la stringa FULLTEXT (campo1, campo2), dove i campi possono essere 1, 2 o più e sono separati da virgole. Es:

CREATE TABLE tabella(
id INT AUTOINCREMENT NOT NULL PRIMARY KEY
campo1 VARCHAR(255),
campo2 TEXT,
FULLTEXT (campo1, campo2)
);

Per inserire gli indici in una tabella già esistente basta invece utilizzare la sintassi:

ALTER TABLE tabella ADD FULLTEXT(campo1,campo2);

Se non avete voglia di scrivere la query a mano potete anche utilizzare l’interfaccia di phpmyadmin per impostare i campi: selezionate la tabella su cui aggiungere i campi, selezionate “struttura” e nella riga del campo da impostare troverete come ultima opzione una casellina che dice FULLTEXT (testo completo).

Nota: affinché si possano utilizzare gli indici fulltext è necessario che la tabella utilizzi l’engine MyISAM e che i campi siano campi di testo (VARCHAR, TEXT…..).

Sintassi per le ricerche
Il cuore delle ricerche fulltext è rappresentato dai comandi MATCH(….) e AGAINST(….) nei quali vanno inseriti rispettivamente il nome dei campi da analizzare e le chiavi di ricerca. Un esempio pratico è il seguente:

SELECT *
FROM tabella
WHERE MATCH(campo1, campo2) AGAINST(‘key’);

Vi saranno risultati solo se vi sarà un valore di attinenza con la chiave di ricerca. MATCH e AGAINST producono un valore di attinenza in virgola mobile, se tale valore è zero non vi saranno risultati. La query così formata però ha il difetto di non riportare i risultati ordinati per attinenza. Quella che segue è una query più completa e funzionale.

SELECT *, MATCH(campo1, campo2) AGAINST(‘key’, IN BOOLEAN MODE) AS attinenza
FROM tabella
WHERE MATCH(campo1, campo2) AGAINST(‘key’, IN BOOLEAN MODE)
ORDER BY attinenza DESC;

Tale query restituisce i risultati ordinati per attinenza per come viene calcolata dai comandi MATCH e AGAINST. Nella clausola AGAINST viene utilizzato altresì la dicitura IN BOOLEAN MODE, che permette di utilizzare operatori booleani per personalizzare e migliorare le ricerche.

Operatori di ricerca
Oltre ai normali operatori AND e OR logici, nelle ricerche fulltest possono essere inseriti altri tipi di operatori per meglio filtrare i risultati, tra cui:

  • Operatore +: indica che la parola a cui è anteposto deve essere presente in ogni record restituito;
  • Operatore -: indica che la parola a cui è anteposto non deve essere presente in alcun record restituito;
  • Operatori < e >: sono utilizzati per variare il contributo che la parola dona alla rilevanza (score) di un singolo record;
  • Operatori (): le parentesi sono utili al fine di raggruppare tra loro sotto-espressioni che avranno un più alto grado di precedenza;
  • Operatore ~: viene utilizzato per segnare una parola in modo che questa diminuisca l’attinenza di un record (viene utilizzato per marcare le cosidette bad words);
  • Operatore *:  è l’unico operatore che può essere posto alla fine della parola o di una parte di essa. Serve ad indicare che caratteri qualsiasi possono seguire la parola o precederla;
  • Operatore “: le parole o frasi racchiuse tra apici doppi obbligheranno MySQL ad effettuare ricerche sulla frase completa e non su ogni singola parola.

Nel prossimo articolo vedremo come usare praticamente le ricerche fulltext con php utilizzando una semplice classe.

Prelevare codice video youtube da URL o da codice incorporato con object o iframe

Mi è capitato spesso, nell’ultimo periodo, di dover inserire dei video youtube in siti web che richiedevano però modifiche del player, in particolare della sua dimensione. Per semplificare le cose ho scelto di incorporare nelle pagine uno stesso codice già personalizzato e passare a tale codice l’id del video scelto dal cliente.
Visto che ogni cliente ha un pensiero a sé stante, ho dovuto personalizzare il tutto in base alla scelta dell’utente di inserire l’URL del video, il vecchio codice di incorporamento o il nuovo codice utilizzato da youtube con il tag <iframe>. Per chi non lo sapesse, youtube ha da poco modificato il tipo di codice da incorporare con un codice che utilizza <iframe>; tale soluzione permette all’utente finale di visualizzare il video con tecnologia flash oppure HTML5 ed è particolarmente indicato per la visualizzazione dei video su dispositivi mobile. Tuttavia, il vecchio codice (tag <object>) è ancora disponibile su richiesta spuntando la voce “Utilizza vecchio codice di incorporamento” posto poco sotto il codice da incorporare.

Ho implementato una piccola funzione per l’estrazione dell’id del video in tutti e tre i casi. La riporto di seguito.

<?php
function estraiCodice($codice){
$codMod = $codice;
$tipo='';
$idVideo='';

//Verifico il tipo di codice
if(strstr($codMod, 'iframe'))
$tipo='iframe';
elseif(strstr($codMod, 'object'))
$tipo='object';
elseif(strstr($codMod, 'watch?v='))
$tipo='link';

//Operazioni nel caso di codice tradizionale con object
if($tipo=='object'){
$part = explode('?', $codice);
$cod = explode('.com/v/',$part[0]);
$idVideo = $cod[1];
}
//Operazioni nel caso di nuovo codice con iframe
elseif($tipo=='iframe'){
$part = explode('embed/', $codice);
$cod = explode('"',$part[1]);
$idVideo = $cod[0];
}
//Operazioni nel caso di inserimento di URL
elseif($tipo=='link'){
$part = explode('?v=', $codice);
if(strstr($part[1], '&')){
$cod = explode('&',$part[1]);
$idVideo = $cod[0];
}else{
$idVideo=$part[1];
}
}

return $idVideo;
}
?>

Il codice è molto semplice. Per prima cosa verifico il tipo di incorporamento che è stato inserito e, successivamente, effettuo le operazioni necessarie per estrarre l’id, che è il risultato che voglio ottenere.

Invio di newsletter in PHP e gestione dello spam

In questi giorni mi sono trovato a risolvere un problema non di poco conto: le mail inviate come newsletter da alcuni siti vengono viste dai riceventi come spam. Ciò era dovuto, nella maggior parte dei casi, alla mancanza di alcuni header nelle impostazioni della mail. Purtroppo non tutti i problemi si sono risolti; infatti, su yahoo e, soprattutto, hotmail le mail venivano viste ancora come posta indesiderata, mentre l’invio su account come gmail, libero e alice non davano alcun problema. Ma procediamo con ordine e analizziamo il codice per l’invio delle mail.

Utilizziamo la classe PHPMailer per gestire in modo estremamente semplice l’invio delle mail. Per utilizzarla scarichiamo il pacchetto e inseriamo all’interno del nostro codice il file class.phpmailer.php:

require_once("include/class.phpmailer.php");

dopodiché si procede con l’inserimento delle varie opzioni:

$mail = new PHPMailer();
$mail->IsSMTP();                    // attiva l'invio tramiteSMTP
$mail->Host     = "vostro.server.smtp"; // indirizzo smtp
$mail->From     = "vostra@mail.com";
$mail->FromName = "Vostro nome";
$mail->AddReplyTo('vostra-mail@reply.com');
$mail->Sender = "vostra@mail.com";
$mail->AddAddress(mail@destinatario.com);
$mail->IsHTML(true);
$mail->Subject  =  "Oggetto della mail";
$mail->Body     =  "Corpo della mail";
if(!$mail->Send()){
echo "Si è verificato un errore nell'invio della mail";
}

Il codice è molto semplice, si istanzia un oggetto della classe in questione e abilitiamo l’invio tramite SMTP attraverso il metodo IsSMTP(). Si inseriscono i propri dati per completare le intestazioni e l’indirizzo del destinatario della mail; con il metodo IsHTML(true) impostiamo l’invio della mail come text/html così da poter inserire i tag html per gestire il formato della mail (ovviamente se è una mail di solo testo si può omettere, anzi è consigliabile come vedremo dopo). Dopo aver inserito l’oggetto e il corpo si effettua l’invio tramite il metodo Send().

Sulla classe PHPMailer ci sono da dire altre 2 cose importanti: tramite di essa si posso inviare email anche tramite server SMTP che richiedono l’autenticazione inserendo i seguenti parametri:

$mail->Username =  "username del server SMTP"; //di solito la mail utilizzata
$mail->Password = 'password'; //di solito la password della mail
$mail->SMTPAuth = true;

oppure inserire degli allegati attraverso il parametro:

$mail->AddAttachment("filename_1.zip");

Anche se in maniera breve, abbiamo fatto una panoramica abbastanza esauriente sull’utilizzo della classe PHPMailer. Con le impostazioni viste sono riuscito a non avere molti problemi con i vari gestori di account di posta che analizzano principalmente le intestazioni con i loro filtri antispam. Purtroppo è il livello del filtro che fa si che la nostra email sia considerata come spam oppure no. Di solito vi è un indice numerico che stabilisce un livello massimo di tolleranza e ogni “imprecisione” o “problema” rilevato sui vari parametri della mail (intestazione, oggetto, corpo…) incide per un valore in base alla gravità. Se la somma di tali valori supera il livello massimo di tolleranza l’email verrà vista come spam.

Se la vostra mail è puro testo non ci dovrebbero essere molti problemi avendo tutte le impostazioni apposto, al contrario, invece, se la mail contiene codice html, i filtri antispam sono molto più restrittivi soprattutto in presenza di immagini. Per cercare di non incorrere in penalizzazioni bisogna inserire un codice html il più possibile pulito e accessibile. Bisogna inserire tutti i tag in ordine con la relativa chiusura secondo la struttura

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Title della mail</title>
</head>

<body>
<!-- Corpo della mail -->
</body>
</html>

All’interno del body possiamo inserire tutti i tag che ci servono per formattare come meglio crediamo la mail (<p>, <table> ecc..) ricordandoci 3 importanti accorgimenti:

  1. se inseriamo immagini inseriamo SEMPRE gli attributi alt e title;
  2. l’attributo title va inserito anche nei link inseriti attraverso il tag <a>;
  3. se inseriamo immagini e/o molti tag html dobbiamo inserire anche abbastanza testo; da prove da me effettuate  una mail con anche solo un’immagine all’interno e poco testo viene penalizzata, mentre se il testo è abbastanza passa più facilmente senza penalizzazioni.

Rispettando queste semplici regole sono riuscito a far pervenire, anche a utenti hotmail, la mail senza che il filtro antispam la taggasse come spam. Naturalmente in molti account è possibile personalizzare la sensibilità del filtro che potrebbe dare problemi anche con accorgimenti più accurati.

L’ultimo argomento dell’articolo riguarda l’analisi di una mail taggata come spam se l’accout ci fornisce le informazioni sulle penalizzazioni effettuate dal filtro antispam. Alcuni account (come gli account  email creati su aruba, ad esempio) ci forniscono tali informazioni. Vediamo un esempio pratico di una mail taggata come spam:


Content analysis details:   (5.2 points, 5.0 required)
pts rule name              description
---- ---------------------- ------------------------------
--------------------
-0.0 NO_RELAYS              Informational: message was not relayed via  SMTP
0.0 HTML_MESSAGE           BODY: HTML included in message
1.7 MIME_HTML_ONLY         BODY: Message only has text/html MIME parts
2.5 HTML_IMAGE_ONLY_16     BODY: HTML: images with 1200-1600 bytes of  words
1.1 HTML_MIME_NO_HTML_TAG  HTML-only message, but there is no HTML tag
-0.0 NO_RECEIVED            Informational: message has no Received  headers
Questa situazione ci informa che il filtro è impostato su una sensibilità massima pari a 5.0 (5.0 required) ma l’email ha riportato un punteggio di 5.2 (5.2 points). Dall’analisi si evince che la mail era stata impostata im maniera errata, dove mancavano i tag più importanti come il tag <html> (“1.1 HTML_MIME_NO_HTML_TAG  HTML-only message, but there is no HTML tag”), era formata in gran parte da codice html con poco testo (“1.7 MIME_HTML_ONLY BODY: Message only has text/html MIME parts”) e il testo era insufficiente anche rispetto alle immagini inserite (2.5 HTML_IMAGE_ONLY_16 BODY: HTML: images with 1200-1600 bytes of words). Per informazioni più dettagliate sui vari tipi di errore si veda il seguente link aggiornato alla versione 3.3 che è quella più aggiornata al momento della scrittura dell’articolo.

Validare campi di input con php e le espressioni regolari

Molto spesso ci si trova a dover lavorare su campi di input e controllarne l’esattezza. In questo articolo vedremo come validare, tramite le espressioni regolari, tre tipi di dato che spesso si trovano nei form delle pagine html, ovvero l’email, il codice fiscale e la partita IVA. Il controllo che viene effettuato non controlla che essi siano corrispondenti a verità, ad esempio, non verifica che l’email esista, ma solo che è scritta nel formato corretto.

Per prima cosa impostiamo l’espressione per il controllo sotto forma di funzione:

 function controlla($stringa)  {
  $pattern="...."; //vedremo tra poco cosa inserire
  if(preg_match($pattern, trim($stringa)))
    return true;
  else
    return false;
}

Come si può notare la funzione è di tipo booleano, restituisce true se la stringa è conforme a un modello predefinito (pattern) altrimenti restituisce false. Quello che inseriremo nella variabile $pattern dipenderà dal tipo di controllo che vogliamo effettuare. Per effettuare il controllo sull’indirizzo email la variabile dovrà essere del tipo:

$pattern="^([a-z0-9_\.-])+@(([a-z0-9_-])+\\.)+[a-z]{2,6}$";

per il codice fiscale il pattern sarà:

$pattern="^[a-zA-Z]{6}[0-9]{2}[a-zA-Z][0-9]{2}[a-zA-Z][0-9]{3}[a-zA-Z]$";

mentre, infine, per validare una partita IVA il pattern sarà:

$pattern="^[0-9]{11}$";

Per effettuare il controllo basterà una semplice condizione:

if(controlla($dato)){
echo "email/cf/piva corretti";
else
echo "Ricontrolla i dati";

Visualizzare località in Google Maps da coordinate inserite in un database

Posto questo articolo per un problema che mi ha fatto dannare per qualche sera. Avevo degli indirizzi in un database da convertire tramite geocoding in coordinate e quindi visualizzarli in google maps. Problema: non riuscivo ad avere un comportamento coerente delle visualizzazioni a ogni caricamento della pagina… Perciò ho cambiato il codice inserendo nel DB non solo l’indirizzo ma direttamente le coordinate. Lo script proposto avrà una parte php per l’inserimento delle coordinate nel DB e una parte javascript per la visualizzazione della mappa.

Per prima cosa vediamo come fare l’inserimento di un indirizzo nel DB utilizzando la classe geocoder5 che ho trovato al questo indirizzo.  Supponiamo di aver inserito i valori che ci interessano (via, cap, città, proviancia ed, eventualmente, nazione) in un form e di riprenderli in un file che li elabora.

require("geocoder5.class.php");

//inseriamo la nostra apiKey
$gmpKey = "tua apiKey";
$data = array();

//la variabile sede contiene tutti i campi sopra citati
array_push($data, addslashes($sede));
$test = & new geocodeaddr($data,$gmpKey); //istanzio il nuovo oggetto
$geocodeResults = $test->getAddress(); //richiamo la funzione
$a=0;

//controllo che l'indirizzo sia stato trovato altrimenti visualizzo l'errore
$controlla=$test->errorMsg1;
if ($controlla=='')
foreach ($geocodeResults as $rowResult){

//prendo i valori solo alla prima iterazione
if($a==0){
$query="INSERT INTO mappa (sede, latitudine, longitudine) VALUES( '$sede', '".$rowResult['lat']."', '".$rowResult['lng']."');";
mysql_query($query) or die(mysql_error());
}

$a++;
}
else
echo $test->errorMsg1;
} ?>

Il codice fin qua è molto semplice, stiamo solamente utilizzando la classe per tradurre l’indirizzo (che ricordo deve essere possibilmente nella forma via, cap, città, proviancia ed, eventualmente, nazione) in coordinate geografiche e inseriamo tali dati in una tabella del DB. Inoltre vi è la possibilità di gestire l’eventuale errore (indirizzo non trovato) personalizzandolo a vostro piacimento .

Passiamo adesso alla visualizzazione della mappa. Per prima cosa bisogna recuperare i dati dal database e inserirli in un vettore; avremo tre vettori: uno per l’indirizzo (lo useremo come descrizione nella nuvoletta che compare cliccando sopra un punto ben preciso), uno per la latitudine e uno per la longitudine. Salto questa parte che è abbastanza semplice e passiamo al resto del codice.

<script src="http://maps.google.com/maps?file=api&amp;dev=2&amp;hl=it&amp;key="<span style="color: #888888;">tuaKey" type="text/javascript"></script>
<script type="text/javascript">
//< ![CDATA[</code>

var map = null;

<span style="color: #ccffcc;"><span style="color: #333399;">function load()</span> </span>{
if (GBrowserIsCompatible()) {

map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());   /* pannellino in alto a sx x ingrandire o diminuire lo zoom */
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(41.90, 12.49), 5);  /* centro la mappa sull'italia */
geocoder = new GClientGeocoder();    /* oggetto che mi consente di comunicare col server gg x ottenere lat e log degli indirizzi*/

}
}//load

<span style="color: #333399;">function createMaker</span>(infos, lat, lon){

var point;
point = new GLatLng(lat,lon); //creo il punto
map.addOverlay(createMarker(point, infos)); //aggiunge il punto alla mappa

}

<span style="color: #333399;">function createMarker</span>(point, infos)
{
var icona = new GIcon();
icona.image = "img/marker.png"; //scelgo il puntatore
icona.iconSize = new GSize(12, 20);
icona.iconAnchor = new GPoint(6, 20);
icona.infoWindowAnchor = new GPoint(6, 20);
icona.shadowSize = new GSize(24, 20);

// Variabile marker
var marker = new GMarker(point, icona);

// Crea listener per il click sull'oggetto
GEvent.addListener(marker, "click", function()
{
marker.openInfoWindowHtml(infos);
});

return marker;
}

<span style="color: #333399;">function showAll()</span>{

var infos=Array(
< ?php
$b=0;
while($b<(count($x)-1)){
echo "$indirizzi[$b]";
if($b!=(count($indirizzi)-2)) echo ",";
$b++;
}//while1
?>
);

var latitudine=Array(
< ?php
$c=0;
while($c<(count($latitudine)-1)){
echo "$latitudine[$c]";
if($c!=(count($latitudine)-2)) echo ",";
$c++;
}//while2
?>
);

var longitudine=Array(
< ?php
$d=0;
while($d<(count($longitudine)-1)){
echo "$longitudine[$d]";
if($d!=(count($longitudine)-2)) echo ",";
$d++;
}//while3
?>
);

for(var i=0; i<indirizzi .length; i++) createMaker(infos[i], latitudine[i], longitudine[i]);

}//showAll
//]]>
</indirizzi></script>

La funzione load() ha il compito di istanziare un oggetto del tipo GMap2 che è quello che ci permette di comunicare con il server di google per ottenere i servizi necessari al nostro scopo. Successivamente verrà richiamata la funzione showAll() che ha il compito di trasformare gli array php in array javascript per passarli alla funzione createMaker. Quest’ultima funzione verrà richiamata più volte per quante sono le località da visualizzare nella mappa.

La funzione createMaker deve creare, per ogni coppia di coordinate geografiche, un punto per la mappa che verrà aggiunto dalla funzione addOverlay della classe GMap2 . Tale funzione accetta in ingresso, però, un oggetto di tipo GMarker e, per ottenere tale oggetto, richiamiamo la funzione createMarker. All’interno di tale funzione possiamo definire l’icona (un’immagine a nostra scelta) da utilizzare e le sue proprietà, ma lo scopo principale è quello di creare il marker passandogli il punto e le informazioni da visualizzare nella relativa nuvoletta. Nell’esempio riportato la nuvoletta delle informazioni viene visualizzata al click del mouse sull’icona ed è gestita da GEvent.addListener.

Supponiamo di inserire il codice appena visto in un file chiamato mappa.php, per terminare il nostro script non ci resta che richiamare le funzioni al caricamento della pagina:

<body onLoad="load(); showAll();" onUnload="GUnload()">

Se volessimo integrare la mappa in una nostra pagina web a parte basta inserire il codice:

<iframe align="middle" width="430" height="450" frameborder="0" src="mappa.php">

nel punto della pagina in cui vogliamo visualizzare la mappa e il gioco è fatto.

SHORT – Effettuare un redirect 301 tramite .htaccess (mod_rewrite) o PHP

Capita spesso di dover modificare l’indirizzo di una pagina web, ad esempio, nei cambi di dominio per reindirizzare al nuovo dominio; proprio in questi casi abbiamo bisogno di indicare che lo spostamento di indirizzo è permanente, così che anche i motori di ricerca modifichino il loro database. Il metodo migliore per effettuare tale operazione è il cosiddetto redirect 301. Il redirect 301 può essere implementato in diverse maniere in base al linguaggio, noi ne vedremo solo 2.

Una prima soluzione è quella di utilizzare la funzione header() di php nel seguente modo:

<?
header( “HTTP/1.1 301 Moved Permanently” );
header( “Location: http://www.nuovo-indirizzo.com” );
?>

Se però il web server utilizzato è Apache con il modulo mod_rewrite attivo allora la soluzione ottimale è senza dubbio utilizzare un file .htaccess configurato nel seguente modo:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^tuodominio.it [NC]
RewriteRule ^(.*)$ http://www.tuodominio.it/$1 [L,R=301]
Redirect permanent /vecchia-pagina.php http://www.nuovo-link.it
</IfModule>

Questo codice non fa altro che impostare su tuodominio.it un rewrite 301 dalla pagina /vecchia-pagina.php (che può essere l’index se si vuole reindirizzare l’url principale) alla pagina http://www.nuovo-link.it (in questo caso ci va tutto l’url).


Controllo di dati inseriti da form html

Il controllo dei dati inseriti dall’utente può essere effettuato sia lato client attraverso javascript (al submit dell’utente) o lato server.  In questo articolo vedremo come effettuare un controllo molto semplice sui dati attraverso PHP.

Supponiamo di avere un form di questo tipo:

<?php

if(isset($_SESSION['errore'])){

echo $_SESSION['errore'];

unset($_SESSION['errore']);

}

?>

<form name="mioForm" action="inoltra.php" method="post" >

<table width="420" border="0" cellspacing="2" cellpadding="2" >

<tr>

<td><label for="nome">Nome*</label></td>

<td><input type="text" name="nome" id="nome" size="20" maxlength="40" value="<?php

if(isset($_SESSION['nome'])){

echo $_SESSION['nome'];

unset($_SESSION['nome']);

}

?>"/></td>

</tr>

<tr>

<td><label for="password">Password*</label></td>

<td><input type="password" name="password" id="password" size="20" maxlength="40" value="<?php

if(isset($_SESSION['password'])){

echo $_SESSION['password'];

unset($_SESSION['password']);

}

?>"/></td>

</tr><input type="submit" value="Invia" />

</form>

Per adesso commentiamo solo il fatto che il form è composto da 2 campi: nome e password. I dati verranno passati alla pagina inoltra.php tramite il metodo POST;  tale pagina effettueremo il controllo, vediamo una parte di codice:

<?php session_start();

if (isset($_POST['nome']) && $_POST['nome']!=""){

$_SESSION['nome']=(string)$_POST['nome'];

$nome=$_SESSION['nome'];

}else{

$_SESSION['errore']='<p><strong>ERRORE: completare il campo "Nome"</strong></p>';

//ricavo l'URL della pagina di provenienza

$url = $_SERVER['HTTP_REFERER'];

//effettuo il reindirizzamento

header("Location: $url");

break;

}

if (isset($_POST['password']) && strlen($_POST['password'])<4){

$_SESSION['password']=(string)$_POST['password'];

$password=$_SESSION['password'];

}else{

$_SESSION['errore']='<p><strong>ERRORE:  il campo "Password" deve essere di almeno 4 caratteri</strong></p>';

$url = $_SERVER['HTTP_REFERER'];

header("Location: $url");

break;

} ?>

Il codice è molto semplice. Con un if controlliamo che il dato passato sia settato e non sia un campo vuoto, se la condizione è verificata allora inserisco il valore del dato passato sia in una variabile si sessione che in una variabile locale (è una scelta soggettiva, io preferisco usare le variabili di sessione solo tra pagine e poi utilizzare variabili locali per tutti gli altri scopi); il controllo su una variabile vuota si può anche fare tramite la funzione empty(). Per quanto riguarda il campo password ho effettuato il controllo sulla lunghezza della stessa che deve, in questo caso, essere formata da almeno 4 caratteri.

Se almeno un controllo non va a buon fine si inizializza un’altra variabile di sessione riportante l’errore riscontrato, si richiama l’indirizzo della pagina di provenienza (molto utile se il form è inserito in più di una url), si fa il redirect alla pagina suddetta e infine si blocca l’esecuzione dello script. Senza l’istruzione break verrà fatto il reindirizzamento dopo che lo script sarà eseguito completamente, quindi verranno eseguite eventuali query o altre operazioni su dati incompleti o mancanti.

Ritorniamo alla pagina contenente il form. Se è la prima volta che si arriva al form il codice php non contribuirà a dare nessun risultato perché le variabili di sessione non sono ancora state inizializzate. Nel caso in cui il form sia già stato compilato ma in maniera incompleta, la prima operazione php è la visualizzazione dell’errore riscontrato prima del form così da avvisare l’utente dell’errore. Successivamente le sessioni vengono utilizzate per immettere nei campi i valori precedentemente immessi, velocizzando quindi, in caso di errore, la compilazione dei campi da parte dell’utente. Alla fine di ogni operazione viene de-allocata la variabile di sessione per evitare che essa sia visualizzabile ogni volta all’arrivo del form dello stesso utente.

Naturalmente il controllo visto ora è un controllo minimale che tende solo a verificare che l’utente abbia inserito dei dati e che essi rispettino una certa lunghezza; controlli più estesi si potrebbero fare sul contenuto del campo attraverso le espressioni regolari. In un altro articolo vedremo come usare le espressioni regolari e come modificare il contenuto dei dati sia per motivi di sicurezza che per evitare errori nell’utilizzo del database.