3

I tried to create a download counter with PHP. The script, I have created, works, but when I click the download link, the script sends me to a blank page. Is it possible to stay on the page while downloading and counting?

Here's my code of my download.php file:

<?php
$Down=$_GET['Down'];
?>

<html>
<head>

<meta http-equiv="refresh" content="0;url=<?php echo $Down; ?>">

</head>

<body>

<?php

$fp = fopen("counter.txt", "r");
$count = fread($fp, 1024);
fclose($fp);
$count = $count + 1;

$fp = fopen("counter.txt", "w");
fwrite($fp, $count);
fclose($fp);


?>

</body>
</html>

That's how the link in my index.php looks like:

<a href="download.php?Down=download.zip">download</a>

Many thanks in advance!

user3579294
  • 33
  • 1
  • 1
  • 3
  • can you post the full code what your using. download.php will be blank because its not doing nothing. your need to do the counter code before the download, no HTML required. – Lawrence Cherone Apr 27 '14 at 22:03
  • @LozCherone that's my full code. i understand your point, but my counter code is not in the same file as the html link. my link is my index.php. the counter code is in a extra script. do i have to put my counter code in my index file? – user3579294 Apr 27 '14 at 22:24
  • that is what AJAX is for.. – user3454730 Apr 29 '14 at 11:57

4 Answers4

4

Ok as you have most of the code missing here is an example, basically your need to call the counter code inside the download.php file, and pass through the file contents after doing the counter code and setting download headers. also be wary or allowing malicious people to download any file from your server by just passing the file name to the download function. download.php?file=index.php ect

<?php 
function get_download_count($file=null){
    $counters = './counters/';
    if($file == null) return 0;
    $count = 0;
    if(file_exists($counters.md5($file).'_counter.txt')){
        $fp = fopen($counters.md5($file).'_counter.txt', "r");
        $count = fread($fp, 1024);
        fclose($fp);
    }else{
        $fp = fopen($counters.md5($file).'_counter.txt', "w+");
        fwrite($fp, $count);
        fclose($fp);
    }
    return $count;
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title></title>
</head>

<body>

<a href="./download.php?file=exampleA.zip">exampleA.zip</a> (Downloaded <?php echo get_download_count('exampleA.zip');?> times)<br>
<a href="./download.php?file=exampleB.zip">exampleB.zip</a> (Downloaded <?php echo get_download_count('exampleB.zip');?> times)<br>

</body>
</html>

download.php as you can see it outputs no HTML as this would corrupt the file.

<?php 
//where the files are
$downloads_folder = './files/';
$counters_folder = './counters/';

//has a file name been passed?
if(!empty($_GET['file'])){
    //protect from people getting other files
    $file = basename($_GET['file']);

    //does the file exist?
    if(file_exists($downloads_folder.$file)){

        //update counter - add if dont exist
        if(file_exists($counters_folder.md5($file).'_counter.txt')){
            $fp = fopen($counters_folder.md5($file).'_counter.txt', "r");
            $count = fread($fp, 1024);
            fclose($fp);
            $fp = fopen($counters_folder.md5($file).'_counter.txt', "w");
            fwrite($fp, $count + 1);
            fclose($fp);
        }else{
            $fp = fopen($counters_folder.md5($file).'_counter.txt', "w+");
            fwrite($fp, 1);
            fclose($fp);
        }

        //set force download headers
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.$file.'"');
        header('Content-Transfer-Encoding: binary');
        header('Connection: Keep-Alive');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . sprintf("%u", filesize($downloads_folder.$file)));

        //open and output file contents
        $fh = fopen($downloads_folder.$file, "rb");
        while (!feof($fh)) {
            echo fgets($fh);
            flush();
        }
        fclose($fh);
        exit;
    }else{
        header("HTTP/1.0 404 Not Found");
        exit('File not found!');
    }
}else{
    exit(header("Location: ./index.php"));
}
?>

Make sure you check the $downloads_folder variable is correct. Hope it helps.

Download Full example code.

Lawrence Cherone
  • 46,049
  • 7
  • 62
  • 106
  • i just get "File not found!", although i checked the path several times – user3579294 Apr 27 '14 at 22:48
  • I just added the full script as a download, you most likely got the path wrong for `$downloads_folder = './files/';` **make sure it ends with** `/` – Lawrence Cherone Apr 27 '14 at 22:49
  • i just uploaded your code to my ftp server. i have an awkward error now. i didn't edited your code. here's the link: http://jomabeats.com/downloadtest/ – user3579294 Apr 27 '14 at 22:58
  • you have an old php version, time to change host – Lawrence Cherone Apr 27 '14 at 23:08
  • Ok, fixed that it should work on your old host now, plus added the ability to track multiple files counter, as i suspect your want to count downloads on more then one file. also updated the dropbox link. – Lawrence Cherone Apr 27 '14 at 23:25
1

Try using php header redirect instead of JS or meta tag redirect:

<?php
//counter code
$fp = fopen("counter.txt", "r");
$count = fread($fp, 1024);
fclose($fp);
$count = $count + 1;

$fp = fopen("counter.txt", "w");
fwrite($fp, $count);
fclose($fp);

// redirect
header("location: ".$_GET["Down"]);
exit;

Also make sure there is nothing outputted before the header.

http://www.php.net/manual/en/function.header.php

Also for the link, if it is still not working try adding the target attr:

