Source of file DownloadableFileController.php
Size: 5,335 Bytes - Last Modified: 2021-12-24T05:16:37+00:00
/var/www/docs.ssmods.com/process/src/code/control/DownloadableFileController.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 | <?php /** * Core controller responsible for determining if the current user can * download the file selected. * * A lot of this code is taken and modified from the "secure asssts" * Silverstripe Module */ class DownloadableFileController extends Controller { private static $admin_permissions = [ "ADMIN", "CATALOGUE_EDIT_PRODUCTS", "CMSACCESSAssetAdmin" ]; // We calculate the timelimit based on the filesize. Set to 0 to give unlimited timelimit. // The calculation is: give enough time for the user with x kB/s connection to donwload the entire file. // E.g. The default 50kB/s equates to 348 minutes per 1GB file. private static $min_download_bandwidth = 50; // [in kilobytes per second] /** * Process all incoming requests passed to this controller, checking * that the file exists and passing the file through if possible. */ public function handleRequest(SS_HTTPRequest $request, DataModel $model) { // Copied from Controller::handleRequest() $this->pushCurrent(); $this->urlParams = $request->allParams(); $this->request = $request; $this->response = new SS_HTTPResponse(); $this->setDataModel($model); $url = array_key_exists('url', $_GET) ? $_GET['url'] : $_SERVER['REQUEST_URI']; // remove any relative base URL and prefixed slash that get appended to the file path // e.g. /mysite/assets/test.txt should become assets/test.txt to match the Filename field on File record $url = Director::makeRelative(ltrim(str_replace(BASE_URL, '', $url), '/')); $file = File::find($url); if($this->canDownloadFile($file)) { // If we're trying to access a resampled image. if(preg_match('/_resampled\/[^-]+-/', $url)) { // File::find() will always return the original image, but we still want to serve the resampled version. $file = new Image(); $file->Filename = $url; } $this->extend('onBeforeSendFile', $file); return $this->sendFile($file); } else { if($file instanceof File) { // Permission failure Security::permissionFailure($this, 'You are not authorised to access this resource. Please log in.'); } else { // File doesn't exist $this->response = new SS_HTTPResponse('File Not Found', 404); } } return $this->response; } /** * Output file to the browser. * For performance reasons, we avoid SS_HTTPResponse and just output the contents instead. */ public function sendFile($file) { $path = $file->getFullPath(); if(SapphireTest::is_running_test()) { return file_get_contents($path); } header('Content-Description: File Transfer'); // Quotes needed to retain spaces (http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download) header('Content-Disposition: inline; filename="' . basename($path) . '"'); header('Content-Length: ' . $file->getAbsoluteSize()); header('Content-Type: ' . HTTP::get_mime_type($file->getRelativePath())); header('Content-Transfer-Encoding: binary'); // Fixes IE6,7,8 file downloads over HTTPS bug (http://support.microsoft.com/kb/812935) header('Pragma: '); if($this->config()->min_download_bandwidth) { // Allow the download to last long enough to allow full download with min_download_bandwidth connection. increase_time_limit_to((int)(filesize($path)/($this->config()->min_download_bandwidth*1024))); } else { // Remove the timelimit. increase_time_limit_to(0); } // Clear PHP buffer, otherwise the script will try to allocate memory for entire file. while (ob_get_level() > 0) { ob_end_flush(); } // Prevent blocking of the session file by PHP. Without this the user can't visit another page of the same // website during download (see http://konrness.com/php5/how-to-prevent-blocking-php-requests/) session_write_close(); readfile($path); die(); } /** * Determine if the file we found can be downloaded or not * * @return Boolean */ public function canDownloadFile(File $file = null) { if($file instanceof File) { $product = DownloadableProduct::get() ->filter("FileID", $file->ID) ->first(); if($product && ($product->canDownload() || $this->hasAccess())) return true; } return false; } public function hasAccess() { $request = $this->getRequest(); $return = false; $order_id = $request->getVar("o"); $key = $request->getVar("k"); $url = array_key_exists('url', $_GET) ? $_GET['url'] : $_SERVER['REQUEST_URI']; $url = Director::makeRelative(ltrim(str_replace(BASE_URL, '', $url), '/')); $file = File::find($url); // if the current user has global permissions, allow them access if (Permission::check($this->config()->admin_permissions)) { return true; } // Otherwise, look for the current order $order = Order::get()->byID($order_id); if ($order) { $return = $order->AccessKey == $key ? true : false; if ($return) { $product = DownloadableProduct::get() ->filter("FileID", $file->ID) ->first(); if($product) { $life = $product->LinkLife; $origin = new DateTime($order->dbObject('LastEdited')->Rfc822()); $now = new DateTime(); $diff = (int) $now->diff($origin)->format('%d'); if ($life < $diff) { $return = false; } } else { $return = false; } } } return $return; } } |