• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 499
  • Last Modified:

What is preventing the forced file transfer on our server?

We have written a page that works fine on our test Apache server, but fails on the live server.

The page allows the user to download jpg images by clicking on a thumbnail.

We force the download by using the following code:

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . basename($file));
    header('Content-Transfer-Encoding: binary');
               
                // Read the file from disk
                readfile($file);

It seems to find the file but the resulting file is always 1 byte in length.

QUESTION: Is there some setting on our server that disallows the forced download of octet stream, binary stream etc?
0
rascal
Asked:
rascal
  • 7
  • 5
  • 5
4 Solutions
 
V4nP3rs13Commented:
Are the images in the same directory as download page? Maybe something like this:
readfile('images/'.$file);
0
 
V4nP3rs13Commented:
Are the images in the same directory as download page? Maybe something like this:
readfile('images/'.$file);
0
 
Ray PaseurCommented:
I can show you a PHP script to force a download.  You might also consider whether you can just give the client a link to the image, and let them click (or right-click) and save.  The plain HTML implementation is pretty easy for everyone to understand.
<?php // RAY_force_download.php
error_reporting(E_ALL);


// A FILE TO DOWNLOAD - THIS LINK COULD COME IN THE URL VIA $_GET OR COULD BE GENERATED INSIDE THE SCRIPT
$url = "http://a0.twimg.com/a/1252097501/images/twitter_logo_header.png";
$url = "http://www.google.com/intl/en_ALL/images/logo.gif";

// USE CASE
force_download($url);


// FUNCTION TO FORCE A DOWNLOAD
function force_download($filename)
{
    // GET A NAME FOR THE FILE
    $basename = basename($filename);

    // GET THE CONTENTS OF THE FILE
    $filedata = file_get_contents($filename);

    if ($filedata)
    {
        // THESE HEADERS ARE USED ON ALL BROWSERS
        header("Content-Type: application-x/force-download");
        header("Content-Disposition: attachment; filename=\"$basename\"");
        header("Content-length: ".(string)(strlen($filedata)));
        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();

        // CAPTURE THE FILE IN THE OUTPUT BUFFERS - WILL BE FLUSHED AT SCRIPT END
        ob_start();
        echo $filedata;
    }
}

Open in new window

0
[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

 
Ray PaseurCommented:
Here is a simpler approach.

HTH, ~Ray
<?php // RAY_temp_link.php
error_reporting(E_ALL);

// A URL
$url = "http://www.google.com/intl/en_ALL/images/logo.gif";

// A FILE NAME
$nom = basename($url);

// A LINK
echo "<a target=\"img\" href=\"$url\">$nom</a>" . PHP_EOL;

Open in new window

0
 
V4nP3rs13Commented:
ray.. you are complicating a little... He wanted the direct link to download... not to open the image and then client save it... everyone knows for a href :) but he wanted something very different from that

here is my code:
<?php
    $file = 'images/example.jpg'; //change or delete this line.. it's just an example
    $filetype = substr($file, 0, -3);
    header("Content-Type:image/$filetype");
    header("Content-Disposition:attachment;filename=images/$file");
?>
0
 
Ray PaseurCommented:
I posted two tested and working code samples.  I do not think they are too complicated and I know they work as written on most modern browsers.  Pick either one.  You can copy it, install it and run it.  As I wrote in the comments, "THIS LINK COULD COME IN THE URL VIA $_GET" and that would provide an easy way to make this a generalized solution.

If the OP wants to post enough of the code that we can see what is really going on, perhaps we can help a little more.  For example, where are the "thumbnails?"  How are they linked to the downloadable images?  I am fairly certain there is an easy solution that can be integrated into the application and that will work across more than just the test server.
0
 
V4nP3rs13Commented:
he should use while with mysql_fetch_array of mysql_query from the database... in every row displayed by while() he should display the tumbnail and the link to page where the header (for direct download) is

index.php
<?php
$query = mysql_query(SELECT * FROM images);
while($r = mysql_fetch_array($query)) {
echo '<a href="download.php?id='.$r["imageid"].'" width="100px" height="100px"><img src="'.$r["imageurl"].'"></a>';
}
?>

download.php
<?php
$id = $_GET["id"];
if(isset($id)) {
$getImgData = mysql_fetch_array(mysql_query("SELECT * FROM images WHERE imageid = '$id'"));
$filetype = substr($getImgData["imageurl"], 0, -3);
header("Content-Type:image/$filetype");
header("Content-Disposition:attachment;filename=images/$getImgData["imageurl"]");
}
?>


change these in the code: "imageurl", "imageid". Because those are columns in the table "images" in MySQL
0
 
Ray PaseurCommented:
Maybe I am missing something.  I don't see how the part about data base tables would come into play.  I'll go to church now and check back when our Asker has had a chance to try the posted solutions or clarify the question.  If it's about how to use MySQL with safe queries and appropriate error checking, that would seem to be a different line of questioning.

