21 commenti tutorial, php

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:

  1. il file di cui si chiede l'inclusione esista: a questo scopo utilizzeremo la funzione file_exists;
  2. evitare che l'utente possa indicare tramite GET dei percorsi tra le cartelle: a questo scopo utilizzeremo la funzione basename;
  3. 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

avatar Olimpio Romanella

Olimpio Romanella

19 November 2016 ore 17:35

@valerio: non e' in tema con il seguente articolo. Scrivimi in privato sulla pagina Facebook.

avatar valerio

valerio

19 November 2016 ore 12:43

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?

avatar Lorenzo

Lorenzo

16 February 2016 ore 17:28

ciao come mai quando ho inserito nel file .htaccess la stringa:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|css|js)
RewriteRule ^(.*)$ /index.php?page=$1 [L]


nel mio sito non visualizzo più la home ma mi esce error 404 impostato da php ?

c'è spiego meglio quando entro nel sito la pagina che dovrebbe essere home non si vede più come faccio a renderla visibile subito come index principale ?

avatar Lorenzo

Lorenzo

16 February 2016 ore 13:32

@Olimpio Romanella:

Grazie mille :)

avatar Olimpio Romanella

Olimpio Romanella

16 February 2016 ore 09:59

@Lorenzo: Ciao Lorenzo, Devi inserire querl codice nel file .htaccess da porre nella document root del tuo progetto.

avatar Lorenzo

Lorenzo

15 February 2016 ore 21:46

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 ?

avatar Olimpio Romanella

Olimpio Romanella

26 February 2015 ore 19:58

@Lorenzo: no. Peró il tutto risulterebbe poco pratico da gestire.

avatar Lorenzo

Lorenzo

26 February 2015 ore 18:59

Grazie mille, guida utilissima... era proprio ciò che stavo cercando!!!

Una domanda: capisco bene che per certi siti di grandi dimensioni può essere meglio utilizzare un CMS, ma se si volesse fare un sito (molto semplice) con 100/200 pagine... un file config_page troppo lungo potrebbe rallentare troppo il sito?

Grazie ancora e complimenti!

avatar Angela

Angela

19 January 2015 ore 12:23

...scusa, avevo ancora la pagina aperta ed aggiornando mi è ripartito il vecchio messaggio :-)

Si, certo. Gli indirizzi funzionano senza url rewrite.

avatar Angela

Angela

19 January 2015 ore 12:21

Un saluto e le mie congratulazioni per l'articolo.
Mi sembra tutto molto chiaro, almeno fino alla fine, quando c'è il riferimento al rewrite url.
Certamente sbaglierò io qualcosa, ma mi blocco.
Ho provato a creare un file .htaccess e posizionarlo allo stesso livello del file index.php, ma non funziona. Ho provato anche a modificare il file .htaccess presente nella cartella /pages, ma niente.

Mi puoi indicare dove sbaglio?
Ti ringrazio in anticipo.

avatar Olimpio Romanella

Olimpio Romanella

18 January 2015 ore 16:30

@Angela: ma aldilà del rewrite, ma con URL stile

index.php?page=chi-siamo

funziona?

avatar Angela

Angela

18 January 2015 ore 13:40

Un saluto e le mie congratulazioni per l'articolo.
Mi sembra tutto molto chiaro, almeno fino alla fine, quando c'è il riferimento al rewrite url.
Certamente sbaglierò io qualcosa, ma mi blocco.
Ho provato a creare un file .htaccess e posizionarlo allo stesso livello del file index.php, ma non funziona. Ho provato anche a modificare il file .htaccess presente nella cartella /pages, ma niente.

Mi puoi indicare dove sbaglio?
Ti ringrazio in anticipo.

avatar Roberto

Roberto

07 April 2014 ore 11:20

@Olimpio Romanella:Ciao,
grazie per la risposta.
Intendevo se si volesse al posto di creare dei file per ogni pagina utilizzare un database con le pagine inserite al suo interno come bisognerebbe procedere?
Cè qualche semplice guida che spiega come realizzare un semplice sistema di gestione dei contenuti con eventuali upload di immagini e file?

Grazie
Roberto

avatar Olimpio Romanella

Olimpio Romanella

04 April 2014 ore 17:44

@Roberto: non ho capito cosa intendi esattamente.
Per interagire con il database nel seguente esempio si potrebbero seguire tante strade più o meno raffinate. Io, per rimanere sul semplice, istanzierei la classe PDO nel file index.php così da poter utilizzarla in tutti i file inclusi.

Ho parlato del PDO in una serie di articoli introduttivi (connessione tramite PDO e eseguire query con PDO) ma che presuppongono un minimo di dimestichezza con il linguaggio SQL.

avatar Roberto

Roberto

04 April 2014 ore 14:45

Ciao,
Grazie per il tuo articolo!
Voleco farti una domanda..
qualora si volesse utilizzare mysql per generare i contenuti, cosa bisognerebbe fare?
C'è qualche guida semplice che spiega come interagire anche con il DB?
Grazie
Roberto

avatar Olimpio Romanella

Olimpio Romanella

12 February 2014 ore 18:45

@DDI @XiNu
nel file .htaccess che ho messo nell'articolo ho indicato tre cartelle (images, css, js) per le quali la regole di rewrite URl non vale. Quindi i relativi file potranno essere collocati al loro interno.

A quel punto userei dei normalissimi URL assoluti senza complicarmi troppo la vita.

avatar XiNu

XiNu

10 February 2014 ore 13:34

Ciao Olimpio, bravo per l'articolo, mi è chiaro più degli altri trovati in rete.
Sarei interessato anch'io al quesito posto da DDI, se puoi delucidi? Grazie in anticipo

avatar DDI

DDI

01 February 2014 ore 11:54

@Olimpio Romanella: ciao Olimpio e complimenti per l'articolo. Come tratteresti i vari files css, javascript immagini? All'interno del template head, ad esempio ho necessità di includere diversi file. Li lascio all'interno della stessa cartella o posso utilizzare la struttura classica?
Qualora inoltre ho la necessità di richiamare non solo pagine diverse ma anche record diversi da inserire in una pagina ad esempio per un template articolo, respiro gli id come per get (Page)? Ciao e grazie,
Ddi

avatar Olimpio Romanella

Olimpio Romanella

21 December 2013 ore 02:43

@antonio: prova ad implementare lo script e vedrai che non é così difficile come può sembrare.
Cercherò di correggere il problema dei commenti appena ho un attimo.

avatar antonio

antonio

20 December 2013 ore 23:56

cmq mi basta fare aggiorna, in questa pagina, che mi commenta da solo

avatar antonio

antonio

20 December 2013 ore 19:28

mi si è fuso il cervello