How can I secure my didgital downloads?

SpaceshipSpaceship
Watch

Ik

Quality //VIP Member
Impact
8
Hi,

I need to know how to do the following:

1- I want to allow users to download MP3 files from my site, BUT I don't want them to see the original file name, or even find out the directory name where I store my MP3 files.

2- I don't want search engines like Google to find my MP3 files.

Thank you
 
0
•••
The views expressed on this page by users and staff are their own, not those of NamePros.
.US domains.US domains
Hi,

Just use Mysql & php, have a record for every song with the download "key" (random key) --- and havea cron job update the mysql record with a new "key" or filename every hour or so, along with renaming the file to the new key.

I havent done it before but it would be easy, then on your website you just grab the records current key to link to; sorry if i made it confusing but its a pretty simple concept.

I can code this up for you for a nominal fee :) hit me up if you need help
 
0
•••
Place your mp3s in a directory... for eg, let's just call it... umm.. mp3s :)

In that directory, place a .htaccess file with:
Code:
deny from all

Next, some PHP
PHP:
<?php

// connect to database (this uses PHP5's MySQLi Class)
$db = new mysqli('localhost', 'username', 'password', 'database');

if ($db->connect_error)
{
	die("Connect Error ({$db->connect_errno}) {$db->connect_error}");
}

// filter_* is PHP 5 only
$fileid = filter_input(INPUT_GET, 'fileid', FILTER_SANITIZE_NUMBER_INT);

if ($fileid > 0)
{
	/**
	Let's say your database is setup this way:

	CREATE TABLE `mp3s` (
		`fileid` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
		`filename` VARCHAR(255) NOT NULL,
		`downloads` INT UNSIGNED NOT NULL
	);
	*/	
	$fsql = $db->query("
		SELECT filename
		FROM mp3s
		WHERE fileid = $fileid
	");

	if ($fsql->num_rows() > 0)
	{
		$filename = $fsql->fetch_array();
		$filename = "./mp3s/{$filename['filename']}";

		header("Pragma: public");
		header("Expires: 0");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Cache-Control: private", false);
		header("Content-Type: application/force-download; name=\"" . basename($filename) . "\";");
		header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";" );
		header("Content-Transfer-Encoding: binary");
		header("Content-Length: " . @filesize($filename));
		readfile($filename);

		$db->query("UPDATE mp3s SET downloads = downloads + 1 WHERE fileid = $fileid LIMIT 1");
		exit;
	}
	$fsql->close();
}

$db->close();

?>
 
0
•••
On some of my sites I create temporary soft links with random names, then redirect the download to the soft link. The soft links get deleted by a cron job.

