Download Files

I'm trying to build a file download capability into a web site.

Please go to http://rkassoc.org/Lakos/test_download1.php?model=eTCX-0050. Source of this is attached. I know there are 3 files for each product & I know the structure of the file names (two are the same regardless of the product).

Note that all the types except "All" use Javascript to go to download.php (also attached) to do the download. This works perfectly for all 3 types.

Note that for the "All" button, I built a revised version of download.php called download_all.php (also attached). Hopefully, the intention is obvious.

When I click "All", it asks me about downloading the "middle" file (Brochure) but not the others.

How can I make it work as intended?

Thanks
test_download1.php
download.php
download_all.php
Richard KortsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ray PaseurCommented:
I confess that I have not read the PHP files posted with the question, but I've dealt with the "force download" issue before.  This solution is a little old, but I think it will still work with modern browsers.
<?php // demo/force_download.php

/**
 * Show how to force a file download
 *
 * Choose a file to download, either via a hard-coded file path
 * or via a URL parameter like this
 *
 * path/to/demo/force_download.php?url=path/to/file.txt
 *
 * If you wanted to use the URL parameter, you might want to
 * (1) Secure the script with password protection
 * (2) replace the $url variable with something like this:
 * $url = $_GET['url'];
 *
 * If you use the URL parameter, be careful that the script
 * does not expose sensitive data on your server!
 */
error_reporting(E_ALL);


// WHAT FILE DO WE WANT TO DOWNLOAD?
$url = "http://www.IcoNoun.com/demo/short_text_file.txt";


// USE CASE
force_download($url);


// FUNCTION TO FORCE A DOWNLOAD FROM A FILE
function force_download($url, $filename=NULL)
{
    // GET THE DOWNLOAD FILE NAME
    if (empty($filename)) $filename = basename($url);

    // GET LENGTH AND FILE RESOURCE POINTER
    $hdr = get_headers($url, TRUE);
    $len = trim($hdr['Content-Length']);
    $fpr = fopen($url,'rb');

    // ON SUCCESS
    if ($fpr)
    {
        // THESE HEADERS ARE USED ON ALL BROWSERS
        header("Content-Type: application-x/force-download");
        header("Content-Disposition: attachment; filename=$filename");
        header("Content-length: $len");
        header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
        header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");

        // THIS HEADER MUST BE OMITTED FOR IE 6+
        if (FALSE === strpos($_SERVER["HTTP_USER_AGENT"], 'MSIE '))
        {
            header("Cache-Control: no-cache, must-revalidate");
        }

        // THIS IS THE LAST HEADER
        header("Pragma: no-cache");

        // FLUSH THE HEADERS TO THE BROWSER
        flush();

        // WRITE THE FILE
        fpassthru($fpr);
    }

    // ERROR
    else
    {
        trigger_error("Unable to open $url", E_USER_ERROR);
    }
}

Open in new window

