Script php compteur téléchargement

Hello,
J'aimerais avoir un script en php pour ajouter un compteur de téléchargement sans base de données afin de suivre le nombre de téléchargement de chaque fichier.

Le lien serait du style : download.php?file="nom du fichier"

Je fais appel à vous car je ne suis pas assez compétent dans ce domaine.
J'ai fais des recherches sur le net mais ceux que j'ai trouvé ne fonctionnent pas, le fichier ne se télécharge pas.

Est-ce quelqu'un aurait ce script sous la main ?

Merci

Jol5926

Réponses

  • StéphaneStéphane Member, Former PluXml Project Manager
    Salut

    Voilà un exemple de script que j'utilise
    <?php
    	# Emplacement des dossiers pour les compteurs de téléchargement et les fichiers à télécharger
    	# (avec un / à la fin des chemins)
    	
    	$hits 		= dirname(__FILE__).'/hits/';
    	$downloads 	= dirname(__FILE__).'/downloads/';
    
    	#==============================================
    	
    	/**
    	 * Fonction qui comptabilise le nombre de téléchargements
    	 *
    	 * @param	filename	nom et emplacement du fichier des hits
    	 **/
    	function hitsCounter($filename) {
    		$counter=0;
    		if(@file_exists($filename)) {
    			$f = @fopen($filename, "r");
    			@flock($f, LOCK_EX); //lock the file
    			$counter = intval(@fgets($f)); 
    			@fclose($f);
    		}
    		$f = @fopen($filename, "w");
    		@flock($f, LOCK_EX); //lock the file
    		@fwrite($f, $counter+1);
    		@fclose($f);
    	}
    	
    	/**
    	 * Protège une chaine contre un null byte
    	 *
    	 * @param	string chaine à nettoyer
    	 * @return	string chaine nettoyée
    	*/
    	function nullbyteRemove($string) {
    		return str_replace("\0", '', $string);
    	}
    
    	$h_file = null; # fichier compteur de téléchargement
    	$d_file = null; # fichier à télécharger
    	
    	# Détermination des noms des fichiers
    	if(isset($_GET['file']) AND !empty($_GET['file'])) {
    		$filename = basename(nullbyteRemove($_GET['file']));
    		$h_file = $hits.$filename.".txt";
    		$d_file = $downloads.$filename;
    	}
    
    	# Contrôle de l'existence du fichier à télécharger
    	if(!file_exists($d_file)) {
    		die('File not found');
    		exit;
    	}
    	
    	# Mise à jour du compteur de téléchargement du fichier
    	hitsCounter($h_file);
    	
    	# Envoi du fichier à l'utilisateur
    	header('Content-Description: File Transfer');
    	header('Content-Type: application/download');
    	header('Content-Disposition: attachment; filename='.basename($d_file));
    	header('Content-Transfer-Encoding: binary');
    	header('Expires: 0');
    	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    	header('Pragma: no-cache');
    	header('Content-Length: '.filesize($d_file));
    	readfile($d_file);
    	exit;
    	
    ?>
    

    il faut à la racine du site
    - un dossier : hits
    - un dossier : downloads

    mettre les fichiers à télécharger dans le dossier downloads
    les compteurs sont stockés dans le dossier hits sous la forme monfichier.zip.txt

    le script est à copier à la racine du site

    apres faut adapter les chemins au debut du script si tu veux changer les emplacements

    le script "download.php" est à appeler de cette façon:

    download.php?file=monfichier.zip

    nb: pour info il me semble que le script ne fonctionne pas chez free.fr à cause de l'utilisation des instructions php flock qui font parties des fonctions php interdites chez cet hébergeur

    Consultant PluXml

    Ancien responsable et développeur de PluXml (2010 à 2018)

  • Hello Stéphane,
    :) Ca fonctionne parfaitement.

    Est-il possible d'afficher à côté du fichier à télécharger le nombre de téléchargement ?

    Merci
  • il n'y a pas un plugin qui existe pour ça ?
  • niqnutn a écrit:
    il n'y a pas un plugin qui existe pour ça ?

    Hello,
    Oui, il existe un plugin de téléchargement qui permet d'ajouter un compteur mais pour un seul téléchargement par page.
    J'ai plusieurs fichiers en téléchargement sur la même page.
  • Hello les amis !!

    Personne ne sait s'il est possible d'afficher à côté du fichier à télécharger le nombre de téléchargement, donc de récupérer les données du fichier texte et de les afficher sur la page de l'article ?

    Merci :)
  • YannicYannic Member
    février 2017 modifié
    Salut,
    Combien de fichiers à télécharger prévoit tu d'avoir en tout et pour tout et combien sur un même article ?

    Car la le compteur du script au dessus ne me semble pas idéal pour ce que tu demande si tu compte afficher beaucoup de fichiers sur la meme page.

    Buster/NGINX/PHP7/PluXml5.8

  • Yannic a écrit:
    Salut,
    Combien de fichiers à télécharger prévoit tu d'avoir en tout et pour tout et combien sur un même article ?

    Car la le compteur du script au dessus ne me semble pas idéal pour ce que tu demande si tu compte afficher beaucoup de fichiers sur la meme page.

    Hello,
    Sur la même page, il y aura 15 à 20 fichiers qui pourront être téléchargés.
  • YannicYannic Member
    février 2017 modifié
    jol5926 a écrit:
    Hello,
    Sur la même page, il y aura 15 à 20 fichiers qui pourront être téléchargés.

    A moins que quelqu'un ai mieux à proposer

    Salut, En partant du script ci-dessus, le mieux serais d'enregistrer les compteurs dans un seul fichier.

    Donc : download.php (que tu appellera par download.php?file=monfichier.zip )
    <?php
    	# Emplacement des dossiers pour les compteurs de téléchargement et les fichiers à télécharger
    	# (avec un / à la fin des chemins)
    	
    	$hits 		= dirname(__FILE__).'/hits/';
    	$downloads 	= dirname(__FILE__).'/downloads/';
    	
    	# Emplacement du fichier compteur
    	$compteur_xml= $hits.'compteur.xml';
    
    	# on remplit un tableau de fichiers
    	if(@file_exists($compteur_xml))
    	{
    		$compteur = simplexml_load_file($compteur_xml);
    	}
    	#==============================================
    	
    	/**
    	 * Fonction qui comptabilise le nombre de téléchargements
    	 *
    	 * @param	filename	nom et emplacement du fichier des hits
    	 **/
    	function hitsCounter($filename)
    	{
    		global $compteur,$compteur_xml;
    		if (isset($compteur->$filename)) $compteur->$filename++; else $compteur->$filename = 1;
    		$SAVE = '<document>';
    		foreach($compteur as $KEY => $VALUE)
    		{
    			$SAVE .= '
    	<'.$KEY.'>'.$VALUE.'</'.$KEY.'>';
    		}
    		$SAVE .= '
    </document>';
    		$XML = new SimpleXMLElement($SAVE);
    		$XML -> asXML($compteur_xml);
    	}
    	
    	/**
    	 * Protège une chaine contre un null byte
    	 *
    	 * @param	string chaine à nettoyer
    	 * @return	string chaine nettoyée
    	*/
    	function nullbyteRemove($string) {
    		return str_replace("\0", '', $string);
    	}
    
    	$h_file = null; # fichier compteur de téléchargement
    	$d_file = null; # fichier à télécharger
    	
    	# Détermination des noms des fichiers
    	if(isset($_GET['file']) AND !empty($_GET['file'])) {
    		$filename = basename(nullbyteRemove($_GET['file']));
    		$h_file = trim(preg_replace('/[^a-zA-Z0-9_.-]/', '', $filename));
    		$d_file = $downloads.$h_file;
    	}
    	else
    		die('File missing');
    
    	# Contrôle de l'existence du fichier à télécharger
    	if(!file_exists($d_file)) {
    		die('File not found');
    		exit;
    	}
    	
    	# Mise à jour du compteur de téléchargement du fichier
    	hitsCounter($h_file);
    
    	# Envoi du fichier à l'utilisateur
    	header('Content-Description: File Transfer');
    	header('Content-Type: application/download');
    	header('Content-Disposition: attachment; filename='.basename($d_file));
    	header('Content-Transfer-Encoding: binary');
    	header('Expires: 0');
    	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    	header('Pragma: no-cache');
    	header('Content-Length: '.filesize($d_file));
    	readfile($d_file);
    	exit;
    

    ensuite il faudrait faire un Template pour cet article (article-xxx.php) ou dans ce template tu mettrais en dessous de la boucle article et au dessus de l’appel au fichier de commentaire la liste des fichiers à télécharger exemple :
    <?php
    	# Emplacement du dossier pour le compteur
    	# (avec un / à la fin des chemins)
    	$hits 		= PLX_ROOT.'hits/';
    	
    	# Emplacement du fichier compteur
    	$compteur_xml= $hits.'compteur.xml';
    
    	# on remplit un tableau de fichiers
    	if(@file_exists($compteur_xml))
    	{
    		$compteur = simplexml_load_file($compteur_xml);
    	}
    	
    	echo '<a href="http://monsite.com/download.php?file=fichier_1.zip">Télécharger fichier_1.zip</a> ( '.($compteur->{"fichier_1.zip"}?:'0').' )<br />';
    	echo '<a href="http://monsite.com/download.php?file=fichier_2.zip">Télécharger fichier_2.zip</a> ( '.($compteur->{"fichier_2.zip"}?:'0').' )<br />';
    	echo '<a href="http://monsite.com/download.php?file=fichier_3.zip">Télécharger fichier_3.zip</a> ( '.($compteur->{"fichier_3.zip"}?:'0').' )<br />';
    ?>
    

    Enfin avec un peu plus de mise en page bien sur.
    Le compteur sur la page ne s’incrémentera qu'après avoir rafraîchi la page.

    Edit : Attention cependant car la personne pourras télécharger tout fichier se trouvant dans le dossier $downloads y compris des fichiers php présents en tapant simplement dans l'url download.php?file=index.php ou autres scripts php que tu pourrais avoir dans ce dossier là

    Edit 2 : Petite correction du second script et petit ajout d'un regex dans le premier script pour ne garder que les caractères a-zA-Z0-9_.- dans les noms de fichiers.

    Buster/NGINX/PHP7/PluXml5.8

  • YannicYannic Member
    février 2017 modifié
    Je n'ai pour le moment pas testé la sécurité du script ci-dessus par contre !

    Peut-etre faudrais lui rajouter une petite couche de protection au niveau de la determination des noms de fichiers

    Buster/NGINX/PHP7/PluXml5.8

  • StéphaneStéphane Member, Former PluXml Project Manager
    Je suis pas fan d'avoir un seul fichier car en cas de probleme tu perds tous tes stats.
    Maintenant vu le contexte d'utilisation c'est vrai que c'est pas génial de devoir lire 20 fichiers pour récupérer les infos et afficher les compteurs.
    Est-ce que c'est vraiment utile d'afficher les compteurs ?

    Consultant PluXml

    Ancien responsable et développeur de PluXml (2010 à 2018)

  • hello,
    Merci pour vos retours.
    Je vais regarder ça de plus près.
    :)
  • bazooka07bazooka07 PluXml Lead Developer, Moderator
    @yannick,

    Pourquoi utiliser dirname(__FILE__), il existe la constante __DIR__
    Comme il existe la constante __CLASS__

    voir doc php
  • YannicYannic Member
    février 2017 modifié
    bazooka07 a écrit:
    @yannick,

    Pourquoi utiliser dirname(__FILE__), il existe la constante __DIR__
    Comme il existe la constante __CLASS__

    voir doc php

    Oh, simplement parce que j'ai bêtement recopié le script d'origine pour le transformer en un fichier xml à lire plutot qu'en 20 fichiers à lire.

    C'est sur, il y as de l'amélioration à faire surtout dans le deuxieme script, celui pour l'article puisque l'on est dans un contexte de template pluxml mais mon but était principalement de poser une base de un fichier hits à lire au lieu de 20.

    Edit: Petite correction du second script qui devrais maintenant fonctionner correctement.

    Buster/NGINX/PHP7/PluXml5.8

  • StéphaneStéphane Member, Former PluXml Project Manager
    pour info __DIR__ n'est possible que depuis php 5.3

    étant un vieux de la vieille j'ai encore l'habitude d'utiliser dirname(__FILE__) mais aussi pour une histoire de compatibilité de PluXml avec les version de php < 5.3

    Consultant PluXml

    Ancien responsable et développeur de PluXml (2010 à 2018)

  • Hello,
    je reviens vers vous pour votre aide.
    J'ai une page du site avec des liens pour ouvrir des fichiers pdf en lecture dans un popup. J'aurais aimé créer un lien pour compter le nombre de clic sur chaque fichier afin de savoir ceux les plus ouvert.
    Les fichiers en pdf ne sont pas téléchargés mais simplement ouvert en lecture.
    Est-ce qu'on peut utiliser le script ci-dessus (#2) et si oui comment le modifier ?
    ou
    Avez-vous un autre script à me proposer ?

    Merci
  • YannicYannic Member
    mars 2017 modifié
    jol5926 a écrit:
    Hello,
    je reviens vers vous pour votre aide.
    J'ai une page du site avec des liens pour ouvrir des fichiers pdf en lecture dans un popup. J'aurais aimé créer un lien pour compter le nombre de clic sur chaque fichier afin de savoir ceux les plus ouvert.
    Les fichiers en pdf ne sont pas téléchargés mais simplement ouvert en lecture.
    Est-ce qu'on peut utiliser le script ci-dessus (#2) et si oui comment le modifier ?
    ou
    Avez-vous un autre script à me proposer ?

    Merci

    Bien que pour le PDF cela risque de dépendre que la personne ai un lecteur embarqué et activé ou non dans son navigateur.

    En modifiant la fin du script comme tel cela devrais faire ce que tu as envie.
    # Mise à jour du compteur de téléchargement du fichier
    	hitsCounter($h_file);
    
    	$extension = substr(strrchr($h_file, "."), 1);
    	
    	if ($extension=='pdf')
    	{
    		$content = file_get_contents($d_file);
    		header("Content-Disposition: inline; filename=$d_file");
    		header("Content-type: application/pdf");
    		header('Cache-Control: private, max-age=0, must-revalidate');
    		header('Pragma: public');
    		echo $content;
    	}
    	else
    	{
    		# Envoi du fichier à l'utilisateur
    		header('Content-Description: File Transfer');
    		header('Content-Type: application/download');
    		header('Content-Disposition: attachment; filename='.basename($d_file));
    		header('Content-Transfer-Encoding: binary');
    		header('Expires: 0');
    		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    		header('Pragma: no-cache');
    		header('Content-Length: '.filesize($d_file));
    		readfile($d_file);
    	}
    	exit;
    

    Buster/NGINX/PHP7/PluXml5.8

  • bg62bg62 Member
    niqnutn a écrit:
    il n'y a pas un plugin qui existe pour ça ?
    ben si justement :
    http://forum.pluxml.org/viewtopic.php?id=4606
    et cela fonctionne très bien, exemple :
    http://refok.fr/index.php?article126/beigeseo-pluxml
    :)
  • YannicYannic Member
    mars 2017 modifié
    bg62 a écrit:
    niqnutn a écrit:
    il n'y a pas un plugin qui existe pour ça ?
    ben si justement :
    http://forum.pluxml.org/viewtopic.php?id=4606
    et cela fonctionne très bien, exemple :
    http://refok.fr/index.php?article126/beigeseo-pluxml
    :)

    Salut, sauf erreur de ma part, cela ne permet pas d'avoir 15 fichiers par page/article avec leurs compteurs respectifs. D'où la discussion et les codes qui ont suivis

    Buster/NGINX/PHP7/PluXml5.8

  • bg62 a écrit:
    niqnutn a écrit:
    il n'y a pas un plugin qui existe pour ça ?
    ben si justement :
    http://forum.pluxml.org/viewtopic.php?id=4606
    et cela fonctionne très bien, exemple :
    http://refok.fr/index.php?article126/beigeseo-pluxml
    :)

    Je confirme que ce plugin fonctionne très bien mais on ne peut mettre qu'un fichier à télécharger par page.
    Comment fais-tu si tu as plusieurs fichiers à télécharger sur la même page avec ce plugin ?
    Pour moi c'est impossible !
    :)
  • bg62bg62 Member
    ah non, là c'est un par page :)
  • Yannic a écrit:
    jol5926 a écrit:
    Hello,
    je reviens vers vous pour votre aide.
    J'ai une page du site avec des liens pour ouvrir des fichiers pdf en lecture dans un popup. J'aurais aimé créer un lien pour compter le nombre de clic sur chaque fichier afin de savoir ceux les plus ouvert.
    Les fichiers en pdf ne sont pas téléchargés mais simplement ouvert en lecture.
    Est-ce qu'on peut utiliser le script ci-dessus (#2) et si oui comment le modifier ?
    ou
    Avez-vous un autre script à me proposer ?

    Merci

    Bien que pour le PDF cela risque de dépendre que la personne ai un lecteur embarqué et activé ou non dans son navigateur.

    En modifiant la fin du script comme tel cela devrais faire ce que tu as envie.
    # Mise à jour du compteur de téléchargement du fichier
    	hitsCounter($h_file);
    
    	$extension = substr(strrchr($h_file, "."), 1);
    	
    	if ($extension=='pdf')
    	{
    		$content = file_get_contents($d_file);
    		header("Content-Disposition: inline; filename=$d_file");
    		header("Content-type: application/pdf");
    		header('Cache-Control: private, max-age=0, must-revalidate');
    		header('Pragma: public');
    		echo $content;
    	}
    	else
    	{
    		# Envoi du fichier à l'utilisateur
    		header('Content-Description: File Transfer');
    		header('Content-Type: application/download');
    		header('Content-Disposition: attachment; filename='.basename($d_file));
    		header('Content-Transfer-Encoding: binary');
    		header('Expires: 0');
    		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    		header('Pragma: no-cache');
    		header('Content-Length: '.filesize($d_file));
    		readfile($d_file);
    	}
    	exit;
    

    Merci
Connectez-vous ou Inscrivez-vous pour répondre.