Source for file log.php
Documentation is available at log.php
* Il questo file sono presenti funzioni e procedure per la gestione del log.
* E' possibile vedere la tabella dei log, impostare i filtri, eseguire operazioni di rollback, ecc.
* @desc File di gestione dei log
* @subpackage Administration
* @author M.Marcello Verona
* @copyright 2007 M.Marcello Verona
* @license http://www.gnu.org/licenses/gpl.html GNU Public License
include("../inc/conn.php");
include("../inc/layouts.php");
include("../inc/func.comuni.php");
include("../inc/func.frontend.php");
* Funzione di ripristino.
* Mediante questa funzione è possibile eseguire rollback di operazioni di DELETE e UPDATE
* @todo Fare verifiche sul corretto funzionamento in ambito Postgres
* @param int $id_log ID dell'operazione nel log su cui operare
$q_log= vmsql_query("SELECT op,storico_pre,storico_post,tabella,id_record FROM {$db1['frontend']}.log WHERE id_log=$id_log",$link);
list ($op,$storico_pre,$storico_post,$tabella,$id_record)= vmsql_fetch_row($q_log);
##############################
$sql_update= "UPDATE $tabella SET ";
// PRENDI LA DOCUMENTAZIONE DELLA TABELLA (serve per esprimere i valori null in caso di int o float o double
for($i= 0;$i< count($info_data_type);$i++ ){
$info_cols[$info_column_name[$i]]= $info_data_type[$i];
foreach($array_pre as $campo=> $val){
if( $info_cols[$campo]== 'int' ||
$info_cols[$campo]== 'tinyint' ||
$info_cols[$campo]== 'mediumint' ||
$info_cols[$campo]== 'double' ||
$info_cols[$campo]== 'float'
if($val== '' || $val== null){
$sql_update.= " $campo=$valore,";
openErrorGenerico("Eccezione nella procedura: impossibile completare il ripristino (1)");
$sql_update= substr($sql_update,0,- 1);
$sql_update.= " WHERE $campo_pk='". addslashes($id_record). "'";
rpc_log('ripristino',$tabella,$_SESSION['user']['uid'],$_SESSION['gid'],$id_record,true);
header("Location: ". $_SERVER['PHP_SELF']. "?id_record=$id_record&feed=ok");
header("Location: ". $_SERVER['PHP_SELF']. "?id_record=$id_record&feed=ko");
openErrorGenerico("Eccezione nella procedura: impossibile completare il ripristino (2)");
} // -- FIne ripristino UPDATE
// verifica se esiste un record con il codice del record.
// In pratica il record è rispristinabile se l'ID è libero (ad es. caso autoincrement)
$q_test = vmsql_query("SELECT * FROM $tabella WHERE $campo_pk='$id_record'",$link);
// se esiste esce con errore
openErrorGenerico("Impossibile ripristinare il record. La chiave primaria è usata da un altro record");
$sql_insert= "INSERT INTO $tabella ";
// PRENDI LA DOCUMENTAZIONE DELLA TABELLA (serve per esprimere i valori null in caso di int o float o double
for($i= 0;$i< count($info_data_type);$i++ ){
$info_cols[$info_column_name[$i]]= $info_data_type[$i];
foreach($array_pre as $campo=> $val){
if( $info_cols[$campo]== 'int' ||
$info_cols[$campo]== 'tinyint' ||
$info_cols[$campo]== 'mediumint' ||
$info_cols[$campo]== 'double' ||
$info_cols[$campo]== 'float' ||
$info_cols[$campo]== 'date' ||
$info_cols[$campo]== 'datetime' ||
$info_cols[$campo]== 'timestamp'
if($val== '' || $val== null){
$sql_valori.= $valore. ",";
$sql_campi= substr($sql_campi,0,- 1);
$sql_valori= substr($sql_valori,0,- 1);
$sql_insert.= "($sql_campi) VALUES ($sql_valori)";
rpc_log('ripristino',$tabella,$_SESSION['user']['uid'],$_SESSION['gid'],$id_record,true);
header("Location: ". $_SERVER['PHP_SELF']. "?id_record=$id_record&feed=ok");
header("Location: ". $_SERVER['PHP_SELF']. "?id_record=$id_record&feed=ko");
* @desc Funzione che mostra la pagina con il log
$files= array("sty/admin.css","sty/tabelle.css","js/mostra_nascondi_id.js","sty/log.css");
$files[]= "js/jscalendar/calendar.js";
$files[]= "js/jscalendar/lang/calendar-it.js";
$files[]= "js/jscalendar/calendar-setup.js";
$files[]= "sty/jscalendar/calendar-win2k-cold-1.css";
echo "<div id=\"briciole\"><a href=\"index.php\">home amministrazione</a> » log database</div>\n";
echo "<h1>Log operazioni sul database</h1>\n";
$ORDER= isset ($_GET['or']) ? (int) $_GET['or']: "data";
$SORT= isset ($_GET['s']) ? $_GET['or']: "DESC";
$colore_tab = " class=\"arancio\"";
$val_op= array('insert'=> 0,'update'=> 0,'delete'=> 0,'ripristino'=> 0,'duplicazione'=> 0);
// Impostazioni per i filtraggi SQL
if(isset ($_GET['uid']) && $_GET['uid']!= ''){
$clausola_uid= "AND log.uid='". intval($_GET['uid']). "'";
$val_uid=(int) $_GET['uid'];
$clausola_uid= ''; $class_uid= ''; $val_uid= '';
if(isset ($_GET['op']) && $_GET['op']!= ''){
$clausola_op= "AND log.op='". addslashes($_GET['op']). "'";
$clausola_op= ''; $class_op= ''; }
if(isset ($_GET['data_dal']) && $_GET['data_dal']!= 'Tutte' && $_GET['data_dal']!= ''){
$clausola_data1= "AND log.data>'". addslashes($_GET['data_dal']). "'";
$val_data1= $_GET['data_dal'];
$QS.= "&data_dal=". $_GET['data_dal'];
$clausola_data1= ''; $class_data= ''; $val_data1= 'Tutte';
if(isset ($_GET['data_al']) && $_GET['data_al']!= 'Tutte' && $_GET['data_al']!= ''){
$clausola_data2= "AND log.data<'". addslashes($_GET['data_al']). "'";
$val_data2= $_GET['data_al'];
$QS.= "&data_al=". $_GET['data_al'];
$clausola_data2= ''; $class_data= ''; $val_data2= 'Tutte';
if(isset ($_GET['tabella']) && $_GET['tabella']!= '') {
$clausola_tabella= "AND log.tabella='". addslashes($_GET['tabella']). "'";
$class_tabella = $colore_tab;
$val_tabella= $_GET['tabella'];
$QS.= "&tabella=". $_GET['tabella'];
} else{ $clausola_tabella= ''; $class_tabella= ""; $val_tabella= ''; }
// se non ci sono filtri nascondi le opzioni filtri mostra
$mostra_filtri = ($clausola_uid . $clausola_op . $clausola_data1 . $clausola_data2 . $clausola_tabella == '') ?
"display:none" : "display:";
$LIMIT= isset ($_GET['l']) ? (int) $_GET['l']: $PASSO;
$OFFSET= isset ($_GET['of']) ? (int) $_GET['of']: 0;
FROM {$db1['frontend']}.log
INNER JOIN {$db1['frontend']}.utente AS u ON u.id_utente=log.uid
INNER JOIN {$db1['frontend']}.gruppo AS g ON u.gid=g.gid
$sql_log = "SELECT log.id_log,
". concat_sintax("log.gid, ' (',g.nome_gruppo,')'", 'gruppo_desc'). ",
FROM {$db1['frontend']}.log
INNER JOIN {$db1['frontend']}.utente AS u ON u.id_utente=log.uid
INNER JOIN {$db1['frontend']}.gruppo AS g ON u.gid=g.gid
$inizio_set = $OFFSET + 1;
$fine_set= (($OFFSET+ $LIMIT)< $TOT) ? $OFFSET+ $LIMIT : $TOT;
if($OFFSET> $TOT) $OFFSET= $TOT;
$str_filtrato = (trim($clausola_uid.
$clausola_istituto)!= '') ? "<span class=\"grigio\">(filtrati)</span>" : "";
echo "<p>Operazioni $inizio_set - $fine_set di <strong>$TOT</strong> $str_filtrato</p>\n";
$PAG= "<div id=\"paginazione\">\n";
$PAG.= "<a href=\"". $_SERVER['PHP_SELF']. "?of=". ($OFFSET- $PASSO). $QS . "\">< < indietro</a>\n | ";
$PAG.= "<span class=\"pag\">< < indietro</span>\n | ";
$n_pagine = ceil($TOT/ $PASSO);
for($i= 0;$i< $n_pagine;$i++ ){
$PAG.= " ". ($i+ 1). " \n | ";
$PAG.= " <a href=\"". $_SERVER['PHP_SELF']. "?of=". ($PASSO* $i). $QS . "\">". ($i+ 1). "</a>\n | ";
if($OFFSET+ $PASSO>= $TOT){
$PAG.= "<span class=\"pag\">avanti > > </span>\n | ";
$PAG.= "<a href=\"". $_SERVER['PHP_SELF']. "?of=". ($OFFSET+ $PASSO). $QS . "\">avanti > > </a>\n | ";
// PRENDI LE TABELLE ESISTENTI SUL LOG
$q_tab_log= vmsql_query("SELECT DISTINCT tabella FROM {$db1['frontend']}.log ORDER BY tabella",$link);
// PRENDI GLI UTENTI ESISTENTI SUL LOG
$q_tab_ut= vmsql_query("SELECT DISTINCT log.uid, ". concat_sintax("log.uid,' - ',u.cognome,' ',u.nome", 'uidnomecognome'). "
FROM {$db1['frontend']}.log , {$db1['frontend']}.utente as u
WHERE u.id_utente=log.uid
ORDER BY uidnomecognome",$link);
$FILTRI= "<p><span class=\"fakelink\" onclick=\"mostra_nascondi('filtri_log');\"><strong>Filtri sul log</strong></span></p>\n";
<div id=\"filtri_log\" style=\"$mostra_filtri;\">
<form action=\"". $_SERVER['PHP_SELF']. "\" method=\"get\">
<fieldset style=\"margin:5px 20px 20px 0px; width:60%;\">
<label for=\"op\">Tipo di operazione:</label>
<select name=\"op\" id=\"op\">
<option value=\"\">Tutte le operazioni</option>\n";
for($i= 0;$i< count($ar_op);$i++ ){
$sel_op = ($val_op[$ar_op[$i]]== 1) ? "selected=\"selected\"" : "";
<option value=\"". $ar_op[$i]. "\" $sel_op>". $ar_op[$i]. "</option>
<label for=\"op\">Tabella:</label>
<select name=\"tabella\" id=\"tabella\">
<option value=\"\">Tutte le tabelle</option>
for($i= 0;$i< count($tabelle);$i++ ){
$sel_tabella = ($tabelle[$i]== $val_tabella) ? " selected=\"selected\"" : "";
$FILTRI.= "<option value=\"". $tabelle[$i]. "\" $sel_tabella>". $tabelle[$i]. "</option>\n";
<label for=\"uid\">Utente:</label>
<select name=\"uid\" id=\"uid\">
<option value=\"\">Tutti gli utenti</option>
for($i= 0;$i< count($utenti);$i++ ){
$sel_utenti = ($id_utenti[$i]== $val_uid) ? " selected=\"selected\"" : "";
$FILTRI.= "<option value=\"". $id_utenti[$i]. "\" $sel_utenti>". $utenti[$i]. "</option>\n";
<label>Data:</label><br />
dal: <input type=\"text\" name=\"data_dal\" id=\"data_dal\" value=\"$val_data1\" /> al <input type=\"text\" name=\"data_al\" id=\"data_al\" value=\"$val_data2\" />
<script type=\"text/javascript\">
inputField : \"data_dal\", // id of the input field
ifFormat : \"%Y-%m-%d %H:%M\", // format of the input field
inputField : \"data_al\", // id of the input field
ifFormat : \"%Y-%m-%d %H:%M\", // format of the input field
<input type=\"button\" onclick=\"submit();\" name=\"filtra\" value=\" Filtra i log \" />
<input type=\"button\" onclick=\"reset();getElementById('tabella').options[0].selected=true;getElementById('op').options[0].selected=true;getElementById('uid').options[0].selected=true;submit();\" name=\"rimuovi\" value=\" Rimuovi tutti i filtri\" />
#########################################################################
echo "<table class=\"tab-color\" summary=\"Tabella Log\">
<th$class_op>operazione</th>
<th$class_tabella>tabella</th>
case 'insert' : $colore= "#EFFFEF"; break;
case 'update' : $colore= "#FFFBEF"; break;
case 'delete' : $colore= "#FFEFEF"; break;
<tr class=\"colore-". $RSlog['op']. "\" >
<td>". $data['ita']. "</td>
<td>". $RSlog['op']. "</td>
<td>". $RSlog['tabella']. "</td>
<td>". $RSlog['nomecognome']. "</td>
<td>". $RSlog['gruppo_desc']. "</td>
<td>". $RSlog['id_record']. "</td>
<td>". $RSlog['fonte']. "</td>
<td><a href=\"log.php?dettaglio=". $RSlog['id_log']. "\">dettaglio</a></td>
<td><a href=\"log.php?id_record=". $RSlog['id_record']. "\">storico</a></td>
* Qualora il record sia stato creato e gestito dalle maschere,
* viene riportata tutta la sua storia: inserimento, modifiche, etc.
* @desc Mostra lo storico di un dato record.
$files= array("sty/admin.css","sty/tabelle.css","js/mostra_nascondi_id.js","sty/log.css");
$ID_RECORD = (int) $_GET['id_record'];
echo "<div id=\"briciole\"><a href=\"index.php\">home amministrazione</a> » <a href=\"log.php\">log database</a> » storico record</div>\n";
echo "<h1>Storico del record</h1>\n";
$sql_log = "SELECT log.id_log,
". concat_sintax("log.gid, ' (',g.nome_gruppo,')'", 'gruppo_desc'). ",
FROM {$db1['frontend']}.log
INNER JOIN {$db1['frontend']}.utente AS u ON u.id_utente=log.uid
INNER JOIN {$db1['frontend']}.gruppo AS g ON u.gid=g.gid
AND log.id_record=$ID_RECORD
#########################################################################
echo "<table class=\"tab-color\" summary=\"Tabella Log\">
<th class=\"grigia\">data</th>
<th class=\"grigia\">operazione</th>
<th class=\"grigia\">tabella</th>
<th class=\"grigia\">utente</th>
<th class=\"grigia\">gruppo</th>
<th class=\"grigia\">id_record</th>
<th class=\"grigia\">fonte</th>
<th class=\"grigia\">dettaglio</th>
<tr class=\"colore-". $RSlog['op']. "\" >
<td>". $data['ita']. "</td>
<td>". $RSlog['op']. "</td>
<td>". $RSlog['tabella']. "</td>
<td>". $RSlog['nomecognome']. "</td>
<td>". $RSlog['gruppo_desc']. "</td>
<td>". $RSlog['id_record']. "</td>
<td>". $RSlog['fonte']. "</td>
<td><a href=\"log.php?dettaglio=". $RSlog['id_log']. "\">dettaglio</a></td>
* Funzione di parsing delle istruzioni UPDATE
* Restituisce un array con chiave tabella e un array modifiche con campo=>valore inserito
* @param string $sql SQL da analizzare
* @return array Array con frammenti di SQL
preg_match("# *UPDATE +([a-z_]+) +SET(.+?) WHERE +(.+) *#i",$sql,$sql_frag);
$out['tabella']= trim($sql_frag[1]);
// MODIFICA DI COMODO PER IL PARSING CORRETTO DELLA VIRGOLA
$sql_frag[2]= preg_replace("|([\w.-])', '?|","$1[@]",$sql_frag[2]);
for($i= 0;$i< count($modifiche);$i++ ){
$t_modifiche= explode("=",$modifiche[$i],2);
$t_modifiche[1]= trim($t_modifiche[1]);
if(substr($t_modifiche[1],0,1)== "'"){
$t_modifiche[1]= substr($t_modifiche[1],1);
if(substr($t_modifiche[1],- 1,1)== "'"){
$t_modifiche[1]= substr($t_modifiche[1],0,- 1);
$arr_modifiche[trim($t_modifiche[0])]= $t_modifiche[1];
$out['modifiche']= $arr_modifiche;
* Funzione di parsing delle istruzioni INSERT
* Restituisce un array con chiave tabella e un array campo=>valore
* @param string $sql SQL da analizzare
* @return array Array con associazione di campi e valori
preg_match("| *INSERT +INTO +([a-z_]+) +\((.+?)\) VALUES +\('?(.+?)'?\)|i",$sql,$sql_frag);
$out['tabella']= trim($sql_frag[1]);
* Funzione per identificare se un dato record è presente in tabella
* @todo Funzione non sviluppata qui
$q= vmsql_query("SELECT * FROM $tabella WHERE $campo_pk='$id_record'");
* Raccoglie informazioni sull'operazione
* presente nel log e restituisce un array con la tabella HTML generata
* e una variabile boolean per la reversibilità dell'operazione
* @param resource $RS Recordset
* @return array Array con la tabella HTML generata e una variabile boolean per la reversibilità dell'operazione
* @see function mostra_dettaglio_log
$presenza_id = (intval($RS['id_record'])> 0 || strlen($RS['id_record'])> 2);
$fonte = ($RS['fonte']== "m") ? 'maschera': 'sottomaschera';
if($storico_pre && $storico_post && $presenza_id){
if(vmsql_test_id($link,$campo_pk,$RS['id_record'],$RS['tabella'],'',true)){
$reversibile= "<span class=\"verde\">reversibile</span>\n";
$reversibile= "<span class=\"rosso\">irreversibile</span> (<strong>il dato è stato eliminato</strong>, ripristinare prima l'operazione di DELETE)\n";
$reversibile= "<span class=\"rosso\">irreversibile</span>\n";
$reversibile= "<span class=\"verde\">reversibile (è sufficiente eliminare il record)</span>\n";
$reversibile= "<span class=\"verde\">reversibile (reinserimento)</span>\n";
$reversibile= "<span class=\"rosso\">irreversibile</span>\n";
<table id=\"info_log\" summary=\"informazioni sull'operazione\" border=\"1\">
<th colspan=\"2\" style=\"text-align:left\"><h3>Riepilogo <span class=\"var\">". strtoupper($RS['op']). "</span></h3></th>
<td>". $RS['id_log']. "</td>
<td>". $RS['tabella']. "</td>
<td>". $RS['id_record']. "</td>
<th>reversibilità</th>
<td>". $reversibile. "</td>
<th>autore operazione</th>
<th>informazioni browser</th>
return array('table'=> $info_operazione,'rev'=> $is_reversibile);
* @desc Funzione che mostra la pagina di dettaglio per una operazione di log
* @param int $id_log ID dell'operazione da mostrare
// PRENDI IL DETTAGLIO DEL LOG
FROM {$db1['frontend']}.log
INNER JOIN {$db1['frontend']}.utente ON log.uid=utente.id_utente
WHERE id_log=$id_log",$link);
// CASO QUERY DI MODIFICA
if(count($parse_sql)== 0){
$OUT.= "Errore di lettura del record";
// Tabella di comparazione:
<h2>Tabella di comparazione record</h2>
<p>Sono evidenziati in giallo i campi che hanno subito modifiche in questa operazione.</p>
<table border=\"1\" summary=\"tabella comparazione\" id=\"tabella-comparazione\">\n";
<th>valore modificato</th>
foreach($storico_pre as $campo=> $valore_old){
if($valore_old== '' || $valore_old== null) $valore_old = "<em class=\"null_old\">Null</em>";
if(isset ($parse_sql['modifiche'][$campo])){
$valore_new = "<span class=\"modificato_new\">". htmlentities(stripslashes($parse_sql['modifiche'][$campo]),ENT_QUOTES). "</span>";
$valore_old = "<span class=\"modificato_old\">". stripslashes($valore_old). "</span>";
$classe_tr= " class=\"evidenza\"";
$valore_new = $valore_old;
$classe_new = " class=\"intatto\"";
$valore_old = "<span class=\"intatto_old\">". $valore_old. "</span>";
$OUT.= "<tr $classe_tr>\n";
$OUT.= "<td class=\"campo\">". $campo. "</td>\n";
$OUT.= "<td>". $valore_old. "</td>\n";
$OUT.= "<td $classe_new>". $valore_new. "</td>\n";
// PROCEDURA DI RIPRISTINO IN CASO UPDATE
$OUT.= "<br /><form action=\"". $_SERVER['PHP_SELF']. "?ripristino=1&type=update\" method=\"post\">
<input type=\"hidden\" name=\"id_log\" value=\"$id_log\" />
<input type=\"button\" onclick=\"submit();\" name=\"ripristino_op\" value=\" Ripristina questa operazione \" />
} // CASO QUERY DI INSERT
else if($RS['op']== 'insert'){
// Tabella di comparazione:
<table border=\"1\" summary=\"tabella comparazione\" id=\"tabella-comparazione\">\n";
for($i= 0;$i< count($parse_sql['campi']);$i++ ){
if($valore_new== '' || $valore_new== null) $valore_new = "<em class=\"null_old\">Null</em>";
$valore = "<span class=\"intatto_old\">". $valore_new. "</span>";
$OUT.= "<tr $classe_tr>\n";
$OUT.= "<td class=\"campo\">". $parse_sql['campi'][$i]. "</td>\n";
$OUT.= "<td>". $valore. "</td>\n";
else if($RS['op']== 'delete'){
// Tabella di comparazione:
<h2>Record eliminato</h2>
<table border=\"1\" summary=\"tabella comparazione\" id=\"tabella-comparazione\">\n";
foreach($storico_pre as $campo=> $valore_old){
if($valore_old== '' || $valore_old== null) $valore_old = "<em class=\"null_old\">Null</em>";
if(isset ($parse_sql['modifiche'][$campo])){
$valore_new = "<span class=\"modificato_new\">". htmlentities($parse_sql['modifiche'][$campo]). "</span>";
$valore_old = "<span class=\"modificato_old\">". $valore_old. "</span>";
$classe_tr= " class=\"evidenza\"";
$valore_new = $valore_old;
$classe_new = " class=\"intatto\"";
$valore_old = "<span class=\"intatto_old\">". $valore_old. "</span>";
$OUT.= "<tr $classe_tr>\n";
$OUT.= "<td class=\"campo\">". $campo. "</td>\n";
$OUT.= "<td>". $valore_old. "</td>\n";
// PROCEDURA DI RIPRISTINO IN CASO DELETE
$OUT.= "<br /><form action=\"". $_SERVER['PHP_SELF']. "?ripristino=1&type=delete\" method=\"post\">
<input type=\"hidden\" name=\"id_log\" value=\"$id_log\" />
<input type=\"button\" onclick=\"submit();\" name=\"ripristino_op\" value=\" Ripristina questa operazione \" />
else if($RS['op']== 'duplicazione'){
// Tabella di comparazione:
<h2>Record duplicato</h2>
// prendi le informazioni
$info_duplicazione= str_replace("DUPLICAZIONE ","",$RS['storico_post']);
$OUT.= "<p>Duplicazione del record della tabella ". str_replace(":",", ID:",$info_duplicazione). "</p>";
echo openLayout1("Dettaglio log Database", array("sty/admin.css","sty/tabelle.css","sty/log.css"));
echo "<div id=\"briciole\"><a href=\"index.php\">home amministrazione</a> » <a href=\"log.php\">log database</a> » dettaglio</div>\n";
echo "<h1>Dettaglio log </h1>\n";
if(isset ($_POST['id_log']) && isset ($_GET['ripristino'])){
$id_log = (int) $_POST['id_log'];
else if(isset ($_GET['dettaglio']) && (intval($_GET['dettaglio'])> 0)){
else if(isset ($_GET['id_record']) && (intval($_GET['id_record'])> 0)){
|