Download counter of exe file in PHP - php

I have a problem with counting downloads of file. There will be no problem if a link to the download file would look like this: http:// your.site.domain/download.php?file=filename.exe&customer=ABC_423. However my customer want to count statistics from link like this: http:// your.site.domain/downloadsfolder/ABC_423/filename.exe and also he needs to hotlink that link on other sites.
I think there would be solution in .htaccess file, but I don't know how to make a proper redirect.
My PHP script looks like this:
session_start();
define('SERVER_NAME', 'www.siteaddress.domain');
define('DOWNLOAD_PATH', 'http:// siteaddress.domain/versions/download');
define('DOWNLOAD_FILE', 'Setup.exe');
$filename = DOWNLOAD_PATH . '/' . $_GET['customer'] . '/' . DOWNLOAD_FILE;
$headers = get_headers($filename);
if ($headers[0] == 'HTTP/1.1 200 OK'){
// file exists, begin download procedure
if(isset($_GET['customer'])){
// begin update statistics
// mysql query to update specified row
}
// headers for downloading file
header("Content-Type: application/force-download");
header('Content-Type: application/x-unknown');
header("Content-Type: application/octet-stream");
//header("Content-Type: application/download"); // not sure if needed
header("Content-Disposition: attachment; filename=".basename($filename).";");
header("Accept-Ranges: bytes");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".remote_filesize(SERVER_NAME, $filename));
ob_clean();
flush();
readfile($filename);
exit;
}else{
echo 'File not found';
exit;
}

This is a simple RewriteRule in .htaccess. Something like this:
RewriteEngine On
RewriteRule ^/downloadsfolder/(.*)/(.*) /download.php?file=$2&customer=$1 [L]
Observe how a random char sequence is detected with (.*) and then used with $1 and $2 for each detected item in the translated URL.
Hope that helped!

Related

PHP - Change file name from url when user downloads file

File links are all http://website.com/f/xxx.png/zip/txt and so on.
I need to set it up so that if a user downloads that file it would download with a different name.
I have seen how to do this on a normal page, but I have no clue how making it work when the image itself is linked to is done.
Appreciate any help :)
Edit: Using the rewrite Steven Jeffries posted,
header('Content-Disposition: inline; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);
$im = imagecreatefrompng($filePathOnServer);
imagepng($im);
to display images and
header('Content-Disposition: attachment; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);
to make other files download solved the issues I had.
I think an easy way to do this would be to redirect download links to another script that handles what to download, etc. Basically, I'd set up a download dir, add some rewrite rules, and then create a script to handle what gets output.
Something like this (untested):
/path-to-web-root/download/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.* /downloads/handle-downloads.php
/path-to-web-root/download/handle-downloads.php
$url = trim($_SERVER['REQUEST_URI'], '/');
if (preg_match('^#downloads/(?<real_filename>.*?)/(?<options>.*)/(?<fake_filename>.*)$#', $url, $matches)) {
// Double check my regex, but basically pull the real filename from the url here
$actual_file = "/path-to-webroot/f/{$matches['real_filename']}";
$options = explode('/', $matches['options']);
if (in_array('zip', $options)) {
// Handle zip, etc.
}
$fake_filename = $matches['fake_filename'];
if (file_exists($actual_file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($fake_filename).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($actual_file));
readfile($file);
exit;
}
}
Then, instead of having the download link being website.com/f/xxx.png/zip/txt, you could instead do website.com/download/xxx.png/zip/txt/new-filename.png. This would allow you to set the filename to whatever you wanted since the browser will just take what's at the end of the url.
Edit: I've included the relevant code from readfile's manual page.
You can set the file response file name by setting header parameter.
For example:
<?php
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="xyz.png"');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
...
More on PHP header function here: http://php.net/manual/en/function.header.php

Dnt allow user to access document from url

I want the log in user can access the PDF file and anonymous user can not access the file from browser like www.domain.com/pdf/name.pdf
My pdf file is getting corrupted.It is gets failed when clicked for download.
I have created pdf folder in that kept my all pdf.
I have html code
<ul>
<li>
Test
</li>
</ul>
check.php file
if($_SESSION[login]==true){
$file_url = 'http://domainname.com/pdf/example.pdf';
$filename='example.pdf';
header("Content-Disposition: attachment; filename=" . urlencode($filename));
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file_url));
$fp = fopen($file_url, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush(); // this is essential for large downloads
}
fclose($fp);
}
ht.access
RewriteEngine on
RewriteRule .* check.php
Just add a function in your php file as below:
function protect_page(){
if(logged_in()===false){
header('Location: protected.php');
exit();
}
}
Check whether the user is logged in by doing
$_SESSION[login]==true
Write the above protect_page() function on the page that has link to your pdf.
And you're good to go.

