26 maggio 2017

Area riservata di WebSite X5 13: inserire in header un menu per l'utente loggato

Nell'articolo precedente abbiamo visto come inserire un avatar per l'utente registrato nell'area riservata di WebSite X5 13.

In questo articolo vedremo come inserire nell'header del sito (intestazione) un pulsante per il login all'area riservata che, nel momento in cui un utente è loggato, si trasforma in un piccolo menu che consente di accedere alla pagina profilo ed effettuare il logout.

Questa è la nostra demo:

demo menu utente area riservata
DEMO

Rispetto all'articolo precedente si deve partire da un punto di vista diverso: il codice deve essere inserito in tutto il sito poiché l'output avviene nell'intestazione e si deve prevedere il riconoscimento della sessione utente. Gran parte del codice è già stata presentata e spiegata nell'articolo precedente che vi consigliamo di leggere e provare, ma cercheremo comunque di dare indicazioni sequenziali agevoli da seguire anche per chi non si fosse cimentato con il precedente esempio.

Poiché utilizzeremo codice PHP è necessario impostare l'estensione .php a tutte le pagine del sito.

Passo 1 - Impostazioni


In Impostazioni » Avanzate » Statistiche, SEO e Codice » Esperto scegliamo dal menu a tendina Prima dell'apertura del tag HTML; incolliamo questo codice che definisce tutte le variabili necessarie per il funzionamento dello script e richiama il file x5engine.php:
<?php
/* Code by Giorgio C. & MAeSI - quellidelcucuzzolo.blogspot.it
Please do not remove credit */
$qblog = $_SERVER['PHP_SELF'];
if (strpos($qblog, '/blog/') !== false || strpos($qblog, '/cart/') !== false)
    $qpath = '../';
else
    $qpath = '';
require_once($qpath . "res/x5engine.php");
$qfolder  = $imSettings['general']['public_folder'];
$qurl     = pathCombine(array(
    $imSettings['general']['url'],
    $qfolder
));
$pa       = Configuration::getPrivateArea();
$dati     = $pa->whoIsLogged();
$username = $dati['username'];
$realname = $dati['realname'];
$datiUser = $pa->getUserByUsername($username); //SOLO EDIZIONE PROFESSIONAL 
$email    = $datiUser['email']; //SOLO EDIZIONE PROFESSIONAL
$userpage = $pa->getLandingPage(); //Pagina di ingresso
$avatar   = glob($qpath . $qfolder . "/avatar-" . $username . ".*");
$tsfoto   = 0;
if (empty($avatar))
    $foto = $qurl . "/default.png";
else {
    foreach ($avatar as $value) {
        if (filemtime($value) > $tsfoto) {
            $tsfoto  = filemtime($value);
            $fotonew = $value;
        }
    }
    $foto = str_replace("../", "", $fotonew);
    $foto = str_replace($qfolder, $qurl, $foto);
}
$n = time();
?>
Le uniche variabili a cui porre attenzione sono quelle commentate: chi utilizza lo script con l'edizione Evolution deve rimuovere le due righe di codice con il commento //SOLO EDIZIONE PROFESSIONAL.

Sempre in questa sezione, scegliamo ora dal menu a tendina Dopo l'apertura del tag BODY ed inseriamo questo codice che gestisce la visualizzazione del menu utente solo se l'utente è loggato, in caso contrario si visualizza il pulsante per il login:

<section class="ms-menu-Utente">
<?php
if ($username)
  {
    echo '<div class="msLog wrapper-dropdown-5"><img src="' . $foto . '?' . $n . '" alt="avatar" />' . $username,
         '<ul class="dropdown">', 
         '<li><a href="' . $qpath . 'profilo.php"><i class="fa fa-user"></i>Profilo</a></li>',
         '<li><a href="' . $qpath . $userpage .'"><i class="fa fa-home"></i>Pagina di ingresso</a></li>', //Pagina di ingresso 
         '<li><a href="' . $qpath . 'res/imlogout.php"><i class="fa fa-remove"></i>Logout</a></li>', 
         '</ul></div>';
  }
