public static function download($fileData, $downloadId, $currentLink, $type = 0)
{
$app = Factory::getApplication();
$params = $app->getParams();
$directLink = $fileData['directlink'];
// Direct Link 0 or 1
$externalLink = $fileData['externallink'];
$absOrRelFile = $fileData['file'];
// Relative Path or Absolute Path
// Type = 1 - Token - unique download link - cannot be direct
if ($type == 1) {
$directLink = 0;
}
// NO FILES FOUND (abs file)
$error = false;
$error = preg_match("/COM_PHOCADOWNLOAD_ERROR/i", $absOrRelFile);
if ($error) {
$msg = Text::_('COM_PHOCADOWNLOAD_ERROR_WHILE_DOWNLOADING_FILE') . ' ' . Text::_($absOrRelFile);
$app->enqueueMessage($msg, 'error');
$app->redirect(Route::_($currentLink));
} else {
// Get extensions
$extension = File::getExt(strtolower($absOrRelFile));
$aft = $params->get('allowed_file_types_download', PhocaDownloadSettings::getDefaultAllowedMimeTypesDownload());
$dft = $params->get('disallowed_file_types_download', '');
$check_http_range = $params->get('check_http_range', 1);
// Get Mime from params ( ext --> mime)
$allowedMimeType = PhocaDownloadFile::getMimeType($extension, $aft);
$disallowedMimeType = PhocaDownloadFile::getMimeType($extension, $dft);
// NO MIME FOUND
$errorAllowed = false;
// !!! IF YES - Disallow Downloading
$errorDisallowed = false;
// !!! IF YES - Allow Downloading
$errorAllowed = preg_match("/PhocaError/i", $allowedMimeType);
$errorDisallowed = preg_match("/PhocaError/i", $disallowedMimeType);
$ignoreDownloadCheck = $params->get('ignore_file_types_check', 2);
if ($ignoreDownloadCheck == 3 || $ignoreDownloadCheck == 4 || $ignoreDownloadCheck == 5) {
$errorAllowed = false;
$errorDisallowed = true;
}
if ($errorAllowed) {
$msg = Text::_('COM_PHOCADOWNLOAD_WARNFILETYPE_DOWNLOAD');
$app->enqueueMessage($msg, 'error');
$app->redirect(Route::_($currentLink));
} else {
if (!$errorDisallowed) {
$msg = Text::_('COM_PHOCADOWNLOAD_WARNFILETYPE_DISALLOWED_DOWNLOAD');
$app->enqueueMessage($msg, 'error');
$app->redirect(Route::_($currentLink));
} else {
if ($directLink == 1) {
// Direct Link on the same server
$fileWithoutPath = basename($absOrRelFile);
$addHit = self::hit($downloadId);
if ($type == 1) {
self::hitToken($downloadId);
}
if ((int) $params->get('send_mail_download', 0) > 0) {
PhocaDownloadMail::sendMail((int) $params->get('send_mail_download', 0), $fileWithoutPath, 1);
}
// USER Statistics
if ((int) $params->get('enable_user_statistics', 1) == 1) {
$addUserStat = PhocaDownloadStat::createUserStatEntry($downloadId);
}
PhocaDownloadLog::log($downloadId, 1);
$app->redirect($absOrRelFile);
exit;
} else {
if ($directLink == 0 && $externalLink != '') {
// External Link but with redirect
// In case there is directLink the external Link does not go this way but directly to the external URL
$addHit = self::hit($downloadId);
if ($type == 1) {
self::hitToken($downloadId);
}
if ((int) $params->get('send_mail_download', 0) > 0) {
PhocaDownloadMail::sendMail((int) $params->get('send_mail_download', 0), $externalLink, 1);
}
// USER Statistics
if ((int) $params->get('enable_user_statistics', 1) == 1) {
$addUserStat = PhocaDownloadStat::createUserStatEntry($downloadId);
}
PhocaDownloadLog::log($downloadId, 1);
$app->redirect($externalLink);
exit;
} else {
// Clears file status cache
clearstatcache();
$fileWithoutPath = basename($absOrRelFile);
$fileSize = filesize($absOrRelFile);
$mimeType = '';
$mimeType = $allowedMimeType;
// HIT Statistics
$addHit = self::hit($downloadId);
if ($type == 1) {
self::hitToken($downloadId);
}
if ((int) $params->get('send_mail_download', 0) > 0) {
PhocaDownloadMail::sendMail((int) $params->get('send_mail_download', 0), $fileWithoutPath, 1);
}
// USER Statistics
if ((int) $params->get('enable_user_statistics', 1) == 1) {
$addUserStat = PhocaDownloadStat::createUserStatEntry($downloadId);
}
PhocaDownloadLog::log($downloadId, 1);
if ($fileSize == 0) {
die(Text::_('COM_PHOCADOWNLOAD_FILE_SIZE_EMPTY'));
exit;
}
// Clean the output buffer
ob_end_clean();
// test for protocol and set the appropriate headers
jimport('joomla.environment.uri');
$_tmp_uri = Uri::getInstance(Uri::current());
$_tmp_protocol = $_tmp_uri->getScheme();
if ($_tmp_protocol == "https") {
// SSL Support
header('Cache-Control: private, max-age=0, must-revalidate, no-store');
} else {
header("Cache-Control: public, must-revalidate");
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header("Pragma: no-cache");
header("Expires: 0");
}
/* end if protocol https */
header("Content-Description: File Transfer");
header("Expires: Sat, 30 Dec 1990 07:07:07 GMT");
header("Accept-Ranges: bytes");
// HTTP Range
/* $httpRange = 0;
if(isset($_SERVER['HTTP_RANGE'])) {
list($a, $httpRange) = explode('=', $_SERVER['HTTP_RANGE']);
str_replace($httpRange, '-', $httpRange);
$newFileSize = $fileSize - 1;
$newFileSizeHR = $fileSize - $httpRange;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: ".(string)$newFileSizeHR);
header("Content-Range: bytes ".$httpRange . $newFileSize .'/'. $fileSize);
} else {
$newFileSize = $fileSize - 1;
header("Content-Length: ".(string)$fileSize);
header("Content-Range: bytes 0-".$newFileSize . '/'.$fileSize);
}
header("Content-Type: " . (string)$mimeType);
header('Content-Disposition: attachment; filename="'.$fileWithoutPath.'"');
header("Content-Transfer-Encoding: binary\n");*/
// Modified by Rene
// HTTP Range - see RFC2616 for more informations (http://www.ietf.org/rfc/rfc2616.txt)
$httpRange = 0;
$newFileSize = $fileSize - 1;
// Default values! Will be overridden if a valid range header field was detected!
$resultLenght = (string) $fileSize;
$resultRange = "0-" . $newFileSize;
// We support requests for a single range only.
// So we check if we have a range field. If yes ensure that it is a valid one.
// If it is not valid we ignore it and sending the whole file.
if ((int) $check_http_range == 1 && isset($_SERVER['HTTP_RANGE']) && preg_match('%^bytes=\\d*\\-\\d*$%', $_SERVER['HTTP_RANGE'])) {
// Let's take the right side
list($a, $httpRange) = explode('=', $_SERVER['HTTP_RANGE']);
// and get the two values (as strings!)
$httpRange = explode('-', $httpRange);
// Check if we have values! If not we have nothing to do!
if (!empty($httpRange[0]) || !empty($httpRange[1])) {
// We need the new content length ...
$resultLenght = $fileSize - $httpRange[0] - $httpRange[1];
// ... and we can add the 206 Status.
header("HTTP/1.1 206 Partial Content");
// Now we need the content-range, so we have to build it depending on the given range!
// ex.: -500 -> the last 500 bytes
if (empty($httpRange[0])) {
$resultRange = $resultLenght . '-' . $newFileSize;
} elseif (empty($httpRange[1])) {
$resultRange = $httpRange[0] . '-' . $newFileSize;
} else {
$resultRange = $httpRange[0] . '-' . $httpRange[1];
}
//header("Content-Range: bytes ".$httpRange . $newFileSize .'/'. $fileSize);
}
}
header("Content-Length: " . $resultLenght);
header("Content-Range: bytes " . $resultRange . '/' . $fileSize);
header("Content-Type: " . (string) $mimeType);
header('Content-Disposition: attachment; filename="' . $fileWithoutPath . '"');
header("Content-Transfer-Encoding: binary\n");
// TEST TEMP SOLUTION - makes problems on somve server, @ added to prevent from warning
// Do problems on some servers
//@ob_end_clean();
//@readfile($absOrRelFile);
// Try to deliver in chunks
@set_time_limit(0);
$fp = @fopen($absOrRelFile, 'rb');
if ($fp !== false) {
while (!feof($fp)) {
echo fread($fp, 8192);
}
fclose($fp);
} else {
@readfile($absOrRelFile);
}
flush();
exit;
/*
https://www.phoca.cz/forum/viewtopic.php?f=31&t=11811
$fp = @fopen($absOrRelFile, 'rb');
// HTTP Range - see RFC2616 for more informations (http://www.ietf.org/rfc/rfc2616.txt)
$newFileSize = $fileSize - 1;
// Default values! Will be overridden if a valid range header field was detected!
$rangeStart = 0;
$rangeEnd = 0;
$resultLength = $fileSize;
// We support requests for a single range only.
// So we check if we have a range field. If yes ensure that it is a valid one.
// If it is not valid we ignore it and sending the whole file.
if ($fp && isset($_SERVER['HTTP_RANGE']) && preg_match('%^bytes=\d*\-\d*$%', $_SERVER['HTTP_RANGE'])) {
// Let's take the right side
list($a, $httpRange) = explode('=', $_SERVER['HTTP_RANGE']);
// and get the two values (as strings!)
$httpRange = explode('-', $httpRange);
// Check if we have values! If not we have nothing to do!
if (sizeof($httpRange) == 2) {
// Explictly convert to int
$rangeStart = intval($httpRange[0]);
$rangeEnd = intval($httpRange[1]); // Allowed to be empty == 0
if (($rangeStart || $rangeEnd) // something actually set?
&& $rangeStart < $fileSize // must be smaller
&& $rangeEnd < $fileSize // must be smaller
&& (!$rangeEnd || $rangeEnd > $rangeStart) // end > start, if end is set
) {
header("HTTP/1.1 206 Partial Content");
if (!$rangeEnd) {
$resultLength = $fileSize - $rangeStart;
$range = $rangeStart . "-" . ($fileSize - 1) . "/" . $fileSize;
} else {
$resultLength = ($rangeEnd - $rangeStart 1);
$range = $rangeStart . "-" . $rangeEnd . "/" . $fileSize;
}
header("Content-Range: bytes " . $range);
} else {
// Didn't validate: kill
$rangeStart = 0;
$rangeEnd = 0;
}
}
}
header("Content-Length: ". $resultLength);
header("Content-Type: " . (string)$mimeType);
header('Content-Disposition: attachment; filename="'.$fileWithoutPath.'"');
header("Content-Transfer-Encoding: binary\n");
@@ -211,13 +198,25 @@ class PhocaDownloadAccessFront
// Try to deliver in chunks
@set_time_limit(0);
if ($fp !== false) {
if ($rangeStart) {
// Need to pass only part of the file, starting at $rangeStart
fseek($fp, $rangeStart, SEEK_SET);
}
// If $rangeEnd is open ended (0, whole file from $rangeStart) try fpassthru,
// else send in small chunks
if ($rangeEnd || @!fpassthru($fp)) {
while ($resultLength > 0 && !feof($fp)) {
// 4 * 1460 (default MSS with ethernet 1500 MTU)
// This is optimized for network packets, not disk access
$bytes = min(5840, $resultLength);
echo fread($fp, $bytes);
$resultLength = $resultLength - $bytes;
}
}
fclose($fp);
} else {
// Ranges are disabled at this point and were never set up
@readfile($absOrRelFile);
}
flush();
exit;
*/
}
}
}
}
}
return false;
}