Direct link access but tracking by mysql/php?

I have a direct link to a file I want to give out to my visitors, for example:
http://www.mydomain.com/mynewmix.mp3
Is there any way I can run the following query when the link above is being ping/hit/downloaded?
UPDATE `db` SET `downloaded`=`downloaded`+1 WHERE `url`='http://www.mydomain.com/mynewmix.mp3'
Any kind of help I can get on this is greatly appreciated. Thank you so much in advance.
Yes this is possible. you can use rewrite module in apache. so you can say that for all (mp3) files the server shouldn't return the mp3 file but instead run a php file/script which executes your query and returns the mp3 file.
this might help you: http://www.workingwith.me.uk/articles/scripting/mod_rewrite
in your .htaccess file:
RewriteEngine on
RewriteRule ^\.mp3$ index.php [L]
this will send all links ending with .mp3 to index.php (actualy it will still be the same link but the index.php will be executed)
other option you have:
RewriteRule ^.*/(\w)*\.mp3$ index.php?filename=$1 [L]
this will execute index.php with the GET veriable filename with the filename
eg. $_GET['filename'] = "filename" (when file: filename.mp3)
in index.php to let the user download the mp3 file (see: Can I serve MP3 files with PHP?):
header("Content-Transfer-Encoding: binary");
header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
header('Content-length: ' . filesize("[file location eg: /home/files/sometrack.mp3]"));
header('Content-Disposition: attachment; filename="sometrack.mp3"');
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile("[file location eg: /home/files/sometrack.mp3]");
exit();
you could do this dynamicly with the following code:
$fileName = $_GET['filename']."mp3"; //we stripped .mp3 in the apache rewrite (might not be so smart)
$fileLocation = "/your/location/".$filename;
header("Content-Transfer-Encoding: binary");
header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
header('Content-length: ' . filesize($fileLocation));
header('Content-Disposition: attachment; filename="'.$fileName.'"');
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile($fileLocation);
exit();
you can access the requested link with:
$_SERVER['REQUEST_URI'];
or the new (generated url with):
$_SERVER['REDIRECT_URL'];
I think there is another way that does what you want:
Create a new php file "download" to start download with parameters
Contents look like this (date and time are keys to get my mp3-file):
<?php
if (isset($_GET['date']) && is_string($_GET['date']) && isset($_GET['time']) && is_string($_GET['time']))
{
require_once($_SERVER['DOCUMENT_ROOT'] . "/bin/functions.php");
DownloadFile($_GET['date'],$_GET['time']);
}
?>
Create a different php file "functions.php" with the function "DownloadFile":
function DownloadFile($Date,$Time)
{
require('connection.php');
mysql_select_db($database, $instance);
$qry = "
UPDATE `table`
SET `Field1` = `Field1` + 1
WHERE `Field2` = '$Date' AND `Field3` = '$Time'
";
$result = mysql_query($qry, $instance) or die(mysql_error());
header('Content-type: Application/mp3');
header("Content-Length: " .(string)(filesize($file)));
header('Content-Disposition: attachment; filename=' . $file);
readfile($file);
}
Use different url for downloading (no anchor)
http://www.yoursite.com/xxx/download.php?date=2000-01-01&time=12:00:00
Yes you can do this. on click of url need to call ajax to run update query on success you proceed to download the file.