else
  {
    echo '<div class="msLog msIn">',
         '<ul>', 
         '<li><a href="' . $qpath . 'imlogin.php"><i class="fa fa-key"></i>Login</a></li>',
         '</ul></div>';
  }
?>
</section>

Quando l'utente è loggato, il menu contiene solo due voci: un link ad una pagina protetta e nascosta chiamata "Profilo" in cui verranno richiamati tutti i dati relativi all'utente, di cui parleremo in seguito, e un link per il logout.
Attenzione: se date un nome diverso a questa pagina, dovete anche cambiare il nome nel codice (profilo.php).

Nel pulsante e nelle voci del menu abbiamo inserito i tag per visualizzare le icone font Awesome. Per tutte le informazioni su come integrare questo font nel programma vi invitiamo a leggere questo articolo.

Per gli stili grafici del menu abbiamo utilizzato questo tutorial (Demo 5) pubblicato su tympanus.net, sito che presenta sempre esempi molto accattivanti.
Al CSS proposto nel tutorial abbiamo fatto qualche piccola modifica. Potete scaricare il file da QUI ed allegarlo al progetto, sempre nella scheda Esperto, File allegati al codice, indicando come Percorso relativo sul Server il nome di una cartella a vostro piacere, ma avendo cura di spuntare la casella Collega il file.
 
Sempre in questa sezione, Prima della chiusura del tag HEAD, incolliamo il codice jQuery che si occupa di mostrare/nascondere le voci del menu e regolare la sua posizione rispetto al menu mobile:
<script>
$(document).ready(function() {
  $('.msLog').on('click', function(event) {
    $(this).css('overflow', 'visible').toggleClass('active');
    event.stopPropagation();
  });
  $('#imMnMn.main-menu .hamburger-button').click(function() {
    $('.msLog').css('z-index', 10);
  })
  $('.hamburger-menu-close-button, .hamburger-site-background').click(function() {
    $('.msLog').css('z-index', 10001);
  })
});
</script>
Non è obbligatorio, ma vi consigliamo di inserire, sempre in questa sezione, anche questo script che si occupa di nascondere il codice in anteprima: in caso contrario si visualizzerebbero parti di codice che comprometterebbero la visione del template in anteprima.
<script>
$(document).ready(function() {
  // funzionalità offline
  if (location.host == "127.0.0.1:8080")
    $(".ms-menu-Utente").html('<div class="msLog msIn"><ul><li><a href="#nogo"><i class="fa fa-key"></i>Login</a></li></ul></div>');
});
</script>

La pagina profilo


Inseriamo nella Mappa del sito una pagina protetta e nascosta che chiameremo "Profilo" ed inseriamo un Oggetto Codice HTML con questo codice che permette di visualizzare i dati dell'utente connesso e il form per cambiare l'avatar:
 <!-- Code by Giorgio C. & MAeSI - quellidelcucuzzolo.blogspot.it
   Please do not remove credit  -->
<section id="ms-datiUtente">
<!-- dati utente -->
<?php
echo '<p id="datiUser">',
     '<img src="' . $foto . '?' . $n . '" alt="avatar" />',
     '<span>Username:</span> ' . $username . '<br />',
     '<span>Nome completo:</span> ' . $dati['realname'] . '<br />',
     '<span>E-mail:</span> ' . $datiUser['email'] . '<br />', // SOLO EDIZIONE PROFESSIONAL 
     '</p>';
?>   
</section>
<div style="clear:both"></div>
<!-- form per cambio avatar -->
<form id="cambioAvatar" enctype="multipart/form-data" method="POST" action="uploadavatar.php">
 <div><label for="avatar">Cambia l'immagine del profilo:</label></div>
 <input type="file" name="image" id="avatar" />
 <input type="submit" value="invia" />
</form>
<!-- messaggio di conferma/errore upload -->
<div id="messaggio">
<?php
if (!empty($_SESSION['message'])) {
    echo $_SESSION['message'];
    unset($_SESSION['message']);
}
?> 
</div>
Chi utilizza l'edizione Evolution deve rimuovere la riga di codice che contiene il commento //SOLO EDIZIONE PROFESSIONAL.
Non ci resta che allegare al progetto il file uploadavatar.php e scrivere le regole CSS che definiscono l'aspetto della pagina. Codici e procedure sono stati già spiegati nell'articolo precedente:

