Besoin d'un petit coup de main, svp

Robert_deSx
Invité n'ayant pas de compte PHPfrance

25 févr. 2012, 13:06

Bonjour, pour le présenter rapidement, je suis un total ignare en php (je ne l'avais jamais utilisé il y a une semaine), mais, à l'occasion de la mise en ligne d'un site perso (très simple, le site) j'ai eu besoin de 2 fonctions, à savoir :

Lancer le téléchargement de fichiers pdf par un clic sur une image
compter le nombre de clics sur l'image

J'ai quelques connaissances en HTML (qui datent d'il y a 15 ans) et j'ai vite découvert que je n'arrivait pas à assurer ces points.
lors du clic sur l'image, acrobat reader se lance au lieu d'avoir l'invite de commande pour accepter le téléchargement (win7)
et pour les compteurs, je trouve inélégant d'aller sur un site de fournisseur de compteur.

Bref, après quelques ballades sur le net, j'ai compris que je ne m'en sortirais pas sans coder un peu au delà de mes capacités.

J'ai trouvé (merci à ceux qui partagent) un truc pur forcer le téléchargement sur un clic gauche (en gros, la balise Href lance un fichier php par un code du genre
<a href="DGM/fichier.php?filename=nomdefichier.pdf">

et dans le fichier php, il y a des fonction header
<?php
if (isset($_GET["nomdefichier"]))
{
$filename=$_GET["nomdefichier"];

// Envoi du fichier
header('Content-Transfer-Encoding: none');
header('Content-Type: application/octetstream; name="'.$filename.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-length: '.filesize($filename));
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");
@readfile($filename) OR die();
}
?>

ça marche super, mais je n'arrive pas à mettre en place un compteur de clic qui soit compatible avec cette astuce.

En plus, évidemment, j'y connait rien et je ne comprends pas la moitié des explication que je lis sur la toile.

je dispose d'un hébergement avec base de données et tout le toutim, je suis certain qu'il y a moyen de faire des choses simples et efficaces, mais ça fait 8 jours que je patasse sans avancer.
je veux juste, sur mon script déjà existant, compter le nombre de téléchargement de mes fichiers et pouvoir afficher ce nombre dans une page.

Alors, voila, si quelqu'un a envie de perdre un peu de temps à me donner une combine que je pusse comprendre et mettre en oeuvre, je le remercie par avance.

slts

Bob

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

25 févr. 2012, 14:33

salut,

simplement avec un fichier texte, ou si tu dispose de php5 avec une petite base sqlite, ce qui peux être plus simple.

Avec une base sqlite tu utilise une table avec le nom et l'emplacement du fichier et un champ compteur.

Lorsque tu envoie un fichier au navigateur tu effectue la mise a compteur

avantage :
- la souplesse de la base de donnée
- ton script n'est plus ouvert aux hacker ouvert (que se passe t il si l'on met index.php dans le lien plutôt qu'un fichier pdf ?
- que du bon :)

http://www.php.net/sqlite

Edit un exemple fonctionnel
<?php
try {
    // connexion base
    $dbHandle = new PDO('sqlite:bobdesx.db');
} catch (PDOException $exception) {
    die($exception->getMessage());
}
if (!empty($_GET['id'])) {
    try {
        // on compte le nombre de fichier référencé par l'id (voir s'il existe)
        $sqlCount = 'select count(*) as nb from fichiers where id=' . $dbHandle->quote($_GET['id'], PDO::PARAM_INT);
        $result = $dbHandle->query($sqlCount);
        $data = $result->fetch(PDO::FETCH_OBJ);
        $result->closeCursor();
        if ($data->nb === '1') {
            // on a bien un fichier référencé dans la base, on le selectionne
            $sql = 'select nom, emplacement from fichiers where id=' . $dbHandle->quote($_GET['id'], PDO::PARAM_INT);
            $result = $dbHandle->query($sql);
            $data = $result->fetch(PDO::FETCH_OBJ);
            $result->closeCursor();
            // on vérifie que le fichier existe bien sur le serveur
            if (file_exists($data->emplacement)) {
                //ok je reprend le script de départ
                header('Content-Transfer-Encoding: binary'); //plutot que none ?
                header('Content-Type: application/octetstream; name="' . $data->nom . '"');
                header('Content-Disposition: attachment; filename="' . $data->nom . '"');
                header('Content-length: ' . filesize($data->emplacement));
                header('Expires: 0');
                header('Cache-Control: must-revalidate');
                header("Pragma: no-cache");
                header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
                header("Expires: 0");
                readfile($data->emplacement);
                // mise a jour de la base
                if ($ret > 0)
                    $dbHandle->query('update fichiers set cpt = cpt+1 where id=' . $dbHandle->quote($_GET['id'], PDO::PARAM_INT));
            } else {
                echo 'heu la y grosse boulette dans la base !!! (fichier inexistant physiquement, base corrompue)';
            }
        } else {
            echo 'Le fichier existe pas dans la base!';
        }
    } catch (PDOException $exception) {
        die($exception->getMessage());
    }
// on considere que l'on passe la clef du fichier dans l'url (champ id)
} else {
    // on affiche les fichiers présent dans la base avec un lien pour le DL
    try {
        $result = $dbHandle->query('select nom, id from fichiers order by nom');
        $result->setFetchMode(PDO::FETCH_OBJ);
        while ($data = $result->fetch()) {
            echo '<a href="bob.php?id='.$data->id.'" title="Télécharger le fichier '.$data->nom.'">'.$data->nom.'</a><br />';
        }
        $result->closeCursor();
    } catch (PDOException $exception) {
        die($exception->getMessage());
    }
}
?>
explication :

ce code utilise l'extension PDO pour la connexion à la base de données. un tuto => http://www.siteduzero.com/tutoriel-3-34 ... x-bdd.html

le code de la table (pour info)
CREATE TABLE 'fichiers' ( 
'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
'nom' VARCHAR(50) NOT NULL, 
'emplacement' TEXT NOT NULL,
 'cpt' BIGINT NOT NULL DEFAULT '0' );
ce code permet de lister les fichiers (dernière partie ligne 47 à 59).
et le téléchargement du fichier (a partir du code que tu a fournis plus haut).

On ne passe plus le nom du fichier mais la clef primaire de la table (qui sert de référence). pourquoi ? parce que passer le fichier c'est un script qui permet de récupérer n'importe quel fichier. imagine qu'a la palce du pdf on demande un ficher de mot de passe. (il ne faut jamais oublié que les information d'une page web sont modifiable et que tu ne peux pas être certain que personne ne vas pas le modifier).
ensuite on vérifie si l'id existe bien dans la base (pour pas essayer de récupérer un fichier qui existe pas.
on récupère le nom du fichier et son emplacement (cela permet d'avoir un nom de fichier sur le disque qui est différent de celui qui donné au début et ainsi virer les espaces et autre caractères spéciaux et aussi gérer l'unicité du nom de fichier et éviter l'écrasement :) ).
lorsque l'on a toute les infos on envoie le tout au navigateur.
si tous c'est bien passé on met a jour le compteur de téléchargement.

voile il te reste a faire le formulaire d'insertion :
- l'accès a la base est déjà mis dans mon code.
- la requête SQL est : insert into ... => http://www.phpdebutant.org/article63.php ou plus détailé sur sqlpro.developpez.com
- le formulaire html est simple à utiliser il te faut deux champs (nom + un champs de type file pour l'upload) : tuto upload de fichier par AB

si tu a des questions tu sais comment faire :mrgreen:

@+
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Il en faut peu pour être heureux ......