public static function download($fileData, $downloadId, $currentLink, $type = 0) { $app = JFactory::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 = JText::_('COM_PHOCADOWNLOAD_ERROR_WHILE_DOWNLOADING_FILE') . ' ' . JText::_($absOrRelFile); $app->redirect(JRoute::_($currentLink), $msg); } else { // Get extensions $extension = JFile::getExt(strtolower($absOrRelFile)); $aft = $params->get('allowed_file_types_download', PhocaDownloadSettings::getDefaultAllowedMimeTypesDownload()); $dft = $params->get('disallowed_file_types_download', ''); // 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 = JText::_('COM_PHOCADOWNLOAD_WARNFILETYPE_DOWNLOAD'); $app->redirect(JRoute::_($currentLink), $msg); } else { if (!$errorDisallowed) { $msg = JText::_('COM_PHOCADOWNLOAD_WARNFILETYPE_DISALLOWED_DOWNLOAD'); $app->redirect(JRoute::_($currentLink), $msg); } 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(JText::_('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 = JURI::getInstance(JURI::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 (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 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; /* http://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; }
function _save($data, $filename, &$errSaveMsg, $fileExists = 0) { $user = JFactory::getUser(); $fileId = false; if ($fileExists == 1) { // We not only owerwrite the file but we must update it if (isset($filename) && $filename != '') { $db = JFactory::getDBO(); $query = 'SELECT a.id AS id' .' FROM #__phocadownload AS a' .' WHERE a.filename = '.$db->Quote($filename); $db->setQuery($query, 0, 1); $fileId = $db->loadObject(); if (!$db->query()) { $this->setError($db->getErrorMsg()); return false; } } } $row = $this->getTable('phocadownload'); if (isset($fileId->id) && (int)$fileId->id > 0) { $data['id'] = (int)$fileId->id; } $data['filesize'] = PhocaDownloadFile::getFileSize($filename, 0); $data['userid'] = $user->id; $data['author_email'] = $data['email']; $data['author_url'] = $data['website']; $data['token'] = PhocaDownloadUtils::getToken($data['title'].$filename); //$data['token'] = PhocaDownloadUtils::getToken($data['title'].$data['filename']); // Bind the form fields to the Phoca gallery table if (!$row->bind($data)) { $this->setError($this->_db->getErrorMsg()); return false; } // Create the timestamp for the date //$row->date = gmdate('Y-m-d H:i:s'); //$row->publish_up = gmdate('Y-m-d H:i:s'); //$jnow =JFactory::getDate(); /*$jnowU = $jnow->toUnix(); if (isset($jnowU)) { $jnowU = (int)$jnowU - 2; // to not display pending because of 1 second }*/ $unow = time(); $unow = $unow - 2;//Frontend will display pending if standard $jnow->toSql(); will be used $jnow = JFactory::getDate($unow);// the class JDate construct works with unix date $now = $jnow->toSql(); $row->date = $now; $row->publish_up = $now; //date('Y-m-d H:i:s', $jnowU); $row->publish_down = null; $row->filename = $filename; $row->catid = $data['catidfiles']; // Lang $userLang = PhocaDownloadUser::getUserLang(); $row->language = $userLang['lang']; // if new item, order last in appropriate group if (!$row->id) { $where = 'catid = ' . (int) $row->catid ; $row->ordering = $row->getNextOrder( $where ); } // Make sure the Phoca gallery table is valid if (!$row->check()) { $this->setError($this->_db->getErrorMsg()); return false; } // Store the Phoca gallery table to the database if (!$row->store()) { $this->setError($this->_db->getErrorMsg()); return false; } PhocaDownloadLog::log($row->id, 2); return true; }