public function readFile($filePathOrData, $headerType = "plain", $localName = "", $data = false, $gzip = null, $realfileSystem = false, $byteOffset = -1, $byteLength = -1) { if ($gzip === null) { $gzip = ConfService::getCoreConf("GZIP_COMPRESSION"); } if (!$realfileSystem && $this->wrapperClassName == "fsAccessWrapper") { $originalFilePath = $filePathOrData; $filePathOrData = fsAccessWrapper::patchPathForBaseDir($filePathOrData); } session_write_close(); restore_error_handler(); restore_exception_handler(); set_exception_handler('download_exception_handler'); set_error_handler('download_exception_handler'); // required for IE, otherwise Content-disposition is ignored if (ini_get('zlib.output_compression')) { AJXP_Utils::safeIniSet('zlib.output_compression', 'Off'); } $isFile = !$data && !$gzip; if ($byteLength == -1) { if ($data) { $size = strlen($filePathOrData); } else { if ($realfileSystem) { $size = sprintf("%u", filesize($filePathOrData)); } else { $size = $this->filesystemFileSize($filePathOrData); } } } else { $size = $byteLength; } if ($gzip && ($size > ConfService::getCoreConf("GZIP_LIMIT") || !function_exists("gzencode") || @strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE)) { $gzip = false; // disable gzip } $localName = $localName == "" ? basename(isset($originalFilePath) ? $originalFilePath : $filePathOrData) : $localName; if ($headerType == "plain") { header("Content-type:text/plain"); } else { if ($headerType == "image") { header("Content-Type: " . AJXP_Utils::getImageMimeType(basename($filePathOrData)) . "; name=\"" . $localName . "\""); header("Content-Length: " . $size); header('Cache-Control: public'); } else { /* if (preg_match('/ MSIE /',$_SERVER['HTTP_USER_AGENT']) || preg_match('/ WebKit /',$_SERVER['HTTP_USER_AGENT'])) { $localName = str_replace("+", " ", urlencode(SystemTextEncoding::toUTF8($localName))); } */ if ($isFile) { header("Accept-Ranges: 0-{$size}"); $this->logDebug("Sending accept range 0-{$size}"); } // Check if we have a range header (we are resuming a transfer) if (isset($_SERVER['HTTP_RANGE']) && $isFile && $size != 0) { if ($headerType == "stream_content") { if (extension_loaded('fileinfo') && $this->wrapperClassName == "fsAccessWrapper") { $fInfo = new fInfo(FILEINFO_MIME); $realfile = call_user_func(array($this->wrapperClassName, "getRealFSReference"), $filePathOrData); $mimeType = $fInfo->file($realfile); $splitChar = explode(";", $mimeType); $mimeType = trim($splitChar[0]); $this->logDebug("Detected mime {$mimeType} for {$realfile}"); } else { $mimeType = AJXP_Utils::getStreamingMimeType(basename($filePathOrData)); } header('Content-type: ' . $mimeType); } // multiple ranges, which can become pretty complex, so ignore it for now $ranges = explode('=', $_SERVER['HTTP_RANGE']); $offsets = explode('-', $ranges[1]); $offset = floatval($offsets[0]); $length = floatval($offsets[1]) - $offset; if (!$length) { $length = $size - $offset; } if ($length + $offset > $size || $length < 0) { $length = $size - $offset; } $this->logDebug('Content-Range: bytes ' . $offset . '-' . $length . '/' . $size); header('HTTP/1.1 206 Partial Content'); header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size); header("Content-Length: " . $length); $file = fopen($filePathOrData, 'rb'); fseek($file, 0); $relOffset = $offset; while ($relOffset > 2000000000.0) { // seek to the requested offset, this is 0 if it's not a partial content request fseek($file, 2000000000, SEEK_CUR); $relOffset -= 2000000000; // This works because we never overcome the PHP 32 bit limit } fseek($file, $relOffset, SEEK_CUR); while (ob_get_level()) { ob_end_flush(); } $readSize = 0.0; $bufferSize = 1024 * 8; while (!feof($file) && $readSize < $length && connection_status() == 0) { $this->logDebug("dl reading {$readSize} to {$length}", $_SERVER["HTTP_RANGE"]); echo fread($file, $bufferSize); $readSize += $bufferSize; flush(); } fclose($file); return; } else { if ($gzip) { $gzippedData = $data ? gzencode($filePathOrData, 9) : gzencode(file_get_contents($filePathOrData), 9); $size = strlen($gzippedData); } HTMLWriter::generateAttachmentsHeader($localName, $size, $isFile, $gzip); if ($gzip) { print $gzippedData; return; } } } } if ($data) { print $filePathOrData; } else { if ($this->getFilteredOption("USE_XSENDFILE", $this->repository->getId()) && $this->wrapperClassName == "fsAccessWrapper") { if (!$realfileSystem) { $filePathOrData = fsAccessWrapper::getRealFSReference($filePathOrData); } $filePathOrData = str_replace("\\", "/", $filePathOrData); $server_name = $_SERVER["SERVER_SOFTWARE"]; $regex = '/^(lighttpd\\/1.4).([0-9]{2}$|[0-9]{3}$|[0-9]{4}$)+/'; if (preg_match($regex, $server_name)) { $header_sendfile = "X-LIGHTTPD-send-file"; } else { $header_sendfile = "X-Sendfile"; } header($header_sendfile . ": " . SystemTextEncoding::toUTF8($filePathOrData)); header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($filePathOrData) . '"'); return; } if ($this->getFilteredOption("USE_XACCELREDIRECT", $this->repository->getId()) && $this->wrapperClassName == "fsAccessWrapper" && array_key_exists("X-Accel-Mapping", $_SERVER)) { if (!$realfileSystem) { $filePathOrData = fsAccessWrapper::getRealFSReference($filePathOrData); } $filePathOrData = str_replace("\\", "/", $filePathOrData); $filePathOrData = SystemTextEncoding::toUTF8($filePathOrData); $mapping = explode('=', $_SERVER['X-Accel-Mapping']); $replacecount = 0; $accelfile = str_replace($mapping[0], $mapping[1], $filePathOrData, $replacecount); if ($replacecount == 1) { header("X-Accel-Redirect: {$accelfile}"); header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($accelfile) . '"'); return; } else { $this->logError("X-Accel-Redirect", "Problem with X-Accel-Mapping for file {$filePathOrData}"); } } $stream = fopen("php://output", "a"); if ($realfileSystem) { $this->logDebug("realFS!", array("file" => $filePathOrData)); $fp = fopen($filePathOrData, "rb"); if ($byteOffset != -1) { fseek($fp, $byteOffset); } $sentSize = 0; $readChunk = 4096; while (!feof($fp)) { if ($byteLength != -1 && $sentSize + $readChunk >= $byteLength) { // compute last chunk and break after $readChunk = $byteLength - $sentSize; $break = true; } $data = fread($fp, $readChunk); $dataSize = strlen($data); fwrite($stream, $data, $dataSize); $sentSize += $dataSize; if (isset($break)) { break; } } fclose($fp); } else { call_user_func(array($this->wrapperClassName, "copyFileInStream"), $filePathOrData, $stream); } fflush($stream); fclose($stream); } }
function readFile($filePathOrData, $headerType = "plain", $localName = "", $data = false, $gzip = null, $realfileSystem = false, $byteOffset = -1, $byteLength = -1) { if ($gzip === null) { $gzip = ConfService::getCoreConf("GZIP_COMPRESSION"); } if (!$realfileSystem && $this->wrapperClassName == "fsAccessWrapper") { $originalFilePath = $filePathOrData; $filePathOrData = fsAccessWrapper::patchPathForBaseDir($filePathOrData); } session_write_close(); restore_error_handler(); restore_exception_handler(); set_exception_handler('download_exception_handler'); set_error_handler('download_exception_handler'); // required for IE, otherwise Content-disposition is ignored if (ini_get('zlib.output_compression')) { AJXP_Utils::safeIniSet('zlib.output_compression', 'Off'); } $isFile = !$data && !$gzip; if ($byteLength == -1) { if ($data) { $size = strlen($filePathOrData); } else { if ($realfileSystem) { $size = sprintf("%u", filesize($filePathOrData)); } else { $size = $this->filesystemFileSize($filePathOrData); } } } else { $size = $byteLength; } if ($gzip && ($size > ConfService::getCoreConf("GZIP_LIMIT") || !function_exists("gzencode") || @strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE)) { $gzip = false; // disable gzip } $localName = $localName == "" ? basename(isset($originalFilePath) ? $originalFilePath : $filePathOrData) : $localName; if ($headerType == "plain") { header("Content-type:text/plain"); } else { if ($headerType == "image") { header("Content-Type: " . AJXP_Utils::getImageMimeType(basename($filePathOrData)) . "; name=\"" . $localName . "\""); header("Content-Length: " . $size); header('Cache-Control: public'); } else { /* if(preg_match('/ MSIE /',$_SERVER['HTTP_USER_AGENT']) || preg_match('/ WebKit /',$_SERVER['HTTP_USER_AGENT'])){ $localName = str_replace("+", " ", urlencode(SystemTextEncoding::toUTF8($localName))); } */ if ($isFile) { header("Accept-Ranges: 0-{$size}"); AJXP_Logger::debug("Sending accept range 0-{$size}"); } // Check if we have a range header (we are resuming a transfer) if (isset($_SERVER['HTTP_RANGE']) && $isFile && $size != 0) { if ($headerType == "stream_content") { if (extension_loaded('fileinfo') && $this->wrapperClassName == "fsAccessWrapper") { $fInfo = new fInfo(FILEINFO_MIME); $realfile = call_user_func(array($this->wrapperClassName, "getRealFSReference"), $filePathOrData); $mimeType = $fInfo->file($realfile); $splitChar = explode(";", $mimeType); $mimeType = trim($splitChar[0]); AJXP_Logger::debug("Detected mime {$mimeType} for {$realfile}"); } else { $mimeType = AJXP_Utils::getStreamingMimeType(basename($filePathOrData)); } header('Content-type: ' . $mimeType); } // multiple ranges, which can become pretty complex, so ignore it for now $ranges = explode('=', $_SERVER['HTTP_RANGE']); $offsets = explode('-', $ranges[1]); $offset = floatval($offsets[0]); $length = floatval($offsets[1]) - $offset; if (!$length) { $length = $size - $offset; } if ($length + $offset > $size || $length < 0) { $length = $size - $offset; } AJXP_Logger::debug('Content-Range: bytes ' . $offset . '-' . $length . '/' . $size); header('HTTP/1.1 206 Partial Content'); header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size); header("Content-Length: " . $length); $file = fopen($filePathOrData, 'rb'); fseek($file, 0); $relOffset = $offset; while ($relOffset > 2000000000.0) { // seek to the requested offset, this is 0 if it's not a partial content request fseek($file, 2000000000, SEEK_CUR); $relOffset -= 2000000000; // This works because we never overcome the PHP 32 bit limit } fseek($file, $relOffset, SEEK_CUR); while (ob_get_level()) { ob_end_flush(); } $readSize = 0.0; $bufferSize = 1024 * 8; while (!feof($file) && $readSize < $length && connection_status() == 0) { AJXP_Logger::debug("dl reading {$readSize} to {$length}", $_SERVER["HTTP_RANGE"]); echo fread($file, $bufferSize); $readSize += $bufferSize; flush(); } fclose($file); return; } else { if ($gzip) { $gzippedData = $data ? gzencode($filePathOrData, 9) : gzencode(file_get_contents($filePathOrData), 9); $size = strlen($gzippedData); } HTMLWriter::generateAttachmentsHeader($localName, $size, $isFile, $gzip); /* header("Content-Type: application/force-download; name=\"".$localName."\""); header("Content-Transfer-Encoding: binary"); if($gzip){ header("Content-Encoding: gzip"); // If gzip, recompute data size! $gzippedData = ($data?gzencode($filePathOrData,9):gzencode(file_get_contents($filePathOrData), 9)); $size = strlen($gzippedData); } header("Content-Length: ".$size); if ($isFile && ($size != 0)) header("Content-Range: bytes 0-" . ($size - 1) . "/" . $size . ";"); header("Content-Disposition: attachment; filename=\"".$localName."\""); header("Expires: 0"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); if (preg_match('/ MSIE /',$_SERVER['HTTP_USER_AGENT'])){ header("Cache-Control: max_age=0"); header("Pragma: public"); } // IE8 is dumb if (preg_match('/ MSIE /',$_SERVER['HTTP_USER_AGENT'])) { header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: private",false); // header("Content-Type: application/octet-stream"); } // For SSL websites there is a bug with IE see article KB 323308 // therefore we must reset the Cache-Control and Pragma Header if (ConfService::getConf("USE_HTTPS")==1 && preg_match('/ MSIE /',$_SERVER['HTTP_USER_AGENT'])) { header("Cache-Control:"); header("Pragma:"); } */ if ($gzip) { print $gzippedData; return; } } } } if ($data) { print $filePathOrData; } else { if ($this->pluginConf["USE_XSENDFILE"] && $this->wrapperClassName == "fsAccessWrapper") { if (!$realfileSystem) { $filePathOrData = fsAccessWrapper::getRealFSReference($filePathOrData); } $filePathOrData = str_replace("\\", "/", $filePathOrData); header("X-Sendfile: " . SystemTextEncoding::toUTF8($filePathOrData)); header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($filePathOrData) . '"'); return; } $stream = fopen("php://output", "a"); if ($realfileSystem) { AJXP_Logger::debug("realFS!", array("file" => $filePathOrData)); $fp = fopen($filePathOrData, "rb"); if ($byteOffset != -1) { fseek($fp, $byteOffset); } $sentSize = 0; $readChunk = 4096; while (!feof($fp)) { if ($byteLength != -1 && $sentSize + $readChunk >= $byteLength) { // compute last chunk and break after $readChunk = $byteLength - $sentSize; $break = true; } $data = fread($fp, $readChunk); $dataSize = strlen($data); fwrite($stream, $data, $dataSize); $sentSize += $dataSize; if (isset($break)) { break; } } fclose($fp); } else { call_user_func(array($this->wrapperClassName, "copyFileInStream"), $filePathOrData, $stream); } fflush($stream); fclose($stream); } }