Jump to content
  • Checkout
  • Login
  • Get in touch

osCommerce

The e-commerce.

Recommended Posts

Posted (edited)

I have tried to make the download function to work properly. It took me a couple of hours by try and error. I would like to share my experience and hope it is useful to people have the similar problem.

 

My original problem was, when user click on the download link, the downloaded file is checkout_success.php or the download.php. It is not the file that I give in the downlaod database. If the server does not allow to downlaod these files, the download will fail. Optionally, user can right click on the link and choose the "Save Target As" menu. But the file name appear in the save dialogue is confusing, it is "checkout_success.php" or "download", not the right file extension. If user does not give the correct file extension to save the file, the downloaded file will not be able to run.

 

I found the following problems:

 

1. If user uses Windows and Internet Explorer, the "attachment" should not appear in the header ""Content-disposition: attachment; filename=..". But it is required by other type of browsers.

 

2. The download file I give is not a plain file name. It is combined with a directary. I have to use diferent directory to store a huge number of download files, insted of putting them in a flat directory. But in the "Content-disposition: attachment; filename=.." header, the filename nust be a plain file name.

 

I added the file size so that user can expect how long the download will take. Because my files are binaries, I use binary transfer encoding. I also added "force-download" because I want user to get an empty file instead of an error file.

 

What follows is the the code that I modifed in the download.php:

 

<?php
/*
?$Id: download.php,v 1.9 2003/02/13 03:01:48 hpdl Exp $

?osCommerce, Open Source E-Commerce Solutions
?http://www.oscommerce.com

?Copyright (c) 2003 osCommerce

?Released under the GNU General Public License
*/

?include('includes/application_top.php');

?if (!tep_session_is_registered('customer_id')) die;

// Check download.php was called with proper GET parameters
?if ((isset($HTTP_GET_VARS['order']) && !is_numeric($HTTP_GET_VARS['order'])) || (isset($HTTP_GET_VARS['id']) && !is_numeric($HTTP_GET_VARS['id'])) ) {
? ?die;
?}
?
// Check that order_id, customer_id and filename match
?$downloads_query = tep_db_query("select date_format(o.date_purchased, '%Y-%m-%d') as date_purchased_day, opd.download_maxdays, opd.download_count, opd.download_maxdays, opd.orders_products_filename from " . TABLE_ORDERS . " o, " . TABLE_ORDERS_PRODUCTS . " op, " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " opd where o.customers_id = '" . $customer_id . "' and o.orders_id = '" . (int)$HTTP_GET_VARS['order'] . "' and o.orders_id = op.orders_id and op.orders_products_id = opd.orders_products_id and opd.orders_products_download_id = '" . (int)$HTTP_GET_VARS['id'] . "' and opd.orders_products_filename != ''");
?if (!tep_db_num_rows($downloads_query)) die;
?$downloads = tep_db_fetch_array($downloads_query);
// MySQL 3.22 does not have INTERVAL
?list($dt_year, $dt_month, $dt_day) = explode('-', $downloads['date_purchased_day']);
?$download_timestamp = mktime(23, 59, 59, $dt_month, $dt_day + $downloads['download_maxdays'], $dt_year);

// Die if time expired (maxdays = 0 means no time limit)
?if (($downloads['download_maxdays'] != 0) && ($download_timestamp <= time())) die;
// Die if remaining count is <=0
?if ($downloads['download_count'] <= 0) die;
// Die if file is not there
?if (!file_exists(DIR_FS_DOWNLOAD . $downloads['orders_products_filename'])) die;
?
// Now decrement counter
// ?tep_db_query("update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " set download_count = download_count-1 where orders_products_download_id = '" . (int)$HTTP_GET_VARS['id'] . "'");

// Returns a random name, 16 to 20 characters long
// There are more than 10^28 combinations
// The directory is "hidden", i.e. starts with '.'
function tep_random_name()
{
?$letters = 'abcdefghijklmnopqrstuvwxyz';
?$dirname = '.';
?$length = floor(tep_rand(16,20));
?for ($i = 1; $i <= $length; $i++) {
? $q = floor(tep_rand(1,26));
? $dirname .= $letters[$q];
?}
?return $dirname;
}

