Classe php la gestione delle visite

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Ciao a tutti,
inauguro questa sezione pubblicando una classe per la gestione delle visite
La classe può essere implementata con la ricerca per data o con la geolocalizzazione per esempio
Manca completamente una gestione degli errori
La classe cmq è abbastanza commentata non dovreste avere difficoltà, al massimo chiedete pure

Ho preparato un esempio funzionante (spero) online a questo indirizzo, la stessa pagina registrerà la visita e mostrerà la tabella statistiche

Iniziamo, occorrono tre tabelle
- agent
memorizziamo gli user agent degli utenti per rispoarmiare spazio sul database
Codice:
CREATE TABLE IF NOT EXISTS `agent` (
  `idAgent` int(11) NOT NULL AUTO_INCREMENT,
  `agent` varchar(255) NOT NULL,
  PRIMARY KEY (`idAgent`),
  KEY `agent` (`agent`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
- pagine
per lo stesso motivo cui sopra memorizziamo i nomi delle pagine. Ho gia inserito una pagina di test
Codice:
CREATE TABLE IF NOT EXISTS `pagine` (
  `idPagina` int(11) NOT NULL AUTO_INCREMENT,
  `nome` varchar(155) NOT NULL,
  PRIMARY KEY (`idPagina`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

INSERT INTO `pagine` (`idPagina`, `nome`) VALUES
(1, 'Pagina di test');
- visite
verranno memorizzati tutti i dati necessari della visita ricevuta.
Codice:
CREATE TABLE IF NOT EXISTS `visite` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(155) NOT NULL,
  `idAgent` int(11) NOT NULL,
  `data` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `lingua` varchar(2) NOT NULL,
  `referer` varchar(255) NOT NULL,
  `idPagina` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `data` (`data`),
  KEY `idPagina` (`idPagina`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
Passiamo alla classe. Vi ricordo che non è completa e che probabilmente la aggiornerò piu avanti seguendo i vostri consigli
PHP:
<?php

/**
 * 03 settembre 2013
 * @criric
 * licenza free
 * fatene quello che volete, tenete conto che la classe non è completa 
 */
class Visite {

    // oggetto mysqli
    var $sql;
    // date per la ricerca
    var $dal;
    var $al;

    /**
     * Nel costruttore istanzio la classe per la connessione al database
     * Setto le proprietà per il periodo di ricerca
     * Non ancora implementato ma prevede date ricevute tramite POST
     */
    public function __construct() {
        // istanzio la classe per la connessione al database
        $this->sql = new mysqli("localhost", "root", "", "database");        
        // Setto le proprietà per il periodo di ricerca
        $this->dal = date("Y-m-") . "01";
        // se settata la data in POST
        if (isset($_POST['dal'])) {
            $this->dal = $_POST['dal'];
        }
        $this->al = date("Y-m-d");
        // se settata la data in POST
        if (isset($_POST['al'])) {
            $this->al = $_POST['al'];
        }
    }

    /**
     * sfrutto il distruttore per chiudere la connessione al db
     */
    public function __destruct() {
        $this->sql->close();
    }

    /**
     * Questo metodo registra la visita nella tabella visite
     * Prende come parametro l'id della pagina
     * Non implementata la gestione degli errori
     * @param type $idPagina
     * @return type boolean
     */
    public function salva_visita($idPagina) {
        // recupero il link da dove è arrivato il visitatore
        $referer = (isset($_SERVER["HTTP_REFERER"])) ? $_SERVER["HTTP_REFERER"] : "n/d";
        // richiamo il metodo per l'agent
        $idAgent = $this->id_agent();
        // query di inserimento
        $query = "INSERT INTO visite 
                              SET ip = '" . $_SERVER["REMOTE_ADDR"] . "',
                                  idAgent = '" . $idAgent . "',
                                  lingua = '" . substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2) . "',
                                  referer = '" . $referer . "',
                                  idPagina = '" . $idPagina . "'";
        // eseguo
        if (!$this->sql->query($query)) {
            // da implementare la gestione degli errori
            $error = $this->sql->error;
            return false;
        }
        // tutto ok
        return true;
    }

    /**
     * Per risparmiare spazio sul db 
     * questo metodo verifica se l'agent del visitatore è gia memorizzato nella tabella agent
     * Restituisce l'id corrispondente
     * @return type int
     */
    private function id_agent() {
        // cerco l'agent nella tabella agent
        $query = "SELECT idAgent FROM agent WHERE agent = '" . $_SERVER["HTTP_USER_AGENT"] . "'";
        // eseguo la query
        $result = $this->sql->query($query);
        // se trovo un risultato
        if ($result && $result->num_rows > 0) {
            $row = $result->fetch_row();
            // restituisco l'id corrispondente
            return $row[0];
        }
        // altrimenti inserisco in tabella il nuovo agent
        $query = "INSERT INTO agent SET agent = '" . $_SERVER["HTTP_USER_AGENT"] . "'";
        if ($this->sql->query($query)) {
            // restituisco l'id corrispondente
            return $this->sql->insert_id;
        }
        // qualcosa è andato storto : da implementare uina gestione per gli errori
        return false;
    }

    /**
     * Questo metodo restituisce il numero di record per la ricerca passata nei parametri
     * Usa le proprieta per il periodo di ricerca
     * @param type $pagina boolean 
     * @param type $uniche boolean se true raggruppa per ip
     * @return type int
     */
    public function conta_visite($pagina = false, $uniche = false) {
        $query = "SELECT id
                        FROM visite 
                        WHERE data BETWEEN '" . $this->dal . "' AND DATE_ADD('" . $this->al . "', INTERVAL 1 DAY)";
        if ($pagina) {
            $query .= " && idPagina = '" . $pagina . "'";
        }
        if ($uniche) {
            $query .= " GROUP BY ip";
        }
        $result = $this->sql->query($query);
        if ($result) {
            return $result->num_rows;
        }
        // qualcosa è andato storto : da implementare uina gestione per gli errori
        return false;
    }

    /**
     * Potrebbe essere necessario nascondere parte dell'ip
     * questo metodo nasconde le ultime due parti dell'ip passato come parametro
     * @param type $ip
     * @return string 
     * 
     */
    private function nascondi_ip($ip) {
        $ex = explode(".", $ip);
        $return = $ex[0] . "." . $ex[1] . ".";
        for ($i = 0; $i < strlen($ex[2]); $i++) {
            $return .= "*";
        }
        $return .= ".";
        for ($i = 0; $i < strlen($ex[3]); $i++) {
            $return .= "*";
        }
        return $return;
    }

    /**
     * Questo metodo stampa la tabella delle visite
     * Usa le proprieta per il periodo di ricerca
     * Usa i dati ricevuti in post per filtrare la ricerca
     * Implementata la paginazione
     * @param type $pagina 
     */
    public function tabella_visite() {
        // imposto l'id pagina a false per visualizzare tutti i record
        // non implementata la ricerca per altre pagine
        $idPagina = false;
        // verifico se è settata una pagina in particolare
        if (isset($_POST['id_pag'])) {
            $idPagina = (int) $_POST['id_pag'];
            // se id pagina è arrivato in forma corretta
            if ((int) $_POST['id_pag'] > 0) {
                // setto l'id pagina per la ricerca
                $idPagina = (int) $_POST['id_pag'];
            }
        }
        // imposto la prima pagina da visualizzare
        $num_pag = 1;
        // verifico che sia settata la pagina da visualizzare
        if (isset($_POST['num_pag'])) {
            $num_pag = (int) $_POST['num_pag'];
            // se la pagina è arrivata in forma corretta
            if ((int) $_POST['num_pag'] > 0) {
                // setto la prima pagina
                $num_pag = (int) $_POST['num_pag'];
            }
        }
        // imposto il limite di risultati per pagina
        $limite_pag = 10;
        // verifico se settato il limite per pagina
        if (isset($_POST['limit'])) {
            // se il limite è arrivato in forma corretta
            if ((int) $_POST['limit'] > 0) {
                // reimposto il limite di risultati per pagina
                $limite_pag = (int) $_POST['limit'];
            }
        }
        // imposto il limite minimo da usare nella query
        if ($num_pag <= 1) {
            $limite_min = 0;
        } else {
            $limite_min = ($num_pag - 1) * $limite_pag;
        }
        // imposto il limite massimo sul quale finirà la ricerca
        $limite_max = $limite_min + $limite_pag;
        // recupero il numero totale di visite
        $totali = $this->conta_visite($pagina);
        // recupero il numero di visite uniche
        $uniche = $this->conta_visite($pagina, true);
        // se il limite massimo supera i record totali lo fermo al numero di record totali
        if ($totali <= $limite_max) {
            $limite_max = $totali;
        }
        // recupero il numero di pagine totali
        $pagine = ceil($totali / $limite_pag);
        // query di ricerca
        $query = "SELECT V.lingua, V.ip, A.agent, V.referer,
                IF(P.nome IS NULL, 'n/d', P.nome) as nomePagina,
                DATE_FORMAT(V.data, '%d/%m/%Y %H:%i:%s') as data
                FROM visite V
                LEFT JOIN pagine P USING(idPagina)
                JOIN agent A USING(idAgent)
                WHERE data BETWEEN '" . $this->dal . "' AND DATE_ADD('" . $this->al . "', INTERVAL 1 DAY)";
        if ($idPagina) {
            $query .= " && pagina = '" . $idPagina . "'";
        }
        $query .= " ORDER BY data DESC LIMIT $limite_min, $limite_pag";
        // eseguo
        $result = $this->sql->query($query);

        echo "<form method='post' action='" . $_SERVER['PHP_SELF'] . "' > ";
        echo "<table>";
        echo "<thead>";
        echo "<tr class='filtri'>";
        echo "<td colspan='7'>";
        echo "Report visite dal " . $this->format_data_it($this->dal) . " al " . $this->format_data_it($this->al);
        echo "<input type='hidden' name='num_pag' value='1'/>";
        echo "</td>";
        echo "</tr>";
        // se la query ha prodotto dei riultati
        if ($result->num_rows > 0) {
            echo "<tr><td colspan='7'>";
            echo "<span class='fleft'>";
            echo "Totale visite  :  $totali Uniche : " . $uniche;
            echo "</span>";
            echo "<span class='fright'>";
            echo "Record per pagina <select name='limit' onchange='this.form.submit()'>";
            for ($i = 5; $i <= 50; $i+=5) {
                echo "<option value='$i' ";
                if ($i == $limite_pag)
                    echo " selected='selected'";
                echo ">$i</option>";
            }
            echo "</select>";
            echo "</span>";
            echo "</td></tr>";
            echo "<tr>";
            echo "<th>Data</th>";
            echo "<th>Pagina</th>";
            echo "<th>Sistema operativo</th>";
            echo "<th>Browser</th>";
            echo "<th>Lingua</th>";
            echo "<th>Ip</th>";
            echo "<th>Referer</th>";
            echo "</tr>";
            echo "</thead>";
            echo "<tbody>";
            $i = 0;
            while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
                $alternate = ($i % 2 == 0) ? "class='alternate'" : "";
                echo "<tr $alternate>";
                echo "<td>" . $row["data"] . "</td>";
                echo "<td>" . $row["nomePagina"] . "</td>";
                echo "<td>" . $this->sistema_operativo($row["agent"]) . "</td>";
                echo "<td>" . $this->browser($row["agent"]) . "</td>";
                echo "<td class='center'>" . $row["lingua"] . "</td>";
                echo "<td>" . $this->nascondi_ip($row["ip"]) . "</td>";
                echo "<td class='center info' title='" . $row["referer"] . "'> ? </td>";
                echo "</tr>";
                $i++;
            }
            echo "<tr>";
            echo "<td colspan='7' class='infopag'>";

            if ($num_pag <= 1) {
                $click = "onclick='return false'";
            } else {
                $click = "onclick='ImpostaPagina(" . ($num_pag - 1) . "," . $limite_pag . ")'";
            }
            echo "<span onclick='ImpostaPagina(1," . $limite_pag . ")' title='prima' class='navpag'>&lt;&lt;</span>";
            echo "<span title='precedente' class='navpag' $click>&lt;</span>";
            echo "<span class='navinfo'>Pagina $num_pag / $pagine</span>";
            if ($num_pag >= $pagine) {
                $click = "onclick='return false'";
            } else {
                $click = "onclick='ImpostaPagina(" . ($num_pag + 1) . "," . $limite_pag . ")'";
            }
            echo "<span title='sucessiva' class='navpag' $click>&gt;</span>";
            echo "<span onclick='ImpostaPagina(" . $pagine . "," . $limite_pag . ")' title='ultima' class='navpag'>&gt;&gt;</span>";
            echo "</td>";
            echo "</tr>";
            echo "</tbody>";
            // altrimenti
        } else {
            // nessun riultato
            echo "<tr><td colspan='7'>Nessun record trovato</td></tr>";
        }
        echo "</table>";
        echo "</form>";
    }

    /**
     * Restituisce la data formattata in italiano 
     * @param stringa $data yyyy-mm-dd hh:ii:ss
     * @param int $ora 1 o 0 mostra o meno l'ora
     * @return stringa 
     */
    private function format_data_it($data, $ora = 1) {

        $split = explode(" ", $data);
        $d = explode("-", $split[0]);
        $d = array_reverse($d);

        if ($ora == 1) {
            return implode("/", $d) . " " . $split[1];
        } else {
            return implode("/", $d);
        }
    }

    /**
     * Estrae dall'agent il sistema operativo
     * è possibile inserire nell'array i sistemi mancanti seguendo la stessa loogica
     * @param type $agent
     * @return type 
     */
    private function sistema_operativo($agent) {
        $so = array(
            'Windows NT 6.2' => 'Windows 8',
            'Windows NT 6.1' => 'Windows 7',
            'Windows NT 6.0' => 'Windows vista',
            'Windows NT 5.1' => 'Windows XP',
            'Windows NT 5.0' => 'Windows 2000',
            'Windows NT 4.90' => 'Windows ME',
            'Win95' => 'Windows 95',
            'Win98' => 'Windows 98',
            'Windows NT 5.2' => 'Windows NET',
            'WinNT4.0' => 'Windows NT',
            'Mac|PPC' => 'Mac',
            'Linux' => 'Linux',
            'FreeBSD' => 'FreeBSD',
            'SunOS' => 'SunOS',
            'Irix' => 'Irix',
            'BeOS' => 'BeOS',
            'OS/2' => 'OS/2',
            'AIX' => 'AIX'
        );
        foreach ($so as $chiave => $valore) {
            if (strstr($agent, $chiave)) {
                return $valore;
            }
        }
        return 'n/d';
    }

    /**
     * Estrae dall'agent il browser
     * è possibile inserire nell'array i browser mancanti seguendo la stessa loogica
     * @param type $agent
     * @return type 
     */
    private function browser($agent) {
        $browser = array(
            "Internet Explorer 9" => "MSIE 9",
            "Internet Explorer 8" => "MSIE 8",
            "Internet Explorer 7" => "MSIE 7",
            "Internet Explorer 6" => "MSIE 6",
            "Internet Explorer" => "MSIE",
            "Chrome" => "Chrome",
            "Mozilla Firefox 23" => "Firefox/23",
            "Mozilla Firefox 20" => "Firefox/20",
            "Mozilla Firefox 8" => "Firefox/8",
            "Mozilla Firefox 7" => "Firefox/7",
            "Mozilla Firefox 6" => "Firefox/6",
            "Mozilla Firefox 5" => "Firefox/5",
            "Mozilla Firefox 4" => "Firefox/4",
            "Mozilla Firefox 3" => "Firefox/3",
            "Mozilla Firefox" => "Firefox",
            "Lynx" => "Lynx",
            "Opera 10" => "Opera/10",
            "Opera 9" => "Opera/9",
            "Opera" => "Opera",
            "Konqueror" => "Konqueror",
            "Safari" => "Safari",
            "GoogleBot" => "Googlebot",
            "BingBot" => "bingbot",
            "W3C" => "W3C"
        );

        foreach ($browser as $chiave => $valore) {
            if (strstr($agent, "$valore")) {
                return $chiave;
            }
        }
        return "n/d";
    }

}

?>
Per far funzionare la paginazione è necessaria una piccola funzione javascript che reimposta i valori della pagina e dei record da visualizzare
HTML:
<script type="text/javascript">
            function ImpostaPagina(pagina,limite){
                document.forms[0].elements['limit'].value = limite;
                document.forms[0].elements['num_pag'].value = pagina;
                document.forms[0].submit();
            }
        </script>
Per registrare correttamente la visita bisogna inserire nella tabella pagine il nome della pagina soggetta alla registrazione delle visite e richiamare il metodo salva_visita(id) passandogli l'id
PHP:
<?php
// includo il file che contiene la classe
include 'visite_class.php';
// istanzio la classe
$visite = new Visite();
// richiamo il metodo passandogli l'id della pagina
$visite->salva_visita(1);
?>
Per visualizzare la tabella delle statistiche è sufficiente richiamare in una pagina il metodo tabella_visite()
PHP:
<?php
// includo il file che contiene la classe
include 'visite_class.php';
// istanzio la classe
$visite = new Visite();
// stampo la tabella visite
$visite->tabella_visite();
?>
Per l'esempio online ho usato il seguente codice css
Codice:
html body {
    text-align: center;
    font-family: Tahoma;
    font-size: 13px;
    color:#456;
}
a {                
    color:#456;
}
table {
    border-collapse: collapse;
    margin:auto;
    box-shadow: 10px 10px 5px #888;
}
table th {
    text-align: left;
    background-color: #4A4A4A;
    color: #FFFFFF;
    font-weight: bold;
    padding: 10px;
}
table td {
    border: 1px solid #D2D2D2;
    padding: 8px 10px 8px 10px;
}
table tr.alternate {
    background-color: #ECECEC;
}
.center {
    text-align: center;
}
.left {
    text-align: left;
}
table td.infopag {
    text-align: center;
    border: none;
    padding: 10px;
}
span.navpag {
    border: 1px solid #D2D2D2;
    border-radius: 4px;
    padding:2px 6px 2px 6px;
    text-decoration: none;
    letter-spacing: -3px;
    cursor:pointer;
    margin: 0 1px 0 1px;
}
span.navinfo {
    margin: 0 8px 0 8px;
}
.info {
    cursor: help;
    font-weight: bold;
}
.fright {
    float: right;
}
.fleft {
    float: left;
}
.filtri {
    font-weight: bold;
}
Che altro aggiungere? :byebye:
 
Ultima modifica:

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Ho aggiornato l'esempio e la classe aggiungendo due metodi per la geolocalizzazione sfruttando un servizio gratuito per webmaster
Ho modificato leggermente la tabella e ho aggiornato i metodi per il riconoscimento del browser e del s.o
Per la geolocalizzazione ho creato una nuova tabella
Codice:
CREATE TABLE IF NOT EXISTS `geoloc` (
  `ip` varchar(155) NOT NULL,
  `data` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `geoloc` text NOT NULL,
  KEY `ip` (`ip`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Mi sono accorto di non aver indicizzato le tabelle sarebbe convienente metter degli indici per velocizzare le ricerche
Riposto la classe aggiornata
PHP:
<?php

/**
 * 03 settembre 2013
 * @criric
 * 05 settembre 2013
 * aggiunti ddue metodi per la geolocalizzazione aggiornati i metodi per riconoscere so e browser
 * 
 * licenza free
 * fatene quello che volete, tenete conto che la classe non è completa 
 */
class Visite {

    // oggetto mysqli
    var $sql;
    // date per la ricerca
    var $dal;
    var $al;

    /**
     * Nel costruttore istanzio la classe per la connessione al database
     * Setto le proprietà per il periodo di ricerca
     * Non ancora implementato ma prevede date ricevute tramite POST
     */
    public function __construct() {
        // istanzio la classe per la connessione al database
        $this->sql = new mysqli("localhost", "root", "", "database");        
        // Setto le proprietà per il periodo di ricerca
        $this->dal = date("Y-m-") . "01";
        // se settata la data in POST
        if (isset($_POST['dal'])) {
            $this->dal = $_POST['dal'];
        }
        $this->al = date("Y-m-d");
        // se settata la data in POST
        if (isset($_POST['al'])) {
            $this->al = $_POST['al'];
        }
    }

    /**
     * sfrutto il distruttore per chiudere la connessione al db
     */
    public function __destruct() {
        $this->sql->close();
    }

    /**
     * Questo metodo registra la visita nella tabella visite
     * Prende come parametro l'id della pagina
     * Non implementata la gestione degli errori
     * @param type $idPagina
     * @return type boolean
     */
    public function salva_visita($idPagina) {
        // richiamo il metodo geoloc
        $this->geoloc();
        // recupero il link da dove è arrivato il visitatore
        $referer = (isset($_SERVER["HTTP_REFERER"])) ? $_SERVER["HTTP_REFERER"] : "n/d";
        // richiamo il metodo per l'agent
        $idAgent = $this->id_agent();
        // query di inserimento
        $query = "INSERT INTO visite 
                              SET ip = '" . $_SERVER["REMOTE_ADDR"] . "',
                                  idAgent = '" . $idAgent . "',
                                  lingua = '" . substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2) . "',
                                  referer = '" . $referer . "',
                                  idPagina = '" . $idPagina . "'";
        // eseguo
        if (!$this->sql->query($query)) {
            // da implementare la gestione degli errori
            $error = $this->sql->error;
            return false;
        }
        // tutto ok
        return true;
    }

    /**
     * Verifica se l'ip è gia presente da meno di una settimana nella tabella geoloc
     * Se non presente
     * frutta un servizio gratuito (http://www.geoplugin.com/) per la geolocalizzazione dell'indirizzo ip
     * inserisce in tabella il nuovo ip con il json ricevuto
     * 
     */
    private function geoloc() {

        // cerco l'ip nella tabella geoloc
        $query = "SELECT ip FROM geoloc 
                         WHERE ip = '" . $ip . "' && data >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
        // eseguo la query
        $result = $this->sql->query($query);
        // se trovo un risultato esco
        if ($result && $result->num_rows > 0) {
            return true;
        }
        // richiamo il servizio di http://www.geoplugin.com/
        $ip = $_SERVER['REMOTE_ADDR'];
        $geo = file_get_contents('http://www.geoplugin.net/json.gp?ip=' . $ip);
        // inserisco i nuovi dati
        $query = "INSERT INTO geoloc SET ip ='$ip',geoloc='" . $this->sql->real_escape_string($geo) . "'";
        // eseguo
        if (!$this->sql->query($query)) {
            // da implementare la gestione degli errori
            $error = $this->sql->error;
            return false;
        }
        // tutto ok
        return true;
    }

    /**
     * Codifica il json in tabella e restituisce la regione o la nazione
     */
    private function info_geoloc($ip) {
        $query = "SELECT geoloc FROM geoloc 
                         WHERE ip = '" . $ip . "' && data >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
        $result = $this->sql->query($query);
        if ($result && $result->num_rows > 0) {
            $row = $result->fetch_row();
            $json = json_decode($row[0]);
            $return = $json->geoplugin_countryName;
            if (!empty($json->geoplugin_region)) {
                $return = $json->geoplugin_region;
            }
            return $return;
        }
        return "n/d";
    }

    /**
     * Per risparmiare spazio sul db 
     * questo metodo verifica se l'agent del visitatore è gia memorizzato nella tabella agent
     * Restituisce l'id corrispondente
     * @return type int
     */
    private function id_agent() {
        // cerco l'agent nella tabella agent
        $query = "SELECT idAgent FROM agent WHERE agent = '" . $_SERVER["HTTP_USER_AGENT"] . "'";
        // eseguo la query
        $result = $this->sql->query($query);
        // se trovo un risultato
        if ($result && $result->num_rows > 0) {
            $row = $result->fetch_row();
            // restituisco l'id corrispondente
            return $row[0];
        }
        // altrimenti inserisco in tabella il nuovo agent
        $query = "INSERT INTO agent SET agent = '" . $_SERVER["HTTP_USER_AGENT"] . "'";
        if ($this->sql->query($query)) {
            // restituisco l'id corrispondente
            return $this->sql->insert_id;
        }
        // qualcosa è andato storto : da implementare uina gestione per gli errori
        return false;
    }

    /**
     * Questo metodo restituisce il numero di record per la ricerca passata nei parametri
     * Usa le proprieta per il periodo di ricerca
     * @param type $pagina boolean 
     * @param type $uniche boolean se true raggruppa per ip
     * @return type int
     */
    public function conta_visite($pagina = false, $uniche = false) {
        $query = "SELECT id
                        FROM visite 
                        WHERE data BETWEEN '" . $this->dal . "' AND DATE_ADD('" . $this->al . "', INTERVAL 1 DAY)";
        if ($pagina) {
            $query .= " && idPagina = '" . $pagina . "'";
        }
        if ($uniche) {
            $query .= " GROUP BY ip";
        }
        $result = $this->sql->query($query);
        if ($result) {
            return $result->num_rows;
        }
        // qualcosa è andato storto : da implementare uina gestione per gli errori
        return false;
    }

    /**
     * Potrebbe essere necessario nascondere parte dell'ip
     * questo metodo nasconde le ultime due parti dell'ip passato come parametro
     * @param type $ip
     * @return string 
     * 
     */
    private function nascondi_ip($ip) {
        $ex = explode(".", $ip);
        $return = $ex[0] . "." . $ex[1] . ".";
        for ($i = 0; $i < strlen($ex[2]); $i++) {
            $return .= "*";
        }
        $return .= ".";
        for ($i = 0; $i < strlen($ex[3]); $i++) {
            $return .= "*";
        }
        return $return;
    }

    /**
     * Questo metodo stampa la tabella delle visite
     * Usa le proprieta per il periodo di ricerca
     * Usa i dati ricevuti in post per filtrare la ricerca
     * Implementata la paginazione
     * @param type $pagina 
     */
    public function tabella_visite() {
        // imposto l'id pagina a false per visualizzare tutti i record
        // non implementata la ricerca per altre pagine
        $idPagina = false;
        // verifico se è settata una pagina in particolare
        if (isset($_POST['id_pag'])) {
            $idPagina = (int) $_POST['id_pag'];
            // se id pagina è arrivato in forma corretta
            if ((int) $_POST['id_pag'] > 0) {
                // setto l'id pagina per la ricerca
                $idPagina = (int) $_POST['id_pag'];
            }
        }
        // imposto la prima pagina da visualizzare
        $num_pag = 1;
        // verifico che sia settata la pagina da visualizzare
        if (isset($_POST['num_pag'])) {
            $num_pag = (int) $_POST['num_pag'];
            // se la pagina è arrivata in forma corretta
            if ((int) $_POST['num_pag'] > 0) {
                // setto la prima pagina
                $num_pag = (int) $_POST['num_pag'];
            }
        }
        // imposto il limite di risultati per pagina
        $limite_pag = 10;
        // verifico se settato il limite per pagina
        if (isset($_POST['limit'])) {
            // se il limite è arrivato in forma corretta
            if ((int) $_POST['limit'] > 0) {
                // reimposto il limite di risultati per pagina
                $limite_pag = (int) $_POST['limit'];
            }
        }
        // imposto il limite minimo da usare nella query
        if ($num_pag <= 1) {
            $limite_min = 0;
        } else {
            $limite_min = ($num_pag - 1) * $limite_pag;
        }
        // imposto il limite massimo sul quale finirà la ricerca
        $limite_max = $limite_min + $limite_pag;
        // recupero il numero totale di visite
        $totali = $this->conta_visite($pagina);
        // recupero il numero di visite uniche
        $uniche = $this->conta_visite($pagina, true);
        // se il limite massimo supera i record totali lo fermo al numero di record totali
        if ($totali <= $limite_max) {
            $limite_max = $totali;
        }
        // recupero il numero di pagine totali
        $pagine = ceil($totali / $limite_pag);
        // query di ricerca
        $query = "SELECT V.lingua, V.ip, A.agent, V.referer,
                IF(P.nome IS NULL, 'n/d', P.nome) as nomePagina,
                DATE_FORMAT(V.data, '%d/%m/%Y %H:%i:%s') as data
                FROM visite V
                LEFT JOIN pagine P USING(idPagina)
                JOIN agent A USING(idAgent)
                WHERE data BETWEEN '" . $this->dal . "' AND DATE_ADD('" . $this->al . "', INTERVAL 1 DAY)";
        if ($idPagina) {
            $query .= " && pagina = '" . $idPagina . "'";
        }
        $query .= " ORDER BY data DESC LIMIT $limite_min, $limite_pag";
        // eseguo
        $result = $this->sql->query($query);
        echo "<form method='post' action='" . $_SERVER['PHP_SELF'] . "' > ";
        echo "<p class='filtri'>";
        echo "Report visite dal " . $this->format_data_it($this->dal) . " al " . $this->format_data_it($this->al);

        echo "</p>";

        echo "<input type='hidden' name='num_pag' value='1'/>";
        echo "<table>";
        echo "<thead>";

        // se la query ha prodotto dei riultati
        if ($result->num_rows > 0) {
            echo "<tr><td colspan='8'>";
            echo "<span class='fleft'>";
            echo "Totale visite  :  $totali Uniche : " . $uniche;
            echo "</span>";
            echo "<span class='fright'>";
            echo "Record per pagina <select name='limit' onchange='this.form.submit()'>";
            for ($i = 5; $i <= 50; $i+=5) {
                echo "<option value='$i' ";
                if ($i == $limite_pag)
                    echo " selected='selected'";
                echo ">$i</option>";
            }
            echo "</select>";
            echo "</span>";
            echo "</td></tr>";
            echo "<tr>";
            echo "<th>Data</th>";
            echo "<th>Pagina</th>";
            echo "<th>Sistema operativo</th>";
            echo "<th>Browser</th>";
            echo "<th>Lingua</th>";
            echo "<th>Ip</th>";
            echo "<th>Geolocation</th>";
            echo "<th>Referer</th>";
            echo "</tr>";
            echo "</thead>";
            echo "<tbody>";
            $i = 0;
            while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
                $alternate = ($i % 2 == 0) ? "class='alternate'" : "";
                echo "<tr $alternate>";
                echo "<td>" . $row["data"] . "</td>";
                echo "<td>" . $row["nomePagina"] . "</td>";
                echo "<td>" . $this->sistema_operativo($row["agent"]) . "</td>";
                echo "<td>" . $this->browser($row["agent"]) . "</td>";
                echo "<td class='center'>" . $row["lingua"] . "</td>";
                echo "<td class='left'>" . $this->nascondi_ip($row["ip"]) . "</td>";
                echo "<td>" . $this->info_geoloc($row["ip"]) . "</td>";
                echo "<td class='center info' title='" . $row["referer"] . "'> ? </td>";
                echo "</tr>";
                $i++;
            }
            echo "<tr>";
            echo "<td colspan='8' class='infopag'>";

            if ($num_pag <= 1) {
                $click = "onclick='return false'";
            } else {
                $click = "onclick='ImpostaPagina(" . ($num_pag - 1) . "," . $limite_pag . ")'";
            }
            echo "<span onclick='ImpostaPagina(1," . $limite_pag . ")' title='prima' class='navpag'>&lt;&lt;</span>";
            echo "<span title='precedente' class='navpag' $click>&lt;</span>";
            echo "<span class='navinfo'>Pagina $num_pag / $pagine</span>";
            if ($num_pag >= $pagine) {
                $click = "onclick='return false'";
            } else {
                $click = "onclick='ImpostaPagina(" . ($num_pag + 1) . "," . $limite_pag . ")'";
            }
            echo "<span title='sucessiva' class='navpag' $click>&gt;</span>";
            echo "<span onclick='ImpostaPagina(" . $pagine . "," . $limite_pag . ")' title='ultima' class='navpag'>&gt;&gt;</span>";
            echo "<span  class='fright'><a href='http://www.geoplugin.com/geolocation/' target='_new'>IP Geolocation</a> by <a href='http://www.geoplugin.com/' target='_new'>geoPlugin</a></span>";
            echo "</td>";
            echo "</tr>";
            echo "</tbody>";
            // altrimenti
        } else {
            // nessun riultato
            echo "<tr><td colspan='8'>Nessun record trovato</td></tr>";
        }
        echo "</table>";
        echo "</form>";
    }

    /**
     * Restituisce la data formattata in italiano 
     * @param stringa $data yyyy-mm-dd hh:ii:ss
     * @param int $ora 1 o 0 mostra o meno l'ora
     * @return stringa 
     */
    private function format_data_it($data, $ora = 1) {

        $split = explode(" ", $data);
        $d = explode("-", $split[0]);
        $d = array_reverse($d);

        if ($ora == 1) {
            return implode("/", $d) . " " . $split[1];
        } else {
            return implode("/", $d);
        }
    }

    /**
     * Estrae dall'agent il sistema operativo
     * è possibile inserire nell'array i sistemi mancanti seguendo la stessa loogica
     * @param type $agent
     * @return type 
     */
    private function sistema_operativo($agent) {
        $so = array(
            'Windows NT 6.2' => 'Windows 8',
            'Windows NT 6.1' => 'Windows 7',
            'Windows NT 6.0' => 'Windows vista',
            'Windows NT 5.1' => 'Windows XP',
            'Windows NT 5.0' => 'Windows 2000',
            'Windows NT 4.90' => 'Windows ME',
            'Win95' => 'Windows 95',
            'Win98' => 'Windows 98',
            'Windows NT 5.2' => 'Windows NET',
            'WinNT4.0' => 'Windows NT',
            'Mac|PPC' => 'Mac',
            'Linux' => 'Linux',
            'FreeBSD' => 'FreeBSD',
            'SunOS' => 'SunOS',
            'Irix' => 'Irix',
            'BeOS' => 'BeOS',
            'OS/2' => 'OS/2',
            'AIX' => 'AIX',
            'bot' => 'bot',
            "W3C" => "W3C"
        );
        foreach ($so as $chiave => $valore) {
            if (strstr($agent, $chiave)) {
                return $valore;
            }
        }
        return 'n/d';
    }

    /**
     * Estrae dall'agent il browser
     * è possibile inserire nell'array i browser mancanti seguendo la stessa loogica
     * @param type $agent
     * @return type 
     */
    private function browser($agent) {
        $browser = array(
            "Internet Explorer 9" => "MSIE 9",
            "Internet Explorer 8" => "MSIE 8",
            "Internet Explorer 7" => "MSIE 7",
            "Internet Explorer 6" => "MSIE 6",
            "Internet Explorer" => "MSIE",
            "Chrome" => "Chrome",
            "Mozilla Firefox 23" => "Firefox/23",
            "Mozilla Firefox 20" => "Firefox/20",
            "Mozilla Firefox 8" => "Firefox/8",
            "Mozilla Firefox 7" => "Firefox/7",
            "Mozilla Firefox 6" => "Firefox/6",
            "Mozilla Firefox 5" => "Firefox/5",
            "Mozilla Firefox 4" => "Firefox/4",
            "Mozilla Firefox 3" => "Firefox/3",
            "Mozilla Firefox" => "Firefox",
            "Python" => "urllib",
            "Curl" => "libcurl",
            "Crawler" => "Crawler",
            "YandexBot" => "YandexBot",
            "Majestic12" => "MJ12",
            "Dataprovider " => "Dataprovider",
            "Lynx" => "Lynx",
            "Opera 10" => "Opera/10",
            "Opera 9" => "Opera/9",
            "Opera" => "Opera",
            "Konqueror" => "Konqueror",
            "Safari" => "Safari",
            "GoogleBot" => "Googlebot",
            "BingBot" => "bingbot",
            "W3C" => "W3C"
        );

        foreach ($browser as $chiave => $valore) {
            if (strstr($agent, "$valore")) {
                return $chiave;
            }
        }
        return "n/d";
    }

}

?>
 
Ultima modifica di un moderatore:

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Rileggendo mi sono accorto che la geolocalizzazione non funzionava correttamente per due piccoli errori nei metodi
riposto i due metodi corretti
PHP:
private function geoloc() {
    // recupero l'ip
    $ip = $_SERVER['REMOTE_ADDR'];
    // cerco l'ip nella tabella geoloc
    $query = "SELECT ip FROM geoloc 
                     WHERE ip = '" . $ip . "' && data >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
    // eseguo la query
    $result = $this->sql->query($query);
    // se trovo un risultato esco
    if ($result && $result->num_rows > 0) {
        return true;
    }
    // richiamo il servizio di http://www.geoplugin.com/

    $geo = file_get_contents('http://www.geoplugin.net/json.gp?ip=' . $ip);
    // inserisco i nuovi dati
    $query = "INSERT INTO geoloc SET ip ='$ip',geoloc='" . $this->sql->real_escape_string($geo) . "'";
    // eseguo
    if (!$this->sql->query($query)) {
        // da implementare la gestione degli errori
        $error = $this->sql->error;
        return false;
    }
    // tutto ok
    return true;
}

private function info_geoloc($ip) {
    $query = "SELECT geoloc FROM geoloc 
                     WHERE ip = '" . $ip . "' ORDER BY data DESC LIMIT 1";
    $result = $this->sql->query($query);
    if ($result && $result->num_rows > 0) {
        $row = $result->fetch_row();
        $json = json_decode($row[0]);
        $return = $json->geoplugin_countryName;
        if (!empty($json->geoplugin_region)) {
            $return = $json->geoplugin_region;
        }
        return $return;
    }
    return "n/d";
}
 

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Ciao Nefyt, questa mi mancava
per ora ho ripulito manualmente anche perchè non ho ben capito come hai fatto :)
in teoria dovrebbe essere sufficiente utilizzare strip_tag() prima dell'inserimento del referer
 

Nefyt

Utente Attivo
17 Apr 2012
1.102
0
0
Beh in pratica li gestisci come $_GET o $_POST, quando vai ad inserire un header per intero rendilo sicuro nella query e poi quando lo vai a stampare utilizza htmlspecialchars() oppure anche strip_tags()



Se vuoi provare da te io ho utilizzato il composer di fiddler2 per mandare la richiesta con parametri personalizzati, comunque puoi tranquillamente farlo anche con curl o jquery o qualunque libreria http
 

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
A seguito dell' "hacking" subito :evil: ho aggiunto un controllo prima dell'inserimento della visita nel metodo salva_visita()
PHP:
// recupero il link da dove è arrivato il visitatore
        $referer = (isset($_SERVER["HTTP_REFERER"])) ? $this->sql->real_escape_string($_SERVER["HTTP_REFERER"]) : "n/d";
e ho ripulito la stringa prima di mandarla in output nel metodo tabella_visite()
PHP:
echo "<td class='center info' title='" . strip_tags($row["referer"]) . "'> ? </td>";
Lascio a voi eventuali altre modifiche per proteggere al meglio il codice
Grazie Nefyt :fonzie:
 
Discussioni simili
Autore Titolo Forum Risposte Data
L php tinymce mi duplica la classe label PHP 3
C [PHP] Estrarre da una classe i valori che mi interessano PHP 5
tucu49 PHP include classe PHP 8
M [PHP] Estendere Connessione a una Classe PHP 1
M [PHP] utilizzo di una classe e delle sue funzioni PHP 2
D [PHP] assegnare una classe PHP 1
W [PHP] Creazione classe PDO PHP 4
D [PHP] chiamata metodi da una classe PHP 3
L [PHP] login con la classe medoo.in PHP 5
macus_adi Classe PHP per la Geolocalizzazione del visitatore Snippet PHP 0
M [wordpress-galleria immagini]Inserire classe php in html PHP 0
L [PHP] Classe che non vede i suoi metodi PHP 3
A [PHP] metodo di una classe per estrarre i dati con ciclo while PHP 1
C [PHP] Metodo di una classe in sltra classe PHP 1
V [PHP] utilizzo di metodi statici in altra classe PHP 5
elpirata [PHP] [RISOLTO] Stampare classe css in base al risultato della query PHP 6
M Assegnare un id o classe a una variabile php PHP 5
C Leggere variabili esterne ad una classe in php 5.2 PHP 6
J [risolto] Trasformare la seguente classe PHP PHP 2
J Creare una classe view php PHP 0
M Classe in php 4 per generare file in Excel PHP 4
T Classe php e proprieta predefinite PHP 8
catellostefano CLASSE PHP Warning: mysql_fetch_assoc() expects parameter 1 to be resource PHP 2
L [PHP] istanziare una classe ? PHP 2
G aiuto con classe template php PHP 1
catellostefano Problema con la classe class.phpmailer.php PHP 5
J classe php sbilenca PHP 17
F Problema con la classe zip php PHP 9
A include in classe PHP PHP 3
G classe CSS sovrascritta HTML e CSS 2
P jButton1ActionPerformed passare parametri ad altra classe Java 2
L creare oggetti da una classe tramite un form Javascript 0
A Riproduzione classe Vector C/C++ 3
O Estendere una rete di classe C Reti LAN e Wireless 1
tritabit Classe MysqliDb mancante nelle librerie arc2 PHP 2
S Copiare attributi da una classe. Programmazione 0
B [Javascript] Cambiare classe ed aggiornare relativi eventi Javascript 3
A [Javascript] Mancata aggiunta di una classe al click Javascript 1
Shyson [WordPress] Mettere classe css WordPress 0
Sevenjeak [C#] Aiuto esportazione tema su libreria di classe ( dll ) .NET Framework 1
C Classe Prenotazione con 2 scelte Java 2
A modificare .jar con classe personalizzata Java 9
Rikk73 Passare come argomento in un metodo un parametro della classe istanziata PHP 0
M Visualizzare da una classe esistente ogni profilo utente PHP 1
napuleone Modificare attributi di una classe con js Javascript 2
C Upload immagini con classe non funzionante PHP 1
A chiamate con istanza di altra classe rispetto la classe di app. (plugin) PHP 1
M aggiungere classe al click Javascript 1
P Inserire classe su script Google Analitics Magento 0
N Dare id ad elementi classe jQuery 1

Discussioni simili