Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

URL dinamici graditi ai motori

Come modificare gli URL per renderli graditi ai motori di ricerca
Come modificare gli URL per renderli graditi ai motori di ricerca
Link copiato negli appunti

Introduzione

È noto come in genere i motori di ricerca non indicizzino in modo soddisfacente le pagine che presentano URL con questo formato: http://www.dominio.com?var1=valore1&var2=valore2

La parte, per così dire, "indigesta" è quella che segue il "?", ovvero la QUERY_STRING, la stringa attraverso la quale si passano ad uno script lato-server informazioni che esso utilizzerà durante l?elaborazione. Gli spiders seguendo i collegamenti a pagine generate dinamicamente, cioè links ai quali non sempre corrisponde un file esistente fisicamente sul server, temono di ritrovarsi troppo spesso dinanzi ad un vicolo cieco o, peggio, cadere in un circolo vizioso: pertanto tendono ad ignorare la parte dell?URL successiva al punto di domanda.

A dire il vero, data la grande diffusione delle pagine dinamiche, oggi alcuni motori di ricerca (Google per tutti) si spingono timidamente oltre e arrivano a considerare anche parte della QUERY_STRING. Tuttavia, inevitabilmente, l?indicizzazione rimarrà poco precisa.

Il problema quindi permane e ad esso gli sviluppatori hanno tentato di ovviare con diverse soluzioni più o meno complicate da mettere in pratica. Il denominatore comune di questi stratagemmi si può ricondurre ad un?opera di "cosmesi" sugli URL che porta a dare loro l?aspetto di una comune pagina statica.

Alla fine di questo articolo troverete i riferimenti a due interessanti interventi pubblicati su www.alistapart.com nei quali vengono illustrati altrettanti metodi di url-rewriting, però lo scopo di questo tutorial è quello di descrivere una terza modalità di camuffamento degli URL, forse meno fine delle precedenti, certamente molto più semplice da mettere in pratica: non richiede alcun tipo di modifica alle impostazioni del server, nè l'utilizzo di un database come nella soluzione di Till Quack.

Anche questo metodo presuppone che i nostri script girino con Apache (non mi risulta che la cosa sia riproducibile con IIS di Microsoft), infatti il trucco sta proprio nello sfruttare una caratteristica del webserver più diffuso in rete.

Dinanzi alla richiesta di una pagina con il seguente URL,

http://www.dominio.com/pagina.php/var1=valore1/var2=valore2 ,

(che agli occhi dei motori appare come il collegamento ad una normalissima pagina statica) Apache riconosce che "pagina.php" è uno script e lo eseguirà normalmente ignorando la parte successiva allo slash ("/").

Tale stringa sarà comunque presente in quanto contenuta nella variabile d?ambiente PATH_INFO, ben nota agli sviluppatori che hanno confidenza con la programmazione CGI.

Nell?esempio precedente la variabile PATH_INFO contiene la stringa "/var1=valore1/var2=valore2", ma si è trattato di una nostra scelta, perché avremmo potuto dare all?indirizzo un qualsiasi altro formato, ad esempio

http://www.dominio.com/pagina.php/var1-valore1-var2-valore2.html

oppure

http://www.dominio.com/pagina.php/var1/valore1/var2/valore2.

La cosa importante è che dei links con questi valori non vengano riconosciuti dagli spiders come collegamenti a pagine dinamiche, e che grazie ad Apache lo script possa accedere ai dati che gli vengono passati nell?URL.

Come utilizzare PATH_INFO

A questo punto la QUERY_STRING, tanto invisa ai motori di ricerca, presenta comunque un vantaggio: in PHP i dati che si trovano dopo il "?" sono facilmente accessibili senza particolari operazioni di scomposizione della stringa: sarà infatti sufficiente richiamare il nome della variabile in questo modo $_GET["nomevariabile"] per averne a disposizione il valore.

Se fosse possibile ottenere un risultato simile con PATH_INFO saremmo a cavallo!

Attraverso la manipolazione della stringa contenuta in $_SERVER["PATH_INFO"], riusciremo ad ottenere la stessa facilità di accesso alle variabili, senza dover rinunciare ad una buona indicizzazione delle nostre pagine da parte dei motori di ricerca.

Ipotizzando che l?URL della pagina dinamica sia il seguente http://www.dominio.com/pagina.php/nome=Mario/cognome=Rossi

$_SERVER["PATH_INFO"] conterrà "/nome=Mario/cognome=Rossi"

<?php

$separators=array("/","=") ;

$collection=$_SERVER["PATH_INFO"] ;

/*
Togliamo il primo slash da PATH_INFO
*/

$collection=substr($collection,1) ;

/*

Nel caso in cui l'ultima variabile resti vuota e si abbia una PATH_INFO di questo tipo,

pagina.php/var1=val1/var2=val2/var3=/, l'ultimo separatore crea errori quindi va tolto

*/

if(substr($collection,-1)==$separators[0]){

$collection=substr($collection,0,-1) ;

}

