php nginx proxy remote file download - php

I want to "proxy" a file located on a remote server (let's call it Server B) and force its download to the visitor, from Server A.
Only Server A can access the ressource on Server B (IP address secured). The ressource can weight up to a few gigabytes.
Here is my code so far:
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$filename);
header('Content-Transfer-Encoding: chunked');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
$stream = fopen('php://output', 'w');
$ch = curl_init($ruri);
curl_setopt($ch, CURLOPT_READFUNCTION, function($ch, $fd, $length) use ($stream) {
return fwrite($stream, fread($fd, $length));
});
curl_exec($ch);
curl_close($ch);
It works partially.
Problem number 1:
The visitor cannot browse any page of the website on Server A while he is downloading the ressource. Why?
Problem number 2:
It does not support pause or resume download. Apparently I can solve it using "range" headers. I did not try yet since "problem number 1" is a big problem, and I would like to solve it first before going further in that direction.
Please note:
I do not want the ressource to be fully downloaded on Server A's disk before serving it to the visitor, I want it to be "forwarded" directly to the visitor (aka "proxy"?)
I read posts about readfile() and file_get_content(), I tried, same problems. Not even mentionning how much these functions "stress" Server A (CPU, Memory), especially with big files.
Isn't there a way to do it more efficiently? I mean without PHP, but rather trough Apache or Nginx?

Related

php proxy remote file download

I am willing to "proxy" a file located on a remote server (let's call it Server B) and force its download to the visitor, from Server A.
Only Server A can access the ressource on Server B (IP address secured). The ressource can weight up to a few gigabytes.
Here is my code so far:
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$filename);
header('Content-Transfer-Encoding: chunked');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
$stream = fopen('php://output', 'w');
$ch = curl_init($ruri);
curl_setopt($ch, CURLOPT_READFUNCTION, function($ch, $fd, $length) use ($stream) {
return fwrite($stream, fread($fd, $length));
});
curl_exec($ch);
curl_close($ch);
It works partially.
Problem number 1:
The visitor cannot browse any page of the website on Server A while he is downloading the ressource. Why?
Problem number 2:
It does not support pause or resume download. Apparently I can solve it using "range" headers. I did not try yet since "problem number 1" is a big problem, and I would like to solve it first before going further in that direction.
Please note:
I do not want the ressource to be fully downloaded on Server A's disk before serving it to the visitor, I want it to be "forwarded" directly to the visitor (aka "proxy"?)
I read posts about readfile() and file_get_content(), I tried, same problems. Not even mentionning how much these functions "stress" Server A (CPU, Memory), especially with big files.
Isn't there a way to do it more efficiently? I mean without PHP, but rather trough Apache or Nginx?

Redirect to any url right after downloading file from server using php

Header("location:index.php"); is not working for me.
$file is path of file.
if (file_exists($file)) {
header('Content-Description: File Transfer');
//header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
header("Content-Type: application/force-download");
readfile($file);
header("location:index.php");
exit;
}
Your browser makes a call to the server. The server responds with headers ("I will be sending a file") and sends the content. Browser reads headers and instead of showing the new page it offers you to save the file. All further actions are ignored.
If you want both file download and redirect, you have to send the request for download to another container (new tab, new window, iframe) and redirect the main window elsewhere with javascript.

How to read file from another FTP host without use host bandwidth transfer

I have a host for store data and a download host (this host doesn't have database). I want to read a file from download host in store host and give it to user for download but I don't want to use monthly bandwidth transfer of store host when user is downloading file and just use download host bandwidth transfer.
There are two ways that I know:
ftp_get download the file and save it in a local file and then set header for download. I don't want use this way because download file in store host.
// in store host
$local_file = 'app.apk';
$ftp_file = '/uploads/2015/06/1eb6a628c60bb69a6b6092d03e252c29.apk';
// download file and save it in local
ftp_get($conn_id , $local_file, $ftp_file, FTP_BINARY);
$file_name = 'app.apk';
$file_size = filesize($local_file);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $file_name);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $file_size);
readfile($local_file);
I don't know file_get_contents use bandwidth transfer of store host when user is downloading file or not.
// in store host
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $file_name);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $file_size);
// readfile($local_file);
$c = file_get_contents('ftp://login:pass#download-host.com/uploads/2015/06/app.apk');
echo $c;
I don't want to use bandwidth transfer in store host; Which way can I use? Way 2 or another way?
There's no way to download a contents from the "download host" directly to the client, without providing the client with all the information needed for the download ("download link").
If you need to hide the download information from the client, you need to download the file on the "store host" and then forward it to the client. Hence you are consuming bandwidth data of the "store host". It does not matter what technology, protocol or function you use. And the ftp_get and file_get_contents("ftp://...") use both the same code behind anyway.
Simply said, there's no way to both hide the download information from the client and not use bandwidth data of the "store host".

Unable to make a file auto-download from an FTP server when script is run

I am attempting to write a PHP page that takes the GET variable which is a filename within the FTP and download it. However, it does not seem to work. The Function itself (ftp_get) is returning as TRUE as the echo statement is being run, however nothing else happens and there is no errors in console.
<?php
$file = $_GET['file'];
$ftp_server = "127.0.0.1";
$ftp_user_name = "user";
$ftp_user_pass = "pass";
// set up a connection or die
$conn_id = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
if (ftp_get($conn_id, $file, $file, FTP_BINARY)) {
echo "Successfully written to $file\n";
} else {
echo "There was a problem\n";
}
?>
Ideally, I would simply link them to: ftp://example.com/TestFile.txt and it would download the file for them, however, it only shows them the contents of the file in their browser rather than downloading it.
I've gone through the PHP Manual site reading the FTP functions and I do believe ftp_get is the correct one I'm suppose to be using.
Is there potentially an easier way of doing this, or is it just something I'm overlooking?
There are two (or maybe more) ways you can do this. You could store a copy of the file on your server like you do with ftp_get and send it to the user afterwards. Or you could download it every time.
Now you can do this using ftp commands, but there is a quicker way using readfile.
Following the first example from the readfile documentation:
// Save the file as a url
$file = "ftp://{$ftp_user_name}:{$ftp_user_pass}#{$ftp_server}" . $_GET['file'];
// Set the appropriate headers for a file transfer
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// and send them
ob_clean();
flush();
// Send the file
readfile($file);
This will simply fetch the file and forward it's contents to the user. And the header will make the browser save the file as a download.
And you could take this even further. Let's say you save this in a file called script.php in a directory accessible to the user via http://example.com/ftp/. If you are using apache2 and have mod_rewrite enabled you can create a .htaccess file in this directory containing:
RewriteEngine On
RewriteRule ^(.*)$ script.php?file=$1 [L]
When the user navigates to http://exmaple.com/ftp/README.md your script.php file will be called with $_GET['file'] equal to /README.md and the file from ftp://user:pass#ftp.example.com/README.md will be downloaded on his computer.

PHP different servers and security

I currently have several servers, the main ones a web server and an internal storage server. Data is stored in a SQL server database.
Without giving too much access to the user, how would I pull a specific document from the storage server for display to the user from the web server?
For example, I have document c:/memberID/info.pdf on the storage server and I want to display it to the client via PHP without giving them access to the internal storage server.
I hope this makes sense!
Look into readfile as well as headers
<?php
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>

Categories