PHP is reading file instead of downloading

I have script below for downloading files from a folder using PHP, it is working local but online it is reading and printing on the page instate of downloading.
if( $result && count($result) > 0){
$row = $result[0];
$book = true;
$Location = './files/';
$bookLocation = $Location . $row['file_name']; // exampe: report.zip
if( file_exists( $bookLocation ) ){
$fileLocation = $bookLocation;
$file_size = filesize($fileLocation);
echo 'Please wait downloading the file....';
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename=' . $row['file_name']);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $file_size);
ob_clean();
flush();
readfile($fileLocation);
exit;
}else{
echo '<h3>Sorry!, file not found...</h3>';
}
}
.htaccess script
RewriteEngine on
RewriteRule ^$ index.html
RewriteRule ^index.html$ index.php
RewriteRule ^([0-9]{1,9})(/)([^/\.]+[^/\.]+)(_+[^/\.]+)(\.html|)/?$ index.php?id=$1&cat=$3
RewriteRule ^([^/\.]+[^/\.]+)(\.html|)/?$ index.php?page=$1
RewriteRule ^(.*)(/)([0-9]{1,9})(/)(.*)(\.html|)/?$ index.php?view_file=$3&file=$5
RewriteRule ^(.*)(/)([0-9]{1,9})(/)(.*)(\.htm)/?$ index.php?download=$3
RewriteRule ^(author)(/)(.*)(.html)/?$ index.php?user=$1
Thanks for the help.
It is possible that in certain browsers, you set it to automatically download and run that particular file type.
If that is the case, there is no way to "fix" this. The browser decides what to do with the file, even if you tell it to download it, the user might have told it to run directly.
Big Edit
While my earlier comment is correct, you have a major issue in your code:
$file_size = filesize($fileLocation);
echo 'Please wait downloading the file....';
header('Content-Description: File Transfer');
You must remove that echo statement. It is bound to cause issues, such as the headers not being sent. Considering your description, I'd say this is your problem.
See, once you send any content, you cannot send more headers.
As Christian suggested, you must remove the echo statement in your code. If it doesn't work for you even after that, try replacing the line
header('Content-Type: application/force-download');
with
header('Content-Type: application/octet-stream');

Files not having any content in after a header() download

I'm trying to create a download so that a user clicks on "down" it downloads a certain file from their account to their computer, I'm currently using this:
header('Content-Disposition: attachment; filename=' . basename("users/$username/$file_folder/$file_name"));
header("Content-Type:" .$file_type);
header("Content-Description: File Transfer");
header("Cache-control: private");
header("Connection: close");
header("Content-Length: ".$file_size);
The problem is, the file is downloading, but it's just empty, there is no content in the file
The code before this is just an if() and a while loop with database records.
Thanks in advance.
You are missing something like below: (unless the file is very large, in which case you would chunk it out)
$filename = 'path/to/file/file_name.txt';
echo file_get_contents($filename);
Alternatively you could populate a variable with the data you want put out into the file and simple echo it out like so:
$data = "begin\n";
$data .= "first line\n";
$data .= "another line\n";
$data .= "last line";
echo $data;
The content would be put out there AFTER your headers. Hope this helps.
The file is empty, because you never output the file. These header calls are just the header, you still need a body for a file to be correctly downloaded. You can use file_get_contents to echo the file contents.
header('Content-Disposition: attachment; filename=' . basename("users/$username/$file_folder/$file_name"));
header("Content-Type:" .$file_type);
header("Content-Description: File Transfer");
header("Cache-control: private");
header("Connection: close");
header("Content-Length: ".$file_size);
// echo the file, this will make the download work
echo file_get_contents("users/$username/$file_folder/$file_name");
after you send the headers you need to actually push out the file content...
see this
http://php.net/manual/en/function.file-put-contents.php

Categories