<a href="download.php?Down=download.zip" target="_new">download</a>
stomo21
  • 280
  • 2
  • 5
  • now, i've got an error: Parse error: syntax error, unexpected $end in /homepages/11/d117010365/htdocs/testserver/downloadtest/download.php on line 37 – user3579294 Apr 27 '14 at 22:38
  • download.php should only have the modified code above – stomo21 Apr 27 '14 at 22:40
  • +1 to this answer because it worked magnifically in my case. Simple effective answer without making everything overcomplicated as other solutions suggest. The php header() does the whole job (at least with Firefox and in my simple case). – elena Jul 12 '22 at 12:59
0

I'd like to improve the answer of Lawrence Cherone. The download counter, imho, should be transparent so it's more secure, nobody should have access directly to php scripts. Finally I integrated jquery so the counter is updated in real time via ajax... so there is no need to reload the page to see the results...

.htaccess (located in root/files/)

RewriteEngine on
RewriteRule ^(.*).(rar|zip)$ /php/doing_download.php?file=$1.$2 [R,L]

doing_download.php (located in root/php)

<?php
  $downloads_folder = $_SERVER['DOCUMENT_ROOT'] . '/files/';
  $counters_folder = $_SERVER['DOCUMENT_ROOT'] . '/files/counter/';
  if (!empty($_GET['file'])) {
    $file = basename($_GET['file']);
    $type = array("zip", "rar");
    $exts = strtolower(substr(strrchr($file, "."), 1));
    if (!in_array($exts, $type)) {
      header("HTTP/1.0 403 Forbidden");
      exit('File not allowed!');
    } else {
      if (file_exists($downloads_folder . $file)) {
        if (file_exists($counters_folder . md5($file) . '_counter.txt')) {
          $fp = fopen($counters_folder . md5($file) . '_counter.txt', "r");
          $count = fread($fp, 1024);
          fclose($fp);
          $fp = fopen($counters_folder . md5($file) . '_counter.txt', "w");
          fwrite($fp, $count + 1);
          fclose($fp);
        } else {
          $fp = fopen($counters_folder . md5($file) . '_counter.txt', "w+");
          fwrite($fp, 1);
          fclose($fp);
        }
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $file . '"');
        header('Content-Transfer-Encoding: binary');
        header('Connection: Keep-Alive');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . sprintf("%u", filesize($downloads_folder . $file)));
        $fh = fopen($downloads_folder . $file, "rb");
        while (!feof($fh)) {
          echo fgets($fh);
          flush();
        }
        fclose($fh);
        exit;
      } else {
        header("HTTP/1.0 404 Not Found");
        exit('File not found!');
      }
    }
  }
?>

count_download.php (located in root/php/)

<?php
  function get_download_count($file = null) {
    $counters = $_SERVER['DOCUMENT_ROOT'] . '/files/counter/';
    if ($file == null) return 0;
    $count = 0;
    if (file_exists($counters . md5($file) . '_counter.txt')) {
      $fp = fopen($counters . md5($file) . '_counter.txt', "r");
      $count = fread($fp, 1024);
      fclose($fp);
    } else {
      $fp = fopen($counters . md5($file) . '_counter.txt', "w+");
      fwrite($fp, $count);
      fclose($fp);
    }
    return $count;
  }
?>

call_download.php (located in root/php)

<?php
  include($_SERVER["DOCUMENT_ROOT"] . "/php/count_download.php");
  $item['item1'] = get_download_count('exampleA.zip');
  $item['item2'] = get_download_count('exampleB.zip');
  echo json_encode($item);
?>

static_download.php (located in root/php)

<?php
  include($_SERVER["DOCUMENT_ROOT"] . "/php/count_download.php");
  $item['item1'] = get_download_count('exampleA.zip');
  $item['item2'] = get_download_count('exampleB.zip');
?>

download.js (located in root/jsc/)

$(document).ready(function() {
  $.ajaxSetup({cache: false});
  getStatus();
});
function getStatus() {
  $.getJSON('php/call_download.php', function(data) {
    $('#item1').html(data.item1);
    $('#item2').html(data.item2);
  });
  setTimeout("getStatus()",1000);
}

index.php (located in root/)

<?php include($_SERVER["DOCUMENT_ROOT"] . "/php/static_download.php"); ?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Download Page</title>
<script type="text/javascript" src="jsc/jquery.min.js"></script>
<script type="text/javascript" src="jsc/download.js"></script>
</head>
<body>
File: <a href="files/exampleA.zip">exampleA.zip</a>&nbsp; - &nbsp;Downloaded <span id="item1"><?php echo $item['item1']; ?></span> Times<br />
File: <a href="files/exampleB.zip">exampleB.zip</a>&nbsp; - &nbsp;Downloaded <span id="item2"><?php echo $item['item2']; ?></span> Times<br />
File: <a href="test/test.zip">test.zip</a><!-- this file never will be counted since is located in other folder --><br />
</body>
</html>

Here, you can download all files and test them!

I hope my answer based on answer of Lawrence Cherone will solve any problem :) @Lawrence Cherone: great job!!!

Alessandro
  • 900
  • 12
  • 23
0
<?php
function downloadCount(){

    $counter = file_get_contents('counter.txt','r');
    $counter = $counter+ 1;
    $myfile = fopen("counter.txt", "w");
    fwrite($myfile, $counter);
    fclose($myfile);
                    
    return $counter;
}
?>
</header>
<body>
HTML...

<a href="download.php?Down=True">

DOWNLOAD </a> <br> DOWNLOADED

<?php 

if ($_GET['Down'])
{

    $counter = downloadCount();
    header("location: YourDownloadLink.fileExtension ");

}
$counter = file_get_contents('counter.txt','r');
                    
echo $counter
                    
?>
 TIMES</h2>