Best to all, ~Ray
0
 
rascalAuthor Commented:
Thanks for all the responses, but I don't think i made myself clear enough:
I already have code that works on my Apache server. It's just that it doesn't work on the live web host's apache server.
My question is: what is it about the live web host's apache server I need to tell them to alter in order to get it to work?
0
 
Ray PaseurCommented:
Please try this.  Install the force-download script on the live web host and test it.  If it works, we know that there is not anything wrong with the live web host.

Then you can either model your script on the force-download script or you can post your script here and we can look at the differences to see what is awry.

Before you waste too much time on this, please check carefully to be sure that the file paths are 100% correct and that you have all the needed permissions.

Also, who is your live web host?  No chance they are running your scripts in "safe mode" is there?
0
 
rascalAuthor Commented:
I tried, and also included a display message. The error message was that the get_file_contents() failed:
"failed to file_get_contents() for file: http://www.<domainname>.com/pages/press/images/_MG_9234_v03.jpg"
Note: I have replaced the actual domain name with <domainname> above. When I pasted the path into my browser, the image appeared fine. So the web host has some setting that is not allowing it.

Also, on my test server, I got the following error:
"[function.file-get-contents]: failed to open stream: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."
I had to wait 60 seconds for this error on my test server, but on the live server the error message they gave happened immediately, so I am not sure the 2 error messages are related.

<?php // RAY_force_download.php 
require_once ("../../include/commonfunctions.php");
error_reporting(E_ALL); 
 
// FUNCTION TO FORCE A DOWNLOAD 
function force_download($filename) 
{ 
    // GET A NAME FOR THE FILE 
    $basename = basename($filename); 
 
    // GET THE CONTENTS OF THE FILE 
    $filedata = file_get_contents($filename); 
 
    if ($filedata) 
    { 
        // THESE HEADERS ARE USED ON ALL BROWSERS 
        header("Content-Type: application-x/force-download"); 
        header("Content-Disposition: attachment; filename=\"$basename\""); 
        header("Content-length: ".(string)(strlen($filedata))); 
        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(); 
 
        // CAPTURE THE FILE IN THE OUTPUT BUFFERS - WILL BE FLUSHED AT SCRIPT END 
        ob_start(); 
        echo $filedata; 
    } 
	else
	{
		echo "failed to file_get_contents() for file: $filename";
		exit();
	}
}
// A FILE TO DOWNLOAD - THIS LINK COULD COME IN THE URL VIA $_GET OR COULD BE GENERATED INSIDE THE SCRIPT 
//$url = "http://a0.twimg.com/a/1252097501/images/twitter_logo_header.png"; 
//$url = "http://www.google.com/intl/en_ALL/images/logo.gif"; 
$url=$g_sSiteRootDirectory . "pages/press/images/" . stripslashes(trim($_REQUEST["f"]));
// USE CASE 
force_download($url); 
?>

Open in new window

0
 
Ray PaseurCommented:
Any chance you could run it EXACTLY the way I posted it, and tell us what happened with the original, unmodified script?  I'm not trying to slow you down, just to eliminate some of the known issues so we do not waste time with a red herring.

Also, please post the fully qualified URL of the file you are trying to download.  I will test from here on my server to see if it works like the Twitter or Google logos.
0
 
V4nP3rs13Commented:
does the live server has the same php version like apache's on test server
0
 
rascalAuthor Commented:
Here is a message from the web host:
The script is working properly but failing to download the file because of the password protection. PHP does not have access to the file via http unless you use curl to authenticate. You can also change your script to use the local file system to locate the file instead of going over http. If you remove the protection the script is execute without any problems.  
Of course it never occurred to me that the apache security on the folder would come into play. (sorry gang!)
The note from the web host above states: "You can also change your script to use the local file system to locate the file instead of going over http".
What would this involve from a script standpoint?
0
 
Ray PaseurCommented:
"use the local file system"

That would mean use relative addressing.  If you can tell us the fully qualified URL of the script and of the file that you want to access, we may be able to help you.  Example:

Script is located in the web root.
Web root has folder named '/images/'
File is '/images/pic.jpg'

Line 7 of the script I posted above at 03/28/10 07:49 AM, ID: 28869271would say something like
$url = "images/pic.jpg";
0
 
rascalAuthor Commented:
Hi all,
I am assuming the web host is accurate when they stated that the transfer could not occur because of the password-protected folder in which everything resides, but I will still try about Ray's suggestion above. Just been delayed slightly. Will let you know how it goes shortly.
0
 
rascalAuthor Commented:
The actual cause of the problem was that the directory had security on it that was preventing the download.
However, all of the suggested solutions were accurate and under normal circumstances would have worked.
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

  • 7
  • 5
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now