// Unlinks all subdirectories and files in $dir
// Works only on one subdir level, will not recurse
function tep_unlink_temp_dir($dir)
{
?$h1 = opendir($dir);
?while ($subdir = readdir($h1)) {
// Ignore non directories
? ?if (!is_dir($dir . $subdir)) continue;
// Ignore . and .. and CVS
? ?if ($subdir == '.' || $subdir == '..' || $subdir == 'CVS') continue;
// Loop and unlink files in subdirectory
? ?$h2 = opendir($dir . $subdir);
? ?while ($file = readdir($h2)) {
? ? ?if ($file == '.' || $file == '..') continue;
? ? ?@unlink($dir . $subdir . '/' . $file);
? ?}
? ?closedir($h2); 
? ?@rmdir($dir . $subdir);
?}
?closedir($h1);
}

// Now send the file with header() magic
/*
?header("Expires: Mon, 26 Nov 1962 00:00:00 GMT");
?header("Last-Modified: " . gmdate("D,d M Y H:i:s") . " GMT");
?header("Cache-Control: no-cache, must-revalidate");
?header("Pragma: no-cache");
?header("Content-Type: Application/octet-stream");
?header("Content-disposition: attachment; filename=" . $downloads['orders_products_filename']);
*/


?$filepath = DIR_FS_DOWNLOAD . $downloads['orders_products_filename'];
?$arr = explode('/',$downloads['orders_products_filename']);
?$filename = end($arr);
?$size = filesize ("$filepath");
?header("Pragma: public");
?header("Expires: 0");
?header("Accept-Ranges: bytes");
?header("Content-Length: " . $size);
?header("Pragma: no-cache");
?header("Cache-Control: no-cache, must-revalidate");
?header("Content-Description: File Transfer");
?header("Content-Type: application/force-download");
?header("Content-Transfer-Encoding: binary");
?$user_agent = strtolower ($_SERVER["HTTP_USER_AGENT"]);
if ((is_integer (strpos($user_agent, "msie"))) && (is_integer (strpos($user_agent, "win"))))
{
?header( "Content-Disposition: filename=".$filename);
} else 
{
?header( "Content-Disposition: attachment; filename=".$filename);
}

?if (DOWNLOAD_BY_REDIRECT == 'true') {
// This will work only on Unix/Linux hosts
? ?tep_unlink_temp_dir(DIR_FS_DOWNLOAD_PUBLIC);
? ?$tempdir = tep_random_name();
? ?umask(0000);
? ?mkdir(DIR_FS_DOWNLOAD_PUBLIC . $tempdir, 0777);
? ?symlink(DIR_FS_DOWNLOAD . $downloads['orders_products_filename'], DIR_FS_DOWNLOAD_PUBLIC . $tempdir . '/' . $downloads['orders_products_filename']);
? ?tep_redirect(DIR_WS_DOWNLOAD_PUBLIC . $tempdir . '/' . $downloads['orders_products_filename']);
?} else {
// This will work on all systems, but will need considerable resources
// We could also loop with fread($fp, 4096) to save memory
? ?//readfile(DIR_FS_DOWNLOAD . $downloads['orders_products_filename']);
? readfile($filepath);
?}


?>

Edited by james_times
Posted (edited)

Sorry, I commented the code line under:

 

// Now decrement counter

 

for testing purpose. You should uncomment this line:

 

tep_db_query("update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . ...

 

in order to decrease the count of download.

Edited by james_times
Posted

This sounds like a nice little project, as I cannot install the download controller as my site is heavily modded this may be an alternative to a small problem which I have ignored.

Welldone James keep up the good work.

  • 1 year later...
Posted (edited)

WOW! This seems to work for me! I've tried a bunch of attempts at getting the headers right on here. This seems best so far.

Edited by grig

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...