• Super User

    [Tutorial] Creare un Calendario Dinamico in PHP

    Questa breve pillola è dedicata a tutti quelli che, come me, avevano la necessità di creare un calendario dinamico completo, magari per una gestione di news più professionale ( il mio caso ) o puramente a scopo informativo come servizio agli utenti.

    Partiamo dal presupposto che la dinamicità la comprenderete solo durante la creazione dello script. Il mio scopo era quello di seguire uno schema così:

    
     ----------------------------------
    | LU | MA | ME | GI | VE | SA | DO |
     ----------------------------------
    |  Giorni                          |
     ----------------------------------
    
    

    E ci ho sbattuto la testa per più di una settimana per trovare il metodo logico giusto. Cominciamo ora con la....

    TEORIA

    Cominciamo ad elencare le caratteristiche che un calendario deve avere:

    1. Riconoscimento automatico giorno ( numerico )
    2. Riconoscimento automatico giorno ( della settimana, numerico )
    3. Riconoscimento automatico mese ( numerico )
    4. Riconoscimento automatico mese ( testuale )
    5. Riconoscimento automatico anno.

    Tutte queste le possiamo trovare grazie alla funzione date() che il nostro fantastico PHP ci mette a disposizione. Ora però ci dobbiamo servire anche di altre informazioni quali:

    1. Giorno della settimana del primo giorno del mese ( Per capire quando dovrebbe cominciare il conto dei giorni )
    2. Numero dei giorni del mese
    3. Numero delle settimane del mese corrente

    In più, se è febbraio, doivremo riuscire a calcolare di quanti giorni è, visto che date() non ha questa funzione.

    La mia idea consiste nel far scorrere i giorni tramite due cicli, uno dentro l'altro: Il primo penserà alle settimane, l'altro ai giorni delle settimane. Naturalmente i giorni non possono essere disposti a caso, bensì il primo giorno di ogni mese deve corrispondere al suo posto nella settimana.

    Per esempio: Se il primo giorno del mese è Martedì, il calcolo dei giorni non deve iniziare Lunedì, come verrebbe + semplice, bensì Martedì.

    Per risolvere questo problemino, ho calcolato il primo giorno del mese ( nella settimana ) e ho impostato il secondo ciclo ( quello dei giorni della settimana ) in modo che non parta prima che il giorno del ciclo corrisponda a quello prima calcolato. Naturalmente ciò non aveva senso se non accumulavo i valori in una variabile in modo tale che in seguito li possa togliere a quelli del ciclo al momento della visualizzazione ( Evitando di avere valori negativi ).

    A questo punto sicuramente vi troverete ancora più confusi di prima, ma non preoccupatevi: anche io mi trovavo così quando scoprì come fare 😄


  • Super User

    PRATICA

    Scommetto che questa è la parte che vi piace di più :D, ma non scordatevi che PRIMA DELLA PRATICA, ci deve essere una TEORIA PERFETTA ( o quasi 😄 ).

    Ecco qui cosa il mio genio malefico è riuscito a confabulare ( Naturalmente tutto commentato per spiegarvi il funzionamento 😞

    
    	//Trovo i dati fondamentali:
    	$dati['giorni_mesi'] = array(31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // Array con i giorni dei mesi
    	$dati['mese_num'] = date("n", time()); // Mese corrente ( numerico )
    	$dati['mese_text'] = date("F", time()); // Mese Corrente ( testuale )
    	$dati['oggi'] = date("j", time()); // Oggi ( numerico senza eventuali zeri )
    	$dati['oggi_sett'] = date("w", time()); // Oggi ( nella settimana, numerico )
    	$dati['anno'] = date("Y", time()); // Anno
    	$dati['start'] = date("w", mktime(0,0,0, $dati['mese_num'], 1, $dati['anno'])); // Giorno della settimana del primo giorno dell'anno
    	$dati['giorni_mesi'][1] = (($dati['mese_num']%400) == 0) ? 29 : 28; // Calcolo dei giorni di febbraio
    	$dati['giorni_mese'] = $dati['giorni_mesi'][$dati['mese_num']-1]; // Giorni del mese corrente
    	$dati['settimane_mese'] = ceil($dati['giorni_mese']/7); // Settimane del mese corrente arrotondato per eccesso.
    	
    	//
    	// Vi sarete accorti che:
    	// 1) Nel calcolo dei giorni del mese corrente c'è un -1: Questo è perchè l'array inizia da 0, non da 1
    	// 2) Ho arrotondato per eccesso il calcolo delle settimane: Per evitare giorni nascosti nell'ultima settimana
    	// 3) I giorni della settimana trovati da date() iniziano da 0 ( Domenica ) fino a 6 ( Sabato )
    	//
    	
    	$info['can_start'] = FALSE; // Se il conteggio reale dei giorni può partire
    	$info['to_less'] = 0; // Giorni da accumulare
    
    	$text = '<div align="center">**'.$dati&#91;'mese_text'&#93;.'**</div>'.
    	'<table align="center">
    		<tr>
    			<td class="cal_days">LU</td>
    			<td class="cal_days">MA</td>
    			<td class="cal_days">ME</td>
    			<td class="cal_days">GI</td>
    			<td class="cal_days">VE</td>
    			<td class="cal_days">SA</td>
    			<td class="cal_days">DO</td>
    		</tr>'; // Schema fisso dei giorni della settimana
    
    	//
    	// Ciclo madre&#58; Continua per tutte le settimane del mese
    	//
    
    	for&#40;$ciclo = 0; $ciclo <= $dati&#91;'settimane_mese'&#93;; $ciclo++&#41;
    	&#123;
    		$text .= '<tr>'; // Aggiungo una griglia
    
    		//
    		// Ciclo Figlio &#40; SubCiclo &#41;&#58; Avanza per tutti i giorni della settimana
    		//
    		
    		for&#40;$subciclo = 1; $subciclo <= 7; $subciclo++&#41;
    		&#123;
    			//
    			// Controllo se il ciclo può partire e se il giorno del ciclo figlio
    			// corrisponde a quello della settimana del primo giorno del mese
    			//
    
    			if&#40;$subciclo != $dati&#91;'start'&#93; && $info&#91;'can_start'&#93; == FALSE&#41;
    			&#123;
    				//
    				// Se tutti e due sono FALSE&#58;
    				//
    
    				$text .= '<td class="cal_day"></td>'; // 1&#41; Aggiungo una casella vuota
    				$info&#91;'to_less'&#93;++; // 2&#41; Aggiungo un giorno da levare
    
    				continue; // 3&#41; Faccio ricominciare il ciclo finchè uno dei due casi si riveli TRUE
    			&#125;
    			else
    			&#123;
    				$info&#91;'can_start'&#93; = TRUE; // Muto il valore di can_start in TRUE
    			&#125;
    			
    			//
    			// Naturalmente solo uno dei due casi può rivelarsi TRUE&#58; Solo ' $subciclo != $dati&#91;'start'&#93; '
    			// dato che can_start diverrà TRUE solo quando si avvererà la prima condizione. Così il conto può partire
    			//
    			// Ora mi calcolo il giorno corrente, Sommando il valore corrente della variabile di questo ciclo ai giorni
    			// delle settimane trascorse &#40; Grazie alla moltiplizacione per 7 di $ciclo &#41; e levando infine i giorni
    			// accumulati in precedenza. Vi ricordo che questo di seguito è la variabile contenente il giorno da mostrare,
    			// non quello di oggi
    
    			$dati&#91;'current_day'&#93; = $subciclo+&#40;$ciclo*7&#41;-$info&#91;'to_less'&#93;; // Calcolo il giorno da mostrare
    			
    			//
    			// Controllo ci restano ancora giorni del mese
    			//
    
    			if&#40;$dati&#91;'current_day'&#93; <= $dati&#91;'giorni_mese'&#93;&#41;
    			&#123;
    
    				//
    				// Se si...
    				//
    				// Vorrete fare capire il giorno di oggi, no? Quindi cambiamo stile
    				// alla cella in caso questa corrisponda a quella di oggi.
    				//
    
    				if&#40;$dati&#91;'current_day'&#93; == $dati&#91;'oggi'&#93;&#41; // Controllo se il giorno da mostrare è quello di oggi
    				&#123;
    					$tdclass = 'oggi'; // Cambio stile in 'oggi' se è oggi
    				&#125; else &#123;
    					$tdclass = 'default'; // Cambio stile in 'Default' se non è oggi
    				&#125;
    
    				$text .= '<td class="'.$tdclass.'">'.$dati&#91;'current_day'&#93;.'</td>'; // Poi aggiungo la cella
    			&#125; else &#123;
    				//
    				// Se invece non ci restano più giorni del mese, faccio terminare il ciclo
    				//
    
    				break;
    			&#125;
    			
    			//
    			// Finisce qui il SubCiclo, se ci sono ancora settimane da mostrare il ciclo continuerà, se no, si fermerà.
    			//
    		&#125;
    
    		$text .= '</tr>'; // Chiudo la griglia
    	&#125;
    
    	$text .= '</table>'; // Chiudo la tabella
    
    

    Beati voi che state leggendo questo script perchè non dovrete sbattere la testa su ogni muro come ho fatto io! 😄

    Spero vi sia utile! 😄 :ciauz: :ciauz: :ciauz:


  • Super User

    mmm....ci linki la pagina dove l'hai usato? 😄


  • Super User

    @Tuonorosso said:

    mmm....ci linki la pagina dove l'hai usato? 😄
    Non credi che l'ho fatto io? 😄 Aspetta...


  • Super User

    @PaTeR said:

    Non credi che l'ho fatto io? 😄 Aspetta...

    http://ctpaterct.altervista.org/calendario.php :yuppi: :yuppi: :yuppi:


  • Super User

    mahuahuhuah, certo che ci credo!!! Era per vedere come veniva...

    PS: ma non puoi linkarci il tuo sito?


  • User Attivo

    si potrebbe implementare anche uno stile diverso per la domenica ed altri giorni festivi :sbav:


  • Super User

    @Tuonorosso said:

    mahuahuhuah, certo che ci credo!!! Era per vedere come veniva...

    PS: ma non puoi linkarci il tuo sito?ho postato sopra 😄


  • Super User

    @sms said:

    si potrebbe implementare anche uno stile diverso per la domenica ed altri giorni festivi :sbav:Sisi, non ho implementato stili per darvi + autonomia, quelli nella pagina li ho messi da esempio 😄


  • Community Manager

    Pater, davvero un ottimo lavoro, grande 🙂

    Quando clicco su una data da un 404 cosa vorresti fare in realta?


  • Super User

    @Giorgiotave said:

    Pater, davvero un ottimo lavoro, grande 🙂

    Quando clicco su una data da un 404 cosa vorresti fare in realta?
    Ah scusate, li dovevo levare... praticamente lo utilizzavo per leggere le nius 😄 Calcolavo anche il TIMESTAMP e leggevo dal DB... E' una delle tante idee che si posso applicare 😄


  • User Attivo

    Utilissimo.

    Grazie mille


  • User Attivo

    non ho fatto in tempo a leggere tutto (spero di non ripetere qualcosa di già detto)

    TIPS per sapere il numero dei giorni di un mese in automatico (febbr. e bisest. compresi)

    • si stabilisce la data del primo giorno del mese successivo
    • si togli un giorno (così siamo all'ultimo giorno del mese in questione)
    • si prende la parte numerica del giorno

    così abbiamo il numero di giorni del mese in questione

    :ciauz:


  • Super User

    @riky78 said:

    non ho fatto in tempo a leggere tutto (spero di non ripetere qualcosa di già detto)

    TIPS per sapere il numero dei giorni di un mese in automatico (febbr. e bisest. compresi)

    • si stabilisce la data del primo giorno del mese successivo
    • si togli un giorno (così siamo all'ultimo giorno del mese in questione)
    • si prende la parte numerica del giorno

    così abbiamo il numero di giorni del mese in questione

    :ciauz:ce lo puoi fare un esempio? non sto capendo molto...


  • User Attivo

    hai ragione.....

    
    $data_inizio="2005-3-5"; //data del mese di cui si vogliono conoscere i giorni
    $data_tmp=date&#40;"Y-m",strtotime&#40;$data_inizio&#41;&#41;."-1";	//inizio mese
    $data_tmp=strtotime&#40;"+1 month",strtotime&#40;$data_tmp&#41;&#41;; //mese prossimo
    $data_fine=date&#40;"Y-m-d",strtotime&#40;"-1 day",$data_tmp&#41;&#41;;
    $giorni=date&#40;"d",strtotime&#40;$data_fine&#41;&#41;;
    echo $giorni;
    
    

    preciso:

    è un modo sicuro x sapere i giorni del mese ed esula dalla pilloa in se


  • Super User

    @riky78 said:

    hai ragione.....

    
    $data_inizio="2005-3-5"; //data del mese di cui si vogliono conoscere i giorni
    $data_tmp=date&#40;"Y-m",strtotime&#40;$data_inizio&#41;&#41;."-1";	//inizio mese
    $data_tmp=strtotime&#40;"+1 month",strtotime&#40;$data_tmp&#41;&#41;; //mese prossimo
    $data_fine=date&#40;"Y-m-d",strtotime&#40;"-1 day",$data_tmp&#41;&#41;;
    $giorni=date&#40;"d",strtotime&#40;$data_fine&#41;&#41;;
    echo $giorni;
    
    

    preciso:

    è un modo sicuro x sapere i giorni del mese ed esula dalla pilloa in seottimo, lo testerò appena possibile 😄


  • User Newbie

    ciao bell script lo usato ma non so il motivo mi mancano 2 giorni dell mese
    se vi interessa la modifica x unirlo ad un db e segnalare vari appuntamenti vi posto il codice.


  • Super User

    Ciao darkrunik e benvenuto nel Forum GT ;),
    ho tolto io il link che avevi postato,se vuoi segnalare il tuo sito puoi farlo nell'apposita area del forum "Segnala il tuo sito",questa è una sezione più tecnica 🙂
    Se vuoi postare la tua modifica,ben venga,saresti d'aiuto a tutti gli utenti interessati 🙂 😉
    Ciao!


  • User Attivo

    Ho visto che lo script è vecchiotto...cmq volevo segnalare un metodo alternativo per fare un calendario... che sembra più semplice..

    Ho dovuto estrapolarlo dal suo contesto e metterlo in una pagina per farvelo vedere, è spiegato sommariamente durante il codice...

    [PHP]<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
    Mese:
    <select name="mese">
    <?php
    $mese = array(1 => 'Gen','Feb','Mar','Apr','Mag','Giu','Lug','Ago','Set','Ott','Nov','Dic');

    		for($a=1; $a<=12; $a++)
    		{
    			echo "<option value='$a'>$mese[$a]</option>\n";
    		}
    	?>
    </select>
    <br/>
    <input type="text" size="4" maxlength="4" name="anno"><br>
    
    <input type="submit" value="Vai"/>
    

    </form>

    <?php
    $month = $_POST['mese'];
    $year = $_POST['anno'];
    echo $mese[$month] . "/" . $year;

    $first = mktime(0,0,0,$month ,1,$year);// time stamp del primo giorno del mese
    $total_days = date("t", $first);// giorni totali del mese
    $first_day_week = date("w",$first);// numero del giorno della settimana (0=domenica,1=lunedì ecc)
    if($first_day_week == 0) $first_day_week = 7;// domenica è 0 quindi lo trasformo in 7
    ?>
    <table style="font:inherit; font-size:10px; color: #666666" width="210" cellspacing="0">
    <tr style="font-weight:bold; text-align:center; color:#000000">
    <td style="background:#FFF3C4">Lu</td>
    <td style="background:#FFEC9F">Ma</td>
    <td style="background:#FFE784">Me</td>
    <td style="background:#FFE16A">Gi</td>
    <td style="background:#FFCC00">Ve</td>
    <td style="background:#FF9900">Sa</td>
    <td style="background:#FF6600">Do</td>
    </tr>
    <tr>
    <?php
    $a = 1;// quando $a sarà divisibile per 7 chiude la riga di tabella e va a capo

    $b = 1;// per cambiare lo sfondo alla cella del giorno della settimana ( ci si può sbizzarrire)

    $day = 1;

    while($day <= $total_days)
    {
    echo "\t\t<td style="text-align:center;";
    if($b == 1)
    {
    echo "background:#FFF3C4">";
    }
    elseif($b == 2)
    {
    echo "background:#FFEC9F">";
    }
    elseif($b == 3)
    {
    echo "background:#FFE784">";
    }
    elseif($b == 4)
    {
    echo "background:#FFE16A">";
    }
    elseif($b == 5)
    {
    echo "background:#FFCC00">";
    }
    elseif($b == 6)
    {
    echo "background:#FF9900">";
    }
    elseif($b == 7)
    {
    echo "background:#FF6600">";
    $b = 0;
    }

    $b++;
    
    if($a < $first_day_week)
    {
    	echo "&nbsp;";
    }
    else
    {
    	if($em->day[$day] === true)
    	{
    

    // Questa è una classe per scrivere un link se l'evento esiste (preso dal db)
    }
    else
    {
    echo $day;
    }
    $day++;
    }
    echo "</td>\n";

    if(is_integer($a / 7)) echo "\t</tr><tr>\n";
    $a++;
    

    }

    ?>
    </tr>
    </table>[/PHP]

    Lo script è pubblicato, quindi non copiate, è reato.:nonono: Grazie

    Ho messo un esempio su
    http://directory.zenia.it/misc/calendar.php

    moderatore sii clemente per il link, non c'è nient'altro che il calendario nella pagina...

    C'è un form per scegliere mese e anno!

    Buon divertimento


  • Super User

    Grazie Francesco Zeno per aver postato la tua soluzione 🙂
    Per il link,figurati,hai fatto bene a postare una demo 🙂
    L'importante è che non spammi il tuo sito,poi tutto è permesso 😉

    @francesco zeno said:

    Lo script è pubblicato, quindi non copiate, è reato.:nonono: Grazie

    Se non è protetto da copyright non è illegale copiarlo.
    Comunque,un consiglio...potresti proteggerlo gratuitamente con una licenza creative commons oppure far inserire un link al tuo sito all'interno dello script...
    in questo modo aumenteresti le visite al tuo sito e alzeresti il tuo pagerank 😉