10 Nov 2013 21 commenti
La realizzazione di siti con le inclusioni dinamiche è una richiesta che ho letto spessissimo sui forum del settore e le risposte fornite non sempre sono all'altezza. La tecnica è relativamente semplice ed ha diverse varianti ma, in tutti i casi, sono richiesti una serie di piccoli accorgimenti per non incorrere in rischi per la sicurezza dei nostri applicativi.
La tecnica consiste nell'avere alcune sezioni della pagina web che si ripetono in tutte le pagine del sito, tipicamente l'head, l'header, la sidebar ed il footer, mentre la parte centrale della pagina varia per mezzo di un'inclusione dinamica.
Premetto che è una tecnica che conviene adottare per progetti relativamente semplici e con poche pagine. In caso contrario conviene ricorrere ad uno dei tanti framework che utilizzano il pattern MVC. Ma detto ciò partiamo.
La logica degli include dinamici
Il meccanismo di funzionamento degli include dinamici è relativamente semplice: andremo ad incudere la pagina che l'utente ci richiederà inviandoci una varibile di tipo $_GET, nel mio esempio sarà $_GET['page'].
Come tutti gli input provenienti dall'utente anche in questo caso dovremo assicurarci che sia "sicuro": sul tema invito tutti a leggere un interessante ed istruttivo articolo linkato di seguito che spiega gli errori in cui si può incorrere con gli include dinamici.
Per i nostri scopi nel ricevere la variabile $_GET['page'] dovremo verificare che:
- il file di cui si chiede l'inclusione esista: a questo scopo utilizzeremo la funzione file_exists;
- evitare che l'utente possa indicare tramite GET dei percorsi tra le cartelle: a questo scopo utilizzeremo la funzione basename;
- il file richiesto sia uno di quelli cui consentiamo l'inclusione: creeremo una cartella dedicata a tale scopo al cui interno metteremo unicamente i file che è possibile includere, nel nostro esempio è la cartella pages/, tale per cui consentiremo l'inclusione solo dei file presenti in quella cartella e non in altre.
Articolazione delle cartelle
Partiamo dall'articolazione delle cartelle. Avremo due cartelle ed un file gestisce le richieste:
- template/ che conterrà i file con i contenuti che si ripetono in più pagine (l'head, l'header, la sidebar ed il footer);
- pages/ che conterrà i file che dovranno essere inclusi dinamicamente;
- index.php che gestirà le richieste dell'utente.
index.php /template/head.php /template/header.php /template/slideshow.php /template/sidebar.php /template/footer.php /pages/home.php /pages/chi-siamo.php /pages/servizi.php /pages/contatti.php
Inoltre, come mi è stato giustamente puntualizzato in una conversazione su Twitter, è opportuno impedire l'accesso diretto ai file collocati nelle due cartelle /pages e /template. Il modo migliore per realizzare ciò è collocare all'interno di suddette cartelle un file .htaccess con la suddetta direttiva:
deny from all
Lo script che gestisce gli include dinamici
Quindi avremo:
<?php /* Settiamo la cartella in cui sono presenti i file di cui consentiamo l'inclusione */ $cartella_file_da_includere = 'pages/'; /* Settiamo la pagina di default che verrà inclusa quando l'utente non ci fornisce indicazione */ $pagina_di_default = 'home'; /* Settiamo la pagina 404 (not found) da includere quando la pagina richiesta non esiste */ $pagina_404 = 'pages/404.php'; /* Settiamo la cartella con i file che contengono le parti statiche del sito */ $template = "template/"; /* Verifichiamo il valore indicato dall'utente e se non esiste la pagina richiesta sarà quella di default */ $pagina_richiesta = isset($_GET['page']) ? basename( (string) $_GET['page'] ) : $pagina_di_default; /* Componiamo il percorso anteponendo il percorso alla cartella ed aggiungendo l'estensione del file (.php) */ $file_da_includere = $cartella_file_da_includere . $pagina_richiesta . ".php"; /* Se il file esiste lo includiamo altrimenti mostriamo la pagina 404 (not found) */ if( file_exists ($file_da_includere) ){ include($template . "head.php"); include($template . "header.php"); include($template . "slideshow.php"); include( $file_da_includere ); include($template . "sidebar.php"); include($template . "footer.php"); } else{ include($template . "head.php"); include($template . "header.php"); include( $pagina_404 ); include($template . "sidebar.php"); include($template . "footer.php"); } ?>
Per testare il corretto funzionamento andremo a puntare il browser sui seguenti URL:
- index.php
- index.php?page=chi-siamo
- index.php?page=servizi
- index.php?page=contatti
Lo script appena mostrato è perfettamente funzionante e rappresenta un buon punto di partenza.
Questo tutorial, come molti altri presenti in rete, potrebbe pertanto chiudersi qui ma prima vorrei soffermarmi su alcuni dei limiti connessi con tale architettura.
Limiti dei siti realizzati con gli include dinamici
In assenza degli opportuni accorgimenti tutto quello che non è presente all'interno della parte centrale della pagina, cioè quella che includiamo dinamicamente, è totalmente statica in tutte le pagine. Ciò porta ad una serie di importanti controindicazioni e problematiche sul piano operativo.
Ne vorrei citare alcune che ritengo siano le più importanti:
- Il tag title ed i metatag dovrebbero essere dinamici mentre così saranno sempre identici all'interno dell file head.php;
- I file inclusi potrebbero avere delle esigenze di dinamicità a seconda della pagina richiesta: ad esempio attribuire una classe css alla voce del menu attiva (la classica class="active" che spesso si utilizza nei menu);
- Il template potrebbe essere dinamico: nell'esempio proposto abbiamo incluso il file slideshow.php che, eventualmente, potremmo gradire solo nella home page; inoltre potremmo desiderare in alcune pagine di non includere sidebar.php.
Queste problematiche possono essere affrontate in vari modi, più o meno complessi e tecnicamente raffinati. Io vi proporro quello che ritengo sia l'approccio più semplice ovvero quello di tipo procedurale (niente OPP e classi php). Nulla vieta di poter raffinare stilisticamente lo script e riscriverlo in modo maggiormente rigoroso.
Aggiungere un file di configurazione
In questa sede ho preferito mostrare un approccio che, seppur inedeguato per progetti medio-grandi, unisce semplicità massima e grande flessibilità e risulta di gran lunga adeguato per quei progetti che prevedano un numero ridotto di pagine, circa 5-10 pagine web.
La tecnica fa ricorso al seguente file di configurazione config_page.php:
<?php /* In questa variabile setteremo la configurazione di default che sarà applicata a tutte le pagine salvo specifica eccezione Potranno essere aggiunte tutte le configurazioni che potranno servirci per i più disparati usi */ $page_option_default = array( 'title' => 'Titolo di defalt della pagina', 'description' => 'Descrizione di defaul della pagina ...', 'slideshow' => FALSE, 'sidebar' => TRUE ); /* Questa variabile, un array vuoto verrà man mano popolato a seconda delle eccezioni che vorremmo specificare per ciascuna pagina */ $page_option = array(); /* Specifichiamo le eccezioni per tutte le pagine del sito la chiave dell'array dovrà avere lo stesso nome della pagina NB: occorre indicare solo le eccezioni rispetto al default e se non vogliamo che ci siano eccezioni non occorrerà nemmeno creare la chiave per la pagina. Ad esempio la pagina chi-siamo, non essendo presente tra le chiavi dell'array prenderà i valori di default indicati precedentemente */ $page_option['home'] = array( 'slideshow' => TRUE ); $page_option['servizi'] = array( 'title' => 'Servizi - Nome Azienda', 'description' => 'i nostri servizi spaziano da ...' ); $page_option['contatti'] = array( 'title' => 'Contatti - Nome Azienda', 'description' => 'Potete contattarci ai seguenti recapiti ...', 'sidebar' => FALSE ); ?>
Il file index.php subirà alcuni cambiamenti:
<?php /*parte di codice già commentato in precedenza*/ $cartella_file_da_includere = 'pages/'; $pagina_di_default = 'home'; $pagina_404 = 'pages/404.php'; $template = "template/"; $pagina_richiesta = isset($_GET['page']) ? basename( (string) $_GET['page'] ) : $pagina_di_default; $file_da_includere = $cartella_file_da_includere . $pagina_richiesta . ".php"; /* includiamo la pagina in cui sono contenute le configurazioni prima mostrate */ require('config_page.php'); /* Se per la pagina non abbiamo indicato uno specifico settaggio vale quello di default */ if( !array_key_exists($pagina_richiesta, $page_option) ){ $page_option = $page_option_default; } /* altrimenti all'array di default sovrascriviamo i parametri che la pagina richiesta ha derogato */ else{ $page_option = array_merge( $page_option_default, $page_option[$pagina_richiesta] ); } if( file_exists ($file_da_includere) ){ include($template . "head.php"); include($template . "header.php"); /* includiamo la slideshow solo se previsto nelle opzioni della pagina */ if($page_option['slideshow'] === TRUE){ include($template . "slideshow.php"); } include( $file_da_includere ); /* come per la slideshow anche per la sidebar */ if($page_option['sidebar'] === TRUE){ include($template . "sidebar.php"); } include($template . "footer.php"); } else{ include($template . "head.php"); include($template . "header.php"); include( $pagina_404 ); include($template . "sidebar.php"); include($template . "footer.php"); } ?>
Al fine di rendere dinamici all'interno dell'head il file template/head.php avrà un'articolazione tipo come segue:
<html> <head> <title><?php echo $page_option['title']; ?></title> <meta name="description" content="<?php echo $page_option['description']; ?>" /> </head> </body>
Aggiunta di un nuovo parametro di configurazione
Il metodo proposto ritengo sia una buona soluzione in termini di semplicità, pulizia del codice e, soprattutto, estendibilità.
Spessissimo potrà capitarci nel prosieguo di un progetto di aver bisono di una ulteriore "opzione di pagina" che magari non era stata considerata in una fase iniziale. In questo caso ci basterà:
- aggiungere all'array $page_option_default il nome della la nuova opzione di pagina ed il relativo valore di default;
- indicare la/le eccezioni rispetto al valore di default per le pagine che lo richiedono.
Quindi, poniamo di voler aggiungere l'opzione chiamata "new-setting" che ci servirà per gestire un particolare settaggio nella nuova pagina creata "nuova-pagina":
<?php /*aggiungiamo il nuovo elemento all'array con i setting di defaul*/ $page_option_default = array( 'title' => 'Titolo di defalt della pagina', 'description' => 'Descrizione di defaul della pagina ...', 'slideshow' => FALSE, 'sidebar' => TRUE, 'new-setting' => 'valore default' ); /* Alle pagine precedenti aggiungiamo la nuova pagina ed il valore del nuovo settaggio */ $page_option['nuova-pagina'] = array( 'new-setting' => 'altro valore' ); ?>
Questa flessibilità ed estendibilità sono, a mio giudizio, il punto di forza di tale approccio.
Rewrite URL ed include dinamici
Concludo questo articolo con una chicca, forse superflua ai fini del tutorial, ma molto importante per coloro che sono attenti ad alcuni aspetti SEO: la rimozione dall'URL della index.php che costituisce una parte ridondante.
RewriteEngine on RewriteCond $1 !^(index\.php|images|css|js|sitemap\.xml|robots\.txt) RewriteRule ^(.*)$ /index.php?page=$1 [L]
Cerchiamo di capire bene questa regola: essa prevede che tutte le richieste siano indizizzate alla index.php ad eccezione di quelle dirette ad alcune sottocartelle (css e js, ma potete specificarne di ulteriori) ed alcuni file (sitemap.xml e robot.txt, ma potete specificarne altri stando attenti ad anteporre il backslash al punto). A questo punto i nostri url alle pagine create secondo l'esempio sono http://localhost/chi-siamo http://localhost/servizi e http://localhost/contatti.
Olimpio Romanella
Sono un appassionato di Web Developing con un particolare debole per php. Mi dedico principalmente dello sviluppo back-end ed in particolare programmazione lato server con php, sviluppo di database relazionali MySql e progettazione di CMS di piccole e medie dimensioni.
Mi avvalgo del framework javascript Jquery, utilizzando molti dei suoi plugin e nei dei miei progetti utilizzo spesso il framework MVC Codeigniter.
21 Commenti presenti
avrei bisogno di un programmino dove sia possibile inserire delle key
che andranno ad aggiornarsi nel titolo della pagina in html e creera delle url dinamiche.
con titolo descrizione e keyword .
sapresti indirizzarmi?
@Olimpio Romanella:
Grazie mille :)
@Lorenzo: Ciao Lorenzo, Devi inserire querl codice nel file .htaccess da porre nella document root del tuo progetto.
Scusate ma questo codice:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|css|js|sitemap\.xml|robots\.txt)
RewriteRule ^(.*)$ /index.php?page=$1 [L]
dove va inserito ?
cmq mi basta fare aggiorna, in questa pagina, che mi commenta da solo
Olimpio Romanella
19 November 2016 ore 17:35
@valerio: non e' in tema con il seguente articolo. Scrivimi in privato sulla pagina Facebook.