Per completezza, indichiamo anche il nuovo codice PHP/JS da utilizzare per visualizzare l'avatar dell'utente loggato nei commenti del guestbook e del blog.

I commenti del guestbook e del blog


In Proprietà della pagina che contiene l'Oggetto Guestbook, e/o in Proprietà della pagina speciale Blog, Esperto, Prima della chiusura del tag HEAD inseriamo questo codice:
<script>
$(document).ready(function() {
    $("input[id$='topic-form-name']").val("<?php echo $realname ?>");
    $('input[id$="topic-form-email"]').val('<?php echo $email ?>'); //SOLO EDIZIONE PROFESSIONAL
    $('input[id$="topic-form-url"]').val('<?php echo $foto ?>').parent().hide();
  $(".topic-comments-user").each(function() {
    var $item = $(this).find("a");
    if ($item.length != 0) {
      var customCampo = $item.attr("href");
      var customNome = $item.contents();
      $item.replaceWith(customNome);
      $(this).prepend("<img class='campoCustomGb' src='" + customCampo + "' alt='avatar' />");
    }
  })
});
</script>
Anche in questo caso, chi lavora con l'edizione Evolution deve cancellare la riga di codice che contiene il commento //SOLO EDIZIONE PROFESSIONAL.
Per tutto il resto facciamo riferimento a quanto già scritto nell'articolo precedente.


Aggiornamento del 13/11/2017

Aggiunto un link alla "Pagina di ingresso" nel menu utente.
Le due righe di codice aggiunte sono commentate.
La demo di questo articolo non è aggiornata.


6 maggio 2017

Area riservata di WebSite X5 13: avatar utente

Questo articolo nasce da una richiesta emersa nella community di WebSite X5 ed elaborata dall'utente Giorgio C. che ci ha coinvolto: mostrare un'immagine associata all'utente registrato, un avatar quindi, che un utente possa cambiare a piacere.
Partendo dal codice di Giorgio, con cui l'utente può visualizzare il proprio avatar nell'header del sito una volta loggato, noi abbiamo fatto una variazione sul tema, creando una pagina profilo e facendo in modo che l'immagine associata ad ogni utente sia visibile a tutti nel momento in cui l'utente inserisce un commento nel guestbook e/o in un articolo del blog.

Qui la nostra demo:

demo avatar utente area riservata
DEMO

Non entriamo nel merito di come creare un'area riservata, poiché la guida del programma è già esaustiva. Sottolineamo però che, per il corretto funzionamento del codice, occorre che nel progetto venga impostata in Gestione Dati, una Cartella su Server con accesso in scrittura verificando che abbia i permessi necessari. Accertarsi inoltre di aver scritto correttamente l'Indirizzo URL del Sito al passo 1 (Attenzione: NON scrivere il nome della pagina index nel percorso).

Vediamo ora come procedere:

La pagina profilo


La pagina profilo è una pagina protetta in cui vengono richiamati i dati dell'utente loggato: l'output è dinamico cioè dipende da chi la visualizza. In essa è presente anche il form con cui l'utente può cambiare il proprio avatar. Può essere impostata come Pagina d'ingresso per tutti gli utenti, o anche raggiungibile con un link.
Inseriamo in essa un Oggetto Codice HTML con il seguente codice:

<!-- Code by Giorgio C. & MAeSI - quellidelcucuzzolo.blogspot.it
     Please do not remove credit  -->
<div id="ms-datiUtente">
<!-- dati utente -->
<?php
$qfolder  = $imSettings['general']['public_folder'];
$n        = time();
$pa       = Configuration::getPrivateArea();
$dati     = $pa->whoIsLogged();
$username = $dati['username'];
$datiUser = $pa->getUserByUsername($username); // SOLO EDIZIONE PROFESSIONAL 
$avatar   = glob($qfolder . "/avatar-" . $username . ".*");
$tsfoto = 0;
if (empty($avatar))
    $foto = $qfolder . "/default.png";