/*

Riduciamo i separatori nell'URL ad uno soltanto (gli "=" erano stati utilizzati solo per somiglianza con i normali URL dinamici (pagina.php?var=val): poi utilizzeremo un explode() per separare le variabili

*/

$collection = str_replace($separators[1], $separators[0], $collection);

/*

Ecco l'explode

*/

$varArray=explode($separators[0],$collection) ;

?>

Originariamente anzichè explode() avevo utilizzato la comoda strtok(), purtroppo però questa funzione presentava un bug che è stato corretto soltanto di recente, quindi ho preferito farne a meno definitivamente per questioni di retrocompatibilità.

Le poche righe di codice appena viste consentono di separare la stringa specificando "/" come marcatore: i vari "pezzi" saranno raccolti nell?array $var.


$varArray sarà strutturato così

Array (

[0] => nome

[1] => Mario

[2] => cognome

[3] => Rossi

)

Il nostro scopo però è quello di rendere accessibili i valori delle variabili in modo simile a quanto accade quando esse vengono passate attraverso QUERY_STRING, cioè con il loro nome.

Conseguentemente lo script richiede alcune modifiche:

<?php

/*

in questo punto va inserito il codice presentato fino ad ora

*/

$_PINFO=array() ;

foreach ($varArray as $key=>$value){

if(!($key%2)){

$_PINFO["$value"]=$varArray[$key+1] ;

}

}//END FOREACH

?>

Questo codice non fa altro che dichiarare un nuovo array (che qui abbiamo chiamato $_PINFO per fornire un aspetto che ricordi l?array $_GET) il quale avrà la seguente struttura

Array (

[nome] => Mario

[cognome] => Rossi

)

La condizione all?interno di if(), attraverso l?operatore modulo "%", verifica che a $_PINFO[$var[0]] venga assegnato il valore di $var[1], e a $_PINFO[$var[2]] quello di $var[3] , e così via...

Ora potremo accedere al valore "Mario" attraverso la variabile $_PINFO["nome"] e al valore "Rossi" con $_PINFO["cognome"], esattamente come accadrebbe con $_GET e la QUERY_STRING.

Come nota a margine è interessante precisare che PATH_INFO e QUERY_STRING non sono incompatibili tra loro, infatti un URL di questo tipo sarebbe perfettamente ammissibile

http://www.dominio.com/pagina.php/nome=Mario/cognome=Rossi?id=5&id2=12

Preparare al meglio le nostre pagine

Il primo passo ovvio è quello di sostituire nei link la QUERY_STRING con PATH_INFO

Ad esempio

<a href="http://www.domain.com/dir/mypag.php?var1=val1&var2=val2">CLICCAMI</a>

potrà trasformarsi in

<a href="http://www.domain.com/dir/mypag.php/var1=val1/var2=val2">CLICCAMI</a>

"&" è stato sostituito con "/", mentre "=" è rimasto intatto per ragioni di chiarezza, ma la scelta sui separatori da utilizzare è assolutamente libera.

Un' altra trasformazione importante è quella che riguarda i percorsi fino ai file: il nostro trucchetto funziona così bene che non inganna soltanto gli spider ma persino il browser...tanto da interferire nel modo in cui ricostruisce i path dei link relativi (la cosa comporta una serie di errori che non sto a descrivere).

La soluzione è utilizzare percorsi completi, quindi nel nostro esempio l'attributo href dei link relativi dovrà cambiare da così

<a href="mypag.php?var1=valore1">CLICCAMI</a>

a così

<a href="/directory/mypag.php/var1=valore1">CLICCAMI</a>

Prima di "/directory/" c'è soltanto il nome dell' Host (www.domain.com).

Ho parlato di percorsi "completi" anzichè "assoluti" perchè non è necessario l'intero "http://www.domain.com/directory/mypag.php/var1=valore1" per fare contento il browser.

La modifica in questione è obbligatoria anche per l'attributo src delle immagini (l'action dei form etc.etc.) ed è necessaria anche se l'url non contiene PATH_INFO, perchè comunque il browser li tradurrebbe in modo errato.

Dal mio punto di vista il fastidio di modificare i percorsi viene controbilanciato dalla maggiore trasportabilità delle pagine da un dominio all'altro.

È anche possibile creare automaticamente il percorso completo come nell'esempio che segue:

<?php

/*
Definiamo la costante MYROOT

*/

define('MYROOT',dirname($_SERVER["SCRIPT_NAME"])) ;

/*

Completiamo un link che contiene anche PATH_INFO

*/

$href1=MYROOT.'/mypag.php/var1=valore1';

/*

Completiamo un tag SRC che, ovviamente, non presenta PATH_INFO

*/

$src1=MYROOT.'/immagine1.jpg' ;

?>

<a href="<?php echo($href1) ?>">CLICCAMI</a><br />

<img id="im1" src="<?php echo($src1) ?>" />

Non c'è molto altro da dire, lo script completo (che troverete alla pagina successiva) può essere incluso in tutte le pagine *.php: se esiste PATH_INFO, e presenta i corretti separatori, ritroveremo le variabili all'interno dell'array $_PINFO.

