Skip to content
Snippets Groups Projects

Resolve "Fix Downloading of files"

Merged Dominik Hebeler requested to merge 20-fix-downloading-of-files into master
4 files
+ 133
14
Compare changes
  • Side-by-side
  • Inline
Files
4
+ 103
0
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Log;
class DownloadController extends Controller
{
// How many hours is a Download link valid
const DOWNLOADLINKVALIDHOURS = 1;
public function redirector(Request $request)
{
return redirect(route('download', [
"url" => $request->input('url', 'https://metager.de'),
"valid-until" => $request->input('valid-until', ''),
"password" => $request->input('password', '')
]));
}
public function download(Request $request)
{
$url = $request->input("url");
$headers = get_headers($url, 1);
$filename = basename($url);
# From the headers we need to remove the first Element since it's the status code:
$status = $headers[0];
$status = intval(preg_split("/\s+/si", $status)[1]);
array_forget($headers, 0);
# Add the Filename if it's not set:
if (!isset($headers["Content-Disposition"])) {
$headers["Content-Disposition"] = "inline; filename=\"" . $filename . "\"";
} elseif (preg_match("/filename=\"{0,1}(.*?)(\"|\s|$)/", $headers["Content-Disposition"], $matches)) {
$filename = $matches[1];
}
$response = new StreamedResponse(function () use ($url) {
# We are gonna stream a large file
$wh = fopen('php://output', 'r+');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 256);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, 50000);
curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, 5);
curl_setopt($ch, CURLOPT_FILE, $wh); // Data will be sent to our stream ;-)
curl_exec($ch);
curl_close($ch);
// Don't forget to close the "file" / stream
fclose($wh);
}, 200, $headers);
$response->send();
return $response;
}
public static function generateDownloadLinkParameters($url)
{
$validUntil = self::generateValidUntilDate();
$password = self::generatePassword($url, $validUntil);
return [
"url" => $url,
"valid-until" => $validUntil,
"password" => $password
];
}
/**
* This function generates a Date/Time String which is used by our Download Controller
* to check if a download link is valid.
* This Date/Time is used in the password hash, too to make sure it is not altered
*/
private static function generateValidUntilDate()
{
$validUntil = Carbon::now()->setTimezone("UTC");
$validUntil->addHours(self::DOWNLOADLINKVALIDHOURS);
return $validUntil->format("d-m-Y H:i:s P");
}
/**
* This function generates the password for Download Links
* The password is an hmac with the proxy password.
* Algo is SHA256
* Data is $url . $validUntil
* When verifying the password we can verify integrity of the supplied valid-until argument
*/
private static function generatePassword($url, $validUntil)
{
return hash_hmac("sha256", $url . $validUntil, env("PROXY_PASSWORD", "unsecure_password"));
}
}
Loading