else {
    foreach ($avatar as $value) {
        if (filemtime($value) > $tsfoto) {
            $tsfoto = filemtime($value);
            $foto   = $value;
        }
    }
}
echo '<div id="datiUser">', 
'<img src="' . $foto . '?' . $n . '" alt="avatar" />', 
'<span>Username:</span> ' . $username . '<br />', 
'<span>Nome completo:</span> ' . $dati['realname'] . '<br />', 
'<span>E-mail:</span> ' . $datiUser['email'] . '<br />', // SOLO EDIZIONE PROFESSIONAL 
    '</div>';
?>
</div>
<div style="clear:both"></div>

<!-- form per cambio avatar -->
<form id="cambioAvatar" enctype="multipart/form-data" method="POST" action="uploadavatar.php">
<div><label for="avatar">Cambia l'immagine del profilo:</label></div>
<input type="file" name="image" id="avatar" />
<input type="submit" value="invia" />
</form>

<!-- messaggio di conferma/errore upload -->
<div id="messaggio">
<?php
if (!empty($_SESSION['message'])) {
    echo $_SESSION['message'];
    unset($_SESSION['message']);
}
?>
</div>

Chi utilizza la Evolution deve rimuovere le due righe di codice con il commento //SOLO EDIZIONE PROFESSIONAL: si tratta del dato e-mail che è presente unicamente se viene utilizzata la registrazione automatica, prevista solo nell'edizione Professional. Si sottolinea inoltre che questo codice può essere utilizzato solo in pagine protette, dove il richiamo del file x5engine.php, necessario per il corretto funzionamento del codice, è già incluso.

Il codice richiede la presenza, nella Cartella su Server con accesso in scrittura indicata in Gestione Dati, di una immagine di default che verrà utilizzata finché l'utente non la cambierà. Noi abbiamo usato questa immagine: default.png. Nel caso si utilizzi un'immagine con diverso nome e/o estensione occorrerà apportare le opportune modifiche al codice.

Ovviamente il risultato sarà visibile solo online. Se vogliamo tenere pulita la pagina dell'anteprima, evitando di visualizzare parti di codice, è possibile inserire questo script in Proprietà Pagina, Esperto, Codice personalizzato, Prima della chiusura del tag HEAD:

<script>
$(document).ready(function() {
  // funzionalità offline
  if (location.host == "127.0.0.1:8080")
    $("#ms-datiUtente").html("I dati saranno visibili solo quando il sito verrà esportato su Internet");
});
</script>

Nella scheda Esperto dell'Oggetto Codice HTML possiamo scrivere le regole CSS per definire l'aspetto grafico che preferiamo. Noi abbiamo utilizzato questo codice:

#datiUser,
#cambioAvatar {
  line-height: 26px;
  font-size: 16px;
  padding: 10px;
}
#datiUser span {
  width: 125px;
  font-weight: bold;
  display: inline-block;
}
#datiUser img {
  max-width: 256px;
  float: left;
  padding: 6px 10px 6px 0;
}
#cambioAvatar input {
  padding-bottom: 10px;
}
#messaggio {
  color: red;
}
#messaggio span {
  color: green;
}

Lo script per l'upload


L'upload del nuovo avatar è gestito dal file uploadavatar.php, che si occupa di validare l'estensione del file caricato, le sue dimensioni in byte, e di rinominare il file in modo che il suo nome contenga l'username dell'utente: nel momento in cui l'utente cambierà il suo avatar, la vecchia immagine verrà cancellata dal server e sostituita da quella nuova.
<?php
/* =================================================================
   PHP Code by Giorgio C. & MAeSI - quellidelcucuzzolo.blogspot.it
   Please do not remove credit    
   =================================================================  */
if (!isset($_SERVER['HTTP_REFERER'])){
exit;
}
//apertura e lettura dati di sessione
require_once("res/x5engine.php"); 
$qfolder = $imSettings['general']['public_folder']; 
$pa      = Configuration::getPrivateArea(); 
$dati    = $pa->whoIsLogged();
$username = $dati['username'];