Ad es. http://www.dominio.it/index.php/nome=mario/cognome=rossi

avrà disponibili le variabili "nome" e "cognome" in questo modo

<?php

include("myscript.php") ;

echo("Ciao".$_PINFO["nome"]." ". $_PINFO['cognome']."!") ;

?>


Lo script completo

<?php

/*

Inizializza l'array vuoto

*/

$_PINFO=array() ;

if(isset($_SERVER["PATH_INFO"])){

/*

Determina i caratteri usati come separatori delle variabili

*/

$separators=array("/","=") ;

$collection=$_SERVER["PATH_INFO"] ;

/*

Togliamo il primo slash da PATH_INFO

*/

$collection=substr($collection,1) ;

/*

Nel caso in cui l'ultima variabile resti vuota e si abbia una PATH_INFO di questo tipo,

pagina.php/var1=val1/var2=val2/var3=/, l'ultimo separatore crea errori quindi va tolto

*/

if(substr($collection,-1)==$separators[0]){

$collection=substr($collection,0,-1) ;

}

/*

Sicurezza: controlla valori inseriti dall'utente

*/

$collection=strip_tags($collection) ;

$collection=escapeshellcmd($collection) ;

//Fine sicurezza

/*

Riduciamo i separatori nell'URL ad uno soltanto e utilizziamo un explode() estrarre le variabili e i loro valori

*/

$collection = str_replace($separators[1], $separators[0], $collection);

/*

Ecco l'explode

*/

$collection=explode($separators[0],$collection) ;

/*

Riempie di variabili l'array $_PINFO

*/

foreach ($collection as $key=>$value){

if(!($key%2)){

$_PINFO[$value]=$collection[$key+1] ;

}

}

/*

decommentare la riga qui sotto se si desidera

mantenere la compatibilità con script che "raccolgono" le variabili

da QUERY_STRING

*/

//$_GET=&$_PINFO ;

/*

Solo dimostrativo non inserire nelle pagine

*/

print_r($_PINFO);

}//end if isset(PATH_INFO)

?>

Una variante

Ho creato anche una versione dello script che ricorre alle espressioni regolari di tipo Perl per estrarre le variabili da PATH_INFO, ma essendo le sue prestazioni leggermente inferiori rispetto a quello visto nella pagina precedente ho preferito lasciarla da parte.

Considerazioni sulla sicurezza

È bene ricordare che nei confronti dei dati raccolti da PATH_INFO dobbiamo mantenere la medesima diffidenza e le stesse cautele che si debbono adottare nei confronti dei dati provenienti da QUERY_STRING.

Non sappiamo che cosa il visitatore malintenzionato potrebbe inserire nella stringa: codice html, script lato client, oppure persino "sql injections" e comandi della shell, dunque nello script finale sono previste alcune funzioni di sicurezza (indicate dai commenti), sta a voi decidere se le ritenete necessarie oppure no per le vostre pagine.

Senza fatica

Chi cercasse soltanto il risultato senza troppo interesse per il funzionamento dello script può ricorrere a questa mini-libreria, da usare come nell'esempio che segue:

<?php

include('url_lib.php') ;

getPIvars('/' , '=', true) ;

/***

Solo dimostrativo

***/

print_r($_PINFO) ;

echo('<br /><br />') ;

/*

Stampa la costante MYROOT

*/

echo(MYROOT) ;

/*

register_globals= On

*/

extract($_PINFO) ;

/*

Compatibilità con script che già utilizzano l'array $_GET

*/

$_GET=&$_PINFO ;

/***

Fine dimostrativo

***/

?>

La chiamata alla funzione getPIvars(), specificando i separatori che si è deciso di utilizzare, rende immediatamente disponibile l'array $_PINFO, questo ovviamente risulterà vuoto se non esiste alcuna PATH_INFO. Il terzo parametro , booleano, è facoltativo: permette di attivare e disattivare il controllo sulla sicurezza (default = true).

Viene creata anche la costante MYROOT che contiene il percorso con cui completare i link, i quali andranno comunque adattati come visto in precedenza.

Conclusioni

Utilizzo da qualche tempo questo metodo per "addomesticare" gli URL e lo trovo quello a me più congeniale, data la sua semplicità. Non conosco siti famosi che lo mettano in pratica, sembra tuttavia che amazon.com ricorra a questo sistema per passare gli ID di sessione e mantenere traccia degli utenti.

Chi sia interessato a metodi più sofisticati, o comuque alternativi, di url-rewriting può consultare l'articolo Indicizzare le pagine dinamiche sui motori di HTML.it (con soluzione anche per ASP e per coloro che non possono accedere alla configurazione del server).

N.B. aggiornamento Apache 2.0

Chi si trovi ad operare con Apache 2.x (il cui supporto da parte di PHP è ancora sperimentale), dovrà inserire nel file httpd.conf o in un .htaccess la direttiva AcceptPathInfo On.


Ti consigliamo anche