Back to PhocaDownloadDownload class

Method download

public static
download
(mixed $fileData, mixed $downloadId, mixed $currentLink, mixed $type = 0)

Method download - Source code

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;
}