//informazioni sull'immagine caricata
$max_size = 102400; //dimensioni massime in byte dell'immagine da caricare
$tmp      = $_FILES['image']['tmp_name'];
if(!function_exists('mime_content_type'))
$type     = $_FILES['image']['type'];
else 
$type     = mime_content_type($tmp);
$size     = $_FILES['image']['size'];  
  
//controllo delle estensioni accettate  
function check_ext($tipo){
 switch ($tipo) {
  case "image/png":
  return true;
  break;
  case "image/jpg":
  return true;
  break;
  case "image/jpeg":
  return true;
  break;
  case "image/gif":
  return true;
  break;
  default:
  return false;
  break;
 }
}

//estensione dell'immagine
function get_ext($tipo) {
 switch ($tipo) {
  case "image/png":
  return ".png";
  break;
  case "image/jpg":
  return ".jpg";
  break;
  case "image/jpeg":
  return ".jpg";
  break;
  case "image/gif":
  return ".gif";
  break;
  default:
  return false;
  break;
 }
}

//gestione degli errori
function get_error($tmp, $type, $size, $max_size){
    if (!is_uploaded_file($tmp)) {
  $_SESSION['message'] = 'File caricato in modo non corretto';
    }
    else if (!check_ext($type)) {
  $_SESSION['message'] = 'Estensione del file non ammessa';
    }
    else if($size > $max_size) {
        $_SESSION['message'] = 'Dimensione del file troppo grande';
    }
}


//caricamento nuova immagine
if (is_uploaded_file($tmp) && check_ext($type) && $size <= $max_size) {
    $ext     = get_ext($type);
    $newfoto = $qfolder . "/avatar-" . $username . $ext;
    if (move_uploaded_file($tmp, $newfoto)) {
        $_SESSION['message'] = '<span>Immagine caricata con succcesso</span>';
    } else {
        $_SESSION['message'] = 'Non è stato possibile caricare l\'immagine';

    }
} else {
    get_error($tmp, $type, $size, $max_size);
}

//ritorno alla pagina contenente il form per l'upload
header('Location: ' . $_SERVER['HTTP_REFERER']);
?>
Il codice è completamente commentato per rendere più agevole la sua comprensione. Sono personalizzabili le dimensioni massime e le estensioni accettate ed anche i messaggi di errore.
Per utilizzare questo codice occorre incollarlo in un file creato con Notepad++ o il Blocco Note, e salvarlo con nome uploadavatar e con estensione .php. I più pigri possono scaricare il file QUI.
Il file uploadavatar.php deve risiedere nella root del sito. Si può allegare al progetto attraverso la scheda Esperto dello stesso Oggetto Codice HTML inserito nella pagina profilo, avendo cura di lasciare vuoto il campo Percorso relativo sul Server, oppure trasferirlo sul server con un programma FTP.

I commenti del guestbook e del blog


Avere un avatar che solo l'utente può vedere è, secondo noi, uno spreco di risorse. Abbiamo provato allora ad associare l'avatar ad un commento che l'utente loggato inserisce nel guestbook e/o nel blog del sito.

Per associare stabilmente l'avatar al commento sono necessarie due condizioni:
1. identificare l'utente loggato grazie all'username
2. memorizzare il percorso dell'immagine nei dati del commento.

Poiché il programma non permette l'inserimento di campi aggiuntivi nel form per l'invio dei commenti, abbiamo pensato di sacrificare il campo Sito Internet, utilizzandolo per memorizzare il percorso assoluto del file immagine. Ovviamente nasconderemo al visitatore questo campo con JavaScript, ma esso risulterà riempito in modo automatico in funzione di chi in quel momento visualizza la pagina: se il visitatore non è un utente loggato, il campo verrà riempito con il percorso corrispondente all'immagine di default.

Questo è il risultato ottenuto:
Nelle Proprietà della pagina che contiene l'Oggetto Guestbook e/o della pagina speciale Blog, scheda Esperto, Codice Personalizzato, Prima della chiusura del tag HEAD, inseriamo questo codice PHP/JS:

<!-- Code by Giorgio C. & MAeSI - quellidelcucuzzolo.blogspot.it
     Please do not remove credit   -->