I've considered doing something similar to Eric's post on one of my sites to act as a download counter. Does this cause problems with large files (10's of MiBs?). I think PHP will read the whole file into memory (which may cause a problem with PHP memory limits), then throw the whole lot at the web server (apache in my case) in one go, in which case apache would have to buffer it until it was transferred to the user, which could be several minutes. Or perhaps PHP buffers it's output, so the PHP script could timeout for large files. Anyone got any experience of this?
 
0
•••
Thank you everyone for the responses. I will try the different methods and see which one is the best.

More solutions are welcome.
 
0
•••
I've considered doing something similar to Eric's post on one of my sites to act as a download counter. Does this cause problems with large files (10's of MiBs?). I think PHP will read the whole file into memory (which may cause a problem with PHP memory limits), then throw the whole lot at the web server (apache in my case) in one go, in which case apache would have to buffer it until it was transferred to the user, which could be several minutes. Or perhaps PHP buffers it's output, so the PHP script could timeout for large files. Anyone got any experience of this?

It's possible I suppose. Although, I do believe PHP uses the output buffer with readfile() - you may even be able to use the fopen() method to retrieve the content in chunks.

Or heck, even file_get_contents, as if your OS supports it - it can use memory mapping.
 
0
•••
It's possible I suppose. Although, I do believe PHP uses the output buffer with readfile() - you may even be able to use the fopen() method to retrieve the content in chunks.

Or heck, even file_get_contents, as if your OS supports it - it can use memory mapping.

Hi Eric,

So that means that your solution will work fine for big video files as well? 150MB+?

Thanks for the help

By the way, I tried your code on my MP3 downloads, and it works great. Just want to make sure it doesn't cause any issue with huge files.

Regards
 
0
•••
For very large files, readfile will not be the best thing to use...

Something like this maybe:

PHP:
<?php

// connect to database (this uses PHP5's MySQLi Class)
$db = new mysqli('localhost', 'username', 'password', 'database');

if ($db->connect_error)
{
	die("Connect Error ({$db->connect_errno}) {$db->connect_error}");
}

// filter_* is PHP 5 only
$fileid = filter_input(INPUT_GET, 'fileid', FILTER_SANITIZE_NUMBER_INT);

if ($fileid > 0)
{
	/**
	Let's say your database is setup this way:

	CREATE TABLE `mp3s` (
		`fileid` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
		`filename` VARCHAR(255) NOT NULL,
		`downloads` INT UNSIGNED NOT NULL
	);
	*/
	$fsql = $db->query("
		SELECT filename
		FROM mp3s
		WHERE fileid = $fileid
	");

	if ($fsql->num_rows() > 0)
	{
		$filename = $fsql->fetch_array();
		$filename = "./mp3s/{$filename['filename']}";
		$filesize = @filesize($filename);

		header("Pragma: public");
		header("Expires: 0");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Cache-Control: private", false);
		header("Content-Type: application/force-download; name=\"" . basename($filename) . "\";");
		header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";" );
		header("Content-Transfer-Encoding: binary");
		header("Content-Length: $filesize");

		// 20971520 = 20MB, could always adjust this - has to be in BYTES, not kilobytes
		if ($filesize >= 20971520)
		{
			$fp = @fopen($filename, 'rb');

			while (!feof($fp))
			{
				echo fread($fp, 2048);
			}
			unset($fp);
		}
		else
		{
			@readfile($filename);
		}
		$db->query("UPDATE mp3s SET downloads = downloads + 1 WHERE fileid = $fileid LIMIT 1");
		exit;
	}
	$fsql->close();
}

$db->close();

?>
 
0
•••
Great! Thank you again, Eric

For very large files, readfile will not be the best thing to use...

Something like this maybe:

PHP:
<?php

// connect to database (this uses PHP5's MySQLi Class)
$db = new mysqli('localhost', 'username', 'password', 'database');

if ($db->connect_error)
{
	die("Connect Error ({$db->connect_errno}) {$db->connect_error}");
}

// filter_* is PHP 5 only
$fileid = filter_input(INPUT_GET, 'fileid', FILTER_SANITIZE_NUMBER_INT);

if ($fileid > 0)
{
	/**
	Let's say your database is setup this way:

	CREATE TABLE `mp3s` (
		`fileid` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
		`filename` VARCHAR(255) NOT NULL,
		`downloads` INT UNSIGNED NOT NULL
	);
	*/
	$fsql = $db->query("
		SELECT filename
		FROM mp3s
		WHERE fileid = $fileid
	");

	if ($fsql->num_rows() > 0)
	{
		$filename = $fsql->fetch_array();
		$filename = "./mp3s/{$filename['filename']}";
		$filesize = @filesize($filename);

		header("Pragma: public");
		header("Expires: 0");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Cache-Control: private", false);
		header("Content-Type: application/force-download; name=\"" . basename($filename) . "\";");
		header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";" );
		header("Content-Transfer-Encoding: binary");
		header("Content-Length: $filesize");

		// 20971520 = 20MB, could always adjust this - has to be in BYTES, not kilobytes
		if ($filesize >= 20971520)
		{
			$fp = @fopen($filename, 'rb');

			while (!feof($fp))
			{
				echo fread($fp, 2048);
			}
			unset($fp);
		}
		else
		{
			@readfile($filename);
		}
		$db->query("UPDATE mp3s SET downloads = downloads + 1 WHERE fileid = $fileid LIMIT 1");
		exit;
	}
	$fsql->close();
}

$db->close();

?>
 
0
•••
hmm, so tired I overlooked it.

unset($fp);

Really should be:

fclose($fp);
 
0
•••
0
•••
Hi Eric,

I need your help!

Your code is perfect. I'm trying to get the user redirected to the homepage after they download the file. So, I put

header("location:index.php");

right after the db_close but the page doesn't redirect!!!

Any thoughts??

Place your mp3s in a directory... for eg, let's just call it... umm.. mp3s :)

In that directory, place a .htaccess file with:
Code:
deny from all

Next, some PHP
PHP:
<?php

// connect to database (this uses PHP5's MySQLi Class)
$db = new mysqli('localhost', 'username', 'password', 'database');

if ($db->connect_error)
{
	die("Connect Error ({$db->connect_errno}) {$db->connect_error}");
}

// filter_* is PHP 5 only
$fileid = filter_input(INPUT_GET, 'fileid', FILTER_SANITIZE_NUMBER_INT);

if ($fileid > 0)
{
	/**
	Let's say your database is setup this way:

	CREATE TABLE `mp3s` (
		`fileid` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
		`filename` VARCHAR(255) NOT NULL,
		`downloads` INT UNSIGNED NOT NULL
	);
	*/	
	$fsql = $db->query("
		SELECT filename
		FROM mp3s
		WHERE fileid = $fileid
	");

	if ($fsql->num_rows() > 0)
	{
		$filename = $fsql->fetch_array();
		$filename = "./mp3s/{$filename['filename']}";

		header("Pragma: public");
		header("Expires: 0");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Cache-Control: private", false);
		header("Content-Type: application/force-download; name=\"" . basename($filename) . "\";");
		header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";" );
		header("Content-Transfer-Encoding: binary");
		header("Content-Length: " . @filesize($filename));
		readfile($filename);

		$db->query("UPDATE mp3s SET downloads = downloads + 1 WHERE fileid = $fileid LIMIT 1");
		exit;
	}
	$fsql->close();
}

$db->close();

?>
 
0
•••
Hi Eric,

I need your help!

Your code is perfect. I'm trying to get the user redirected to the homepage after they download the file. So, I put

header("location:index.php");

right after the db_close but the page doesn't redirect!!!

Any thoughts??

you'll need to set cron job
 
0
•••
you'll need to set cron job

I don't see a need for a cron job here. This is a normal code to download a file. All I need is to redirect the user to the homepage once the file download code is processed.
 
0
•••
try putting a space after the :

if that doesn't help, make sure your in the right directory and that you do not need to use any ../ or /
 
0
•••
try putting a space after the :

if that doesn't help, make sure your in the right directory and that you do not need to use any ../ or /

No luck!

It seems like the header location doesn't work when other headers are used before it!
 
0
•••
You can't send a header once content has been sent, as the headers have already been sent by that point.
 
0
•••
I even tried to place some html code after that piece of code, but it didn't show!!
 
0
•••
Dynadot — .com TransferDynadot — .com Transfer
Appraise.net

We're social

Spaceship
Domain Recover
DomainEasy — Live Options
  • The sidebar remains visible by scrolling at a speed relative to the page’s height.
Back