So my company store all PDF files in Amazon S3 privately.
When the user request it our system pull it from Amazon S3 and then serve it to the user with following code:
header("Cache-Control: public");
header("Pragma: public");
header("Expires: 0");
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="'.$fileName.'"');
header('Content-Length: ' . strlen($res->body));
header("Content-type: application/pdf");
header("Content-Transfer-Encoding: binary");
header('Connection: close');
echo $res->body;
$res is the respond returned from Amazon with the content from $res->body;
I see random slow download speed when the user try to download the PDF files, especially when the PDF is large (~5mb) compare to the rest that only having 800kb-1.5mb.
Solution tried:
1) Removing the content-length header doesn't help.
2) Remove EnableSendfile off in httpd.conf doesn't help either.
I also checked the server to make sure it wasn't the workload of the server that's causing this.
The speed test of both the server and user's workstation looks good too.
Do anyone of you have any idea what is the reason that's causing this slowness?
It might be that multiple people from your company use the internet.
You should do a full scan of the network, but still even then your not alone on the internet, and their "virtual" server environments are shared as well.
from my understanding the issue is that simply takes time to fetch the file from S3 in order to return it to the user.
Make yourself a favor:
create a signed url for a short period time
redirect the user to such url
dont worry, as creating signed urls doesn't expose any private information that compromises your security (if you do ir correctly)
Related
I recently found a youtube video that talked about accessing a PDF in a web browser. It was interesting because as I suspected I could access a PDF most anywhere on the system (given permissions) and pass it along via PHP to a web browser.
I do not want his to become a security discussion so please abstain from security comments!
https://www.youtube.com/watch?v=z4a6QJSGL28
The code looks something like this
$file="/home/kodi/Pictures/scans/test.pdf";
$filename="test.pdf";
header('Content-type: application/pdf');
header('Content-disposition: inline; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
#readfile($file);
So I tested and it works then I tried this
$file="/home/kodi/Pictures/scans/test.jpg";
$filename="test.jpg";
header('Content-type: application/jpg');
header('Content-disposition: inline; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
#readfile($file);
Oddly enough this did NOT display in a web browser, but several seconds later, my preferred app for downloaded jpgs opened and there was the file . It had downloaded instead of opening in browser.
I have been working on a LAN app that can access users folders on the server through PAM authentication and have been using base64 encoding, however I felt that if I could reduce the overhead of base64 images (30%) , conversions and literally converting each image in a list to display links to them, the system would load faster. This would definately be a better way but everyone says that this kind of thing does not work! The proof that there is hope that it will work ios in the file I downloaded from the web server that was in a user folder.
Any ideas how to make it work with jpgs?
Your content type is incorrect, it should be image/jpeg, instead of application/jpg
Without downloading and than sending the data in a body of the request. Is there any way how to just "stream it through"? At the moment I am limited by the memory allocated by PHP as I have to hold the content of the entire file in memory before sending it through ...
I am working on an enterprise App Store for Apple iOS apps (and android too but that is fine with a link) and they require the domain to be same as the server and the server itself is just too small for hosting so many files ... it also requires a valid SSL certificate which I have on the server.
I have tried to link directly to S3 already but it won't work, the only way to do this is to serve the files from the server, thus I have been asking about passing the file over/hiding the original location or I don't know, maybe mounting S3 as a drive?
A proxy using fpassthru needs to be done as suggested by #AD7six as follows:
$handle = #fopen('file path or in this case url to file on S3', 'rb');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache'); //keeps ie happy
header('Content-Disposition: attachment; filename=app.ipa');
header('Content-type: application/octet-stream');
header('Content-Length: '.$fileInfo['size']); // taken from a previous S3 API call to get object info
header('Content-Transfer-Encoding: binary');
ob_end_clean(); // apparently very important for bigger files
fpassthru($handle); // proxy stream file through your server
exit();
Have you read the official documentation of S3?
See this answer: How to create download link for an Amazon S3 bucket's object?
There is no need to push the data through your server to send it to the client. In the case you need protected downloadable items, there is as well a way to give the download link a token that is only valid for a given amount of time.
I have used following code to download approximate 920MB file,
set_time_limit(0);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("X-Sendfile: $zipname"); // For Large Files
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"".$zipname."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($directory_location . '/' . $zipname));
ob_end_flush();
readfile($directory_location . '/' . $zipname);
Before this code i did some study with the following links Using X-Sendfile with Apache/PHP, Streaming a large file using PHP and Limit download speed using PHP but not much helpful to me because file download still takes more time with just (2MB) file. It's not showing and transfer rate or anything else. I want download start to serve file with around 60Kbps, with all files (Large or small)
UPDATE: One more thing i noticed its not showing any download process just executing and after sometime display the pop-up to choose the location, and after hitting save button its direct save to the computer without any downloading process window :(
Please help me to guide the right way.
Based on above comments there are two solutions:
1) Just download the file directly. You don't appear to be doing any validation, so if not, then just pass the user to the file to download and let apache handle it.
2) If you do need validation / pre-processing, then check mod_xsendfile - adding the header isn't enough, you actually need to add the mod to apache. If you're in Linux then compile from source (https://tn123.org/mod_xsendfile/). If you're not in Linux then mod_xsendfile for Win x64? has a response from the author saying he can provide binaries - but that's in 2010. There's a bit of advice around the web - although it's been a while since I looked at it so can't really help much more.
I am currently trying to develop a PHP application in which my server downloads a file and the user can do the same almost simultaneously. I already think about the problem "If the user downloads fastly than the server...", but it's not a problem at this moment.
To do so, I used the header and readfile functions of php. Here is my code :
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$data['name'].'";');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.$data['size']);
readfile($remoteFile);
I must to use the Content-length header to set the proper size of the file and not the size that is downloaded when the user clicks on the link. However, after some seconds or minutes, download is stopped and I need to restart...
If you think about a solution, even if it didn't use the header(); function, please tell me.
Thank you in advance...
I have experienced that this is directly related to maximum runtime settings, that are enforced upon you if you run with safe_mode on.
If you have the option, try setting set_time_limit(0) and see if that makes it work.
if you have your own server, you should look into the mod_xsendfile module for apache, since that is built specifically to send large files to the user.
Oh, and its stupidly easy to use
header("X-Sendfile: $path_to_somefile");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$somefile\"");
exit;
I am not a web developer by all means. But I am trying to help someone deliver a video from their server. Basically when the user clicks a button on the website, we want the user to be prompted to download the video. So after Googling for a while I figured out how to write a short php script using content-disposition:
<?php
$fn = 'videoFile.mp4';
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header('Content-Description: File Transfer');
header('Content-type: video/mp4');
header('Content-Length: '.filesize($fn));
header('Content-disposition: attachment; filename='.$fn);
readfile($fn);
?>
So the button on the website points to this script. PC browsers seem to start the download with no problem. But the main focus of this is for Android phones. When you click to download the file on the default Android Browser, it fails and all it says is "Download Unsuccessful".
Another thing is that on my computer (using Firefox), the download starts and at about 200MB, it just stops. It doesn't show any signs of failure, it just looks like it finished downloading. The actual file size is about 1GB.
I have played around with the content-type quite a bit, hoping that was the problem. I used "video/mpeg" and "application/force-download" and neither of them worked.
Is there something I'm not doing write? Could the 2 problems be related? Should I be going about this a different way? Thanks for any input.
The Android browser does not appear to like Content-disposition: and related headers. I recommend just a plain redirect to the file in question.