public function switchAction($action, $httpVars, $filesVars) { $repository = ConfService::getRepository(); if (!$repository->detectStreamWrapper(true)) { return false; } if (!isset($this->pluginConf)) { $this->pluginConf = array("GENERATE_THUMBNAIL" => false); } $selection = new UserSelection($repository, $httpVars); $destStreamURL = $selection->currentBaseUrl(); if ($action == "preview_data_proxy") { $file = $selection->getUniqueFile(); if (!file_exists($destStreamURL . $file) || !is_readable($destStreamURL . $file)) { header("Content-Type: " . AJXP_Utils::getImageMimeType(basename($file)) . "; name=\"" . basename($file) . "\""); header("Content-Length: 0"); return; } $this->logInfo('Preview', 'Preview content of ' . $file, array("files" => $selection->getUniqueFile())); if (isset($httpVars["get_thumb"]) && $httpVars["get_thumb"] == "true" && $this->getFilteredOption("GENERATE_THUMBNAIL", $repository->getId())) { $dimension = 200; if (isset($httpVars["dimension"]) && is_numeric($httpVars["dimension"])) { $dimension = $httpVars["dimension"]; } $this->currentDimension = $dimension; $cacheItem = AJXP_Cache::getItem("diaporama_" . $dimension, $destStreamURL . $file, array($this, "generateThumbnail")); $data = $cacheItem->getData(); $cId = $cacheItem->getId(); header("Content-Type: " . AJXP_Utils::getImageMimeType(basename($cId)) . "; name=\"" . basename($cId) . "\""); header("Content-Length: " . strlen($data)); header('Cache-Control: public'); header("Pragma:"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", time() - 10000) . " GMT"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 5 * 24 * 3600) . " GMT"); print $data; } else { //$filesize = filesize($destStreamURL.$file); $node = new AJXP_Node($destStreamURL . $file); $fp = fopen($destStreamURL . $file, "r"); $stat = fstat($fp); $filesize = $stat["size"]; header("Content-Type: " . AJXP_Utils::getImageMimeType(basename($file)) . "; name=\"" . basename($file) . "\""); header("Content-Length: " . $filesize); header('Cache-Control: public'); header("Pragma:"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", time() - 10000) . " GMT"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 5 * 24 * 3600) . " GMT"); $stream = fopen("php://output", "a"); AJXP_MetaStreamWrapper::copyFileInStream($destStreamURL . $file, $stream); fflush($stream); fclose($stream); AJXP_Controller::applyHook("node.read", array($node)); } } }
public function switchAction($action, $httpVars, $filesVars) { $repository = ConfService::getRepositoryById($httpVars["repository_id"]); if (!$repository->detectStreamWrapper(true)) { return false; } if (AuthService::usersEnabled()) { $loggedUser = AuthService::getLoggedUser(); if ($loggedUser === null && ConfService::getCoreConf("ALLOW_GUEST_BROWSING", "auth")) { AuthService::logUser("guest", null); $loggedUser = AuthService::getLoggedUser(); } if (!$loggedUser->canSwitchTo($repository->getId())) { echo "You do not have permissions to access this resource"; return false; } } $selection = new UserSelection($repository, $httpVars); if ($action == "open_file") { $selectedNode = $selection->getUniqueNode(); $selectedNodeUrl = $selectedNode->getUrl(); if (!file_exists($selectedNodeUrl) || !is_readable($selectedNodeUrl)) { echo "File does not exist"; return false; } $filesize = filesize($selectedNodeUrl); $fp = fopen($selectedNodeUrl, "rb"); $fileMime = "application/octet-stream"; //Get mimetype with fileinfo PECL extension if (class_exists("finfo")) { $finfo = new finfo(FILEINFO_MIME); $fileMime = $finfo->buffer(fread($fp, 2000)); } //Get mimetype with (deprecated) mime_content_type if (strpos($fileMime, "application/octet-stream") === 0 && function_exists("mime_content_type")) { $fileMime = @mime_content_type($fp); } //Guess mimetype based on file extension if (strpos($fileMime, "application/octet-stream") === 0) { $fileExt = substr(strrchr(basename($selectedNodeUrl), '.'), 1); if (empty($fileExt)) { $fileMime = "application/octet-stream"; } else { $regex = "/^([\\w\\+\\-\\.\\/]+)\\s+(\\w+\\s)*({$fileExt}\\s)/i"; $lines = file($this->getBaseDir() . "/resources/other/mime.types"); foreach ($lines as $line) { if (substr($line, 0, 1) == '#') { continue; } // skip comments $line = rtrim($line) . " "; if (!preg_match($regex, $line, $matches)) { continue; } // no match to the extension $fileMime = $matches[1]; } } } fclose($fp); // If still no mimetype, give up and serve application/octet-stream if (empty($fileMime)) { $fileMime = "application/octet-stream"; } //Send headers HTMLWriter::generateInlineHeaders(basename($selectedNodeUrl), $filesize, $fileMime); $stream = fopen("php://output", "a"); AJXP_MetaStreamWrapper::copyFileInStream($selectedNodeUrl, $stream); fflush($stream); fclose($stream); AJXP_Controller::applyHook("node.read", array($selectedNode)); $this->logInfo('Download', 'Read content of ' . $selectedNodeUrl, array("files" => $selectedNodeUrl)); } }
/** * Read a file (by chunks) and copy the data directly inside the given stream. * * @param string $path * @param resource $stream */ public static function copyFileInStream($path, $stream) { $url = self::translateURL($path); AJXP_MetaStreamWrapper::copyFileInStream($url, $stream); /* $wrapperClass = AJXP_MetaStreamWrapper::actualRepositoryWrapperClass(parse_url($url, PHP_URL_HOST)); call_user_func(array($wrapperClass, "copyFileInStream"), $url, $stream); */ if (self::$linkNode !== null) { ConfService::loadDriverForRepository(self::$linkNode->getRepository()); } }
public function readFile($filePathOrData, $headerType = "plain", $localName = "", $data = false, $gzip = null, $realfileSystem = false, $byteOffset = -1, $byteLength = -1) { if (!$data && !$gzip && !file_exists($filePathOrData)) { throw new Exception("File {$filePathOrData} not found!"); } if ($gzip === null) { $gzip = ConfService::getCoreConf("GZIP_COMPRESSION"); } if (!$realfileSystem && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "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 = filesize($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 ($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') && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "fsAccessWrapper") { $fInfo = new fInfo(FILEINFO_MIME); $realfile = AJXP_MetaStreamWrapper::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'); if (!is_resource($file)) { throw new Exception("Failed opening file " . $filePathOrData); } 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) && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "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()) && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "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 (!is_resource($fp)) { throw new Exception("Failed opening file " . $filePathOrData); } 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 { AJXP_MetaStreamWrapper::copyFileInStream($filePathOrData, $stream); } fflush($stream); fclose($stream); } }
public function switchAction($action, $httpVars, $filesVars) { $repository = ConfService::getRepository(); if (!$repository->detectStreamWrapper(true)) { return false; } $selection = new UserSelection($repository, $httpVars); $node = $selection->getUniqueNode(); if ($action == "read_video_data") { if (!file_exists($node->getUrl()) || !is_readable($node->getUrl())) { throw new Exception("Cannot find file!"); } $this->logDebug("Reading video"); session_write_close(); $filesize = filesize($node->getUrl()); $filename = $node->getUrl(); $basename = AJXP_Utils::safeBasename($filename); //$fp = fopen($destStreamURL.$file, "r"); if (preg_match("/\\.ogv\$/", $basename)) { header("Content-Type: video/ogg; name=\"" . $basename . "\""); } else { if (preg_match("/\\.mp4\$/", $basename)) { header("Content-Type: video/mp4; name=\"" . $basename . "\""); } else { if (preg_match("/\\.m4v\$/", $basename)) { header("Content-Type: video/x-m4v; name=\"" . $basename . "\""); } else { if (preg_match("/\\.webm\$/", $basename)) { header("Content-Type: video/webm; name=\"" . $basename . "\""); } } } } if (isset($_SERVER['HTTP_RANGE']) && $filesize != 0) { $this->logDebug("Http range", array($_SERVER['HTTP_RANGE'])); // 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]); if ($offset == 0) { $this->logInfo('Preview', 'Streaming content of ' . $filename, array("files" => $filename)); } $length = floatval($offsets[1]) - $offset + 1; if (!$length) { $length = $filesize - $offset; } if ($length + $offset > $filesize || $length < 0) { $length = $filesize - $offset; } header('HTTP/1.1 206 Partial Content'); header('Content-Range: bytes ' . $offset . '-' . ($offset + $length - 1) . '/' . $filesize); header('Accept-Ranges:bytes'); header("Content-Length: " . $length); $file = fopen($filename, 'rb'); if (!is_resource($file)) { throw new Exception("Cannot open file {$file}!"); } 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; while (!feof($file) && $readSize < $length && connection_status() == 0) { if ($length < 2048) { echo fread($file, $length); } else { echo fread($file, 2048); } $readSize += 2048.0; flush(); } fclose($file); } else { $this->logInfo('Preview', 'Streaming content of ' . $filename, array("files" => $filename)); header("Content-Length: " . $filesize); header("Content-Range: bytes 0-" . ($filesize - 1) . "/" . $filesize . ";"); header('Cache-Control: public'); $stream = fopen("php://output", "a"); AJXP_MetaStreamWrapper::copyFileInStream($node->getUrl(), $stream); fflush($stream); fclose($stream); } AJXP_Controller::applyHook("node.read", array($node)); } else { if ($action == "get_sess_id") { HTMLWriter::charsetHeader("text/plain"); print session_id(); } } }
public function switchAction($action, $httpVars, $postProcessData) { $repository = ConfService::getRepository(); if (!$repository->detectStreamWrapper(false)) { return false; } if ($action == "audio_proxy") { $selection = new UserSelection($repository, $httpVars); $destStreamURL = $selection->currentBaseUrl(); $node = new AJXP_Node($destStreamURL . "/" . $selection->getUniqueFile()); // Backward compat // May be a backward compatibility problem, try to base64decode the filepath if (!file_exists($node->getUrl()) && strpos($httpVars["file"], "base64encoded:") === false) { $file = AJXP_Utils::decodeSecureMagic(base64_decode($httpVars["file"])); if (!file_exists($destStreamURL . $file)) { throw new Exception("Cannot find file!"); } else { $node = new AJXP_Node($destStreamURL . $file); } } if (!is_readable($node->getUrl())) { throw new Exception("Cannot find file!"); } $fileUrl = $node->getUrl(); $localName = basename($fileUrl); $cType = "audio/" . array_pop(explode(".", $localName)); $size = filesize($node->getUrl()); header("Content-Type: " . $cType . "; name=\"" . $localName . "\""); header("Content-Length: " . $size); $stream = fopen("php://output", "a"); AJXP_MetaStreamWrapper::copyFileInStream($fileUrl, $stream); fflush($stream); fclose($stream); AJXP_Controller::applyHook("node.read", array($node)); $this->logInfo('Preview', 'Read content of ' . $node->getUrl(), array("files" => $node->getUrl())); //exit(1); } else { if ($action == "ls") { if (!isset($httpVars["playlist"])) { // This should not happen anyway, because of the applyCondition. AJXP_Controller::passProcessDataThrough($postProcessData); return false; } // We transform the XML into XSPF $xmlString = $postProcessData["ob_output"]; $xmlDoc = new DOMDocument(); $xmlDoc->loadXML($xmlString); $xElement = $xmlDoc->documentElement; header("Content-Type:application/xspf+xml;charset=UTF-8"); print '<?xml version="1.0" encoding="UTF-8"?>'; print '<playlist version="1" xmlns="http://xspf.org/ns/0/">'; print "<trackList>"; foreach ($xElement->childNodes as $child) { $isFile = $child->getAttribute("is_file") == "true"; $label = $child->getAttribute("text"); $ar = explode(".", $label); $ext = strtolower(end($ar)); if (!$isFile || $ext != "mp3") { continue; } print "<track><location>" . AJXP_SERVER_ACCESS . "?secure_token=" . AuthService::getSecureToken() . "&get_action=audio_proxy&file=" . base64_encode($child->getAttribute("filename")) . "</location><title>" . $label . "</title></track>"; } print "</trackList>"; AJXP_XMLWriter::close("playlist"); } } }