<?php
$qfolder = $imSettings['general']['public_folder']; 
$qurl = pathCombine(array($imSettings['general']['url'], $qfolder));
$qblog = $_SERVER['PHP_SELF'];
if (strpos($qblog, '/blog/') !== false)
    $qpath = '../';
else
    $qpath = '';
$pa = Configuration::getPrivateArea();
$dati    = $pa->whoIsLogged();
$username = $dati['username'];
$realname = $dati['realname'];
$datiUser = $pa->getUserByUsername($username);  //SOLO EDIZIONE PROFESSIONAL 
$email = $datiUser['email'];      //SOLO EDIZIONE PROFESSIONAL
$avatar = glob($qpath.$qfolder."/avatar-" . $username . ".*"); 
$tsfoto = 0;
if (empty($avatar))
    $foto = $qurl . "/default.png";
else {
    foreach ($avatar as $value) {
        if (filemtime($value) > $tsfoto) {
            $tsfoto  = filemtime($value);
            $fotonew = $value;
        }
    }
    $foto = str_replace("../", "", $fotonew);
    $foto = str_replace($qfolder, $qurl, $foto);
}
?>
<script>
$(document).ready(function() {
    $("input[id$='topic-form-name']").val("<?php echo $realname ?>");
    $('input[id$="topic-form-email"]').val('<?php echo $email ?>'); //SOLO EDIZIONE PROFESSIONAL
    $('input[id$="topic-form-url"]').val('<?php echo $foto ?>').parent().hide();
  $(".topic-comments-user").each(function() {
    var $item = $(this).find("a");
    if ($item.length != 0) {
      var customCampo = $item.attr("href");
      var customNome = $item.contents();
      $item.replaceWith(customNome);
      $(this).prepend("<img class='campoCustomGb' src='" + customCampo + "' alt='avatar' />");
    }
  })
});
</script>

Il codice si occupa di identificare l'eventuale utente loggato, riempire automaticamente i campi del form con Nome completo e E-mail (solo per l'edizione Professional), inserire nel campo nascosto il percorso dell'immagine utilizzata dall'utente come avatar e, infine, visualizzare l'avatar nel relativo commento.


Anche in questo caso chi utilizza l'edizione Evolution deve rimuovere le tre righe di codice con il commento //SOLO EDIZIONE PROFESSIONAL. 

Di seguito al codice precedente, possiamo inserire le regole CSS che gestiscono la formattazione dell'avatar. Noi abbiamo utilizzato regole di stile minimali, ma qui ci si può sbizzarrire:
<style>
.topic-comment:after {
    content: '';
    display: block;
    clear: both;
}
.topic-comments-user img {
    float: left;
    margin-right: 12px;
    width: 64px;
}
</style>
La prima regola scritta è fondamentale poiché interrompe il flusso degli elementi, evitando sovrapposizioni nel caso in cui l'immagine sia più alta del relativo commento.
Se nel sito sono presenti sia il guestbook che il blog è preferibile inserire il codice CSS una volta sola nel progetto, in Impostazioni Avanzate, Statistiche, SEO e Codice, Esperto, Prima della chiusura del tag HEAD.

Si fa presente che il percorso dell'avatar viene memorizzato, per ogni commento, nel database o in un file di testo quindi, se un utente cambia l'immagine del profilo scegliendo una nuova immagine con uguale estensione, tutti i commenti (vecchi e nuovi) visualizzeranno la nuova immagine poiché la nuova immagine sovrascrive sul server quella vecchia; se però un utente dovesse caricare un'immagine con estensione diversa da quella precedentemente utilizzata, solo i nuovi commenti inseriti avranno memorizzato l'estensione della nuova immagine, quindi i vecchi commenti visualizzeranno l'avatar vecchio, i nuovi commenti quello nuovo.


Un grande ringraziamento a Giorgio per tutto il lavoro che ha svolto e ha condiviso e all'autore di questo articolo ispiratore.


Aggiornamento del 10/05/2017

Aggiornato il codice per mantenere sul server avatar dello stesso utente con diversa estensione.