0
Dave BaldwinFixer of ProblemsCommented:
According to the IANA http://www.iana.org/assignments/media-types/media-types.xhtml , there is no 'Content-type: application/force-download'.  And the PHP man page http://php.net/manual/en/function.header.php shows this.
<?php
// We'll be outputting a PDF
header('Content-Type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

Open in new window


My own code that I borrowed from somewhere, possibly Ray, is below.
header("Content-Disposition: attachment; filename=" . urlencode($file));   
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");            
header("Content-Length: " . strlen($csv));
flush(); // this doesn't really matter.

echo $csv;
flush(); // this is essential for large downloads

Open in new window

I'm curious if you are actually get three files?
0
Dave BaldwinFixer of ProblemsCommented:
I just checked your demo page and it appears that you are not.  Actually I don't think you can force download of three files in one page like that.  PHP and the web server will not normally allow you to send new headers after content has already been sent.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Ray PaseurCommented:
Hmm... I wonder if you could send the headers if the content was buffered with ob_start()?  Maybe I'll try an experiment later today.
0
Ray PaseurCommented:
After looking around for good solutions, my conclusion is that the best way may be to create a Zip Archive and force the download of the Archive.

This worked in Chrome, but there is still the question of file names.
<!-- demo/temp_rkorts.php http://www.experts-exchange.com/questions/28714186/Download-Files.html -->
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<style type="text/css">
/* STYLE SHEET HERE */
</style>

<script>
var links =
[ 'http://iconoun.com/demo/images/tnp_lightning.png'
, 'http://iconoun.com/demo/images/tnp_rain.png'
, 'http://iconoun.com/demo/images/tnp_snow.png'
]
;

function downloadAll(urls) {
    var link = document.createElement('a');

    link.setAttribute('download', null);
    link.style.display = 'none';

    document.body.appendChild(link);

    for (var i = 0; i < urls.length; i++) {
        link.setAttribute('href', urls[i]);
        link.click();
    }

    document.body.removeChild(link);
}
</script>

<title>HTML5 Page - Multiple Downloads</title>
</head>
<body>

<button onclick="downloadAll(window.links)">Download Multiple Files</button>

<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>

</body>
</html>

Open in new window

0
Ray PaseurCommented:
Here's a Zip Archive example.
<?php // demo/zip_archive.php

/**
 * Create a Zip Archive from a subdirectory
 *
 * http://php.net/manual/en/zip.examples.php
 * http://php.net/manual/en/zip.examples.php#85714 <-- Errors are obscure!
 * http://php.net/manual/en/class.ziparchive.php
 * http://php.net/manual/en/ziparchive.close.php#101606
 */
error_reporting(E_ALL);
date_default_timezone_set('America/New_York');


// THIS IS THE LIST OF scandir() RESPONSES THAT WE DO NOT WANT
$unwanted
= array
( '.'
, '..'
, 'teste2.txt'
)
;


// THE URL ARGUMENT IS THE NAME OF THE DIRECTORY TO ZIP
$dir = (!empty($_GET["dir"])) ? $_GET["dir"] : NULL;

// BUT FOR MY TESTS IT IS HARDCODED
$dir = 'oop5';
if (!$dir) die("PLEASE PROVIDE dir= IN THE URL");


// A GOOD PATH ON MY SERVER
$path
= getcwd()
. DIRECTORY_SEPARATOR
. $dir
;
if (!is_dir($path)) die("FAIL: NOT VALID PATH $path");


// INSTANTIATE THE OBJECT
$zip = new ZipArchive();

// CREATE A DATE-TIME ARCHIVE NAME
$archive
= date('Ymd\THis')
. '_archive_'
. $dir
. '.zip'
;
// TRY TO CREATE THE ARCHIVE
if ($zip->open($archive, ZIPARCHIVE::CREATE) !== TRUE) trigger_error("FAIL: ZIP->OPEN $archive", E_USER_ERROR);


// GET THE LIST OF FILES
if (!$files = scandir($path)) die("FAIL: scandir() $path");
foreach ($files as $file)
{
    $filename = $path . DIRECTORY_SEPARATOR . $file;

    // SKIP THE UNWANTED AND ADD THE OTHERS TO THE ARCHIVE
    if ( in_array($file, $unwanted) ) continue;
    if ( !is_file($filename) )        continue;
    // ACTIVATE THIS FOR A PROGRESS REPORT: echo PHP_EOL . "$filename: $file";
    $zip->addFile($filename, $file );
}

if (!$zip->close()) die("FAIL: ZIP->CLOSE");

$fs  = filesize($archive);
$fsn = number_format($fs);


// PREPARE A LINK
$link
= '<a target="_blank" href="'
. $archive
. '">'
. "DOWNLOAD $archive $fsn BYTES"
. '</a>'
;
echo PHP_EOL . $link;

/**
 * You can use something like this to send the Zip Archive directly to the browser
 *
header("Content-Type: archive/zip");
header("Content-Disposition: attachment; filename=$dir".".zip");
header("Content-Length: $fs");
readfile($archive);
 */

Open in new window

0
Richard KortsAuthor Commented:
Ray & Dave,

I know how to do the zip file & zip all 3 into one.

The customer SPECIFICALLY requested that zip files NOT be used as some visitors might not know how to deal with a zip file.

I'm guessing, based on Dave's comment that it may not be possible.

Do you think the "All" option would work if I cascaded the 3 download. That is, create a version of download.php that at the end did (somehow, header won't work) went back to itself with a new file name?

Can I do a redirect to another php program other hand using header("Location: program.php"); ?.

Thanks
0
Ray PaseurCommented:
Some of this would be a research project for me, but let's see if this idea is useful.  Using the "force download" concept with one file per request, you could put up a web page with three links.  Each link would download one file.   I think that would be the smoothest client experience.  You could use a little JavaScript to hide the links once the download is started, so the page will be "empty" once all of the downloads have been triggered.

The part about this that gives me some pause is the browser support for things that are obviously outside the mainstream, and multi-file downloads are outside the mainstream.  I don't want to lead you in the direction of a solution that works today but breaks tomorrow, or is unusable in one of the popular browsers.
0
Richard KortsAuthor Commented:
Ray,

Basically I did what you indicated in your last post.

http://rkassoc.org/Lakos/test_download1.php?model=eTCX-0050

This does one at a time, which works fine using the attached (to the original post) download.php.

I don't see a need to disable or his the button already downloaded.

It actually turns out there will be 4 files.

The whole idea I was trying to accomplish was the "force download" with multiple files WITHOUT zipping.

But "All" as I have it programmed does not work. That's download_all.php (original attachment).

Richard
0
Dave BaldwinFixer of ProblemsCommented:
You might try using 'curl' in the 'download_all' file to call the individual files one at a time.
0
Richard KortsAuthor Commented:
Dave,

Can you provide me with a reference link to 'curl'? I have seen that used (like in the API for Authorize.net) but I never understood it.

Thanks
0
Dave BaldwinFixer of ProblemsCommented:
Here it is but I'm not sure that it will work in your situation.  http://php.net/manual/en/book.curl.php
0
Richard KortsAuthor Commented:
I talked the customer into the zip option if multiple files are selected.

So unknown if it can work as I described.

Thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.