static function readfile($file, $mime = true, $filename = true) { $h = patchworkPath($file); if (!$h || !file_exists($h) || is_dir($h)) { user_error(__METHOD__ . "(..): invalid file ({$file})"); return; } $file = $h; if (true === $mime) { $mime = strtolower(strrchr($file, '.')); $mime = isset(self::$contentType[$mime]) ? self::$contentType[$mime] : false; } $mime || ($mime = isset(p::$headers['content-type']) ? substr(p::$headers['content-type'], 14) : 'application/octet-stream'); $mime = strtolower($mime); $head = 'HEAD' == $_SERVER['REQUEST_METHOD']; $gzip = p::gzipAllowed($mime); $filter = $gzip || $head || !$CONFIG['xsendfile'] || in_array($mime, self::$ieSniffedTypes_edit) || in_array($mime, p::$ieSniffedTypes_download); header('Content-Type: ' . $mime); if ($filename) { $filename = basename(true === $filename ? $_SERVER['PATCHWORK_REQUEST'] : $filename); $size = false; if (!$filter) { // Force IE>=8 to respect attachment content disposition header('X-Download-Options: noopen'); } // It seems that IE assumes that filename is represented in its local system charset... // But we don't want to introduce "Vary: User-Agent" just because of this. if (('POST' === $_SERVER['REQUEST_METHOD'] || p::$private) && isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') && preg_match('/[\\x80-\\xFF]/', $filename)) { if (stripos(p::$headers['content-type'], 'octet-stream') && preg_match('#(.*)(\\.[- -,/-~]+)$#D', $filename, $size)) { // Don't search any rational here, it's IE... header('Content-Disposition: attachment; filename=' . rawurlencode($size[1]) . str_replace('"', "''", $size[2])); } else { $filename = Patchwork\Utf8::toAscii($filename); } } $size || header('Content-Disposition: attachment; filename="' . str_replace('"', "''", $filename) . '"'); // If only RFC 2231 were in use... See http://greenbytes.de/tech/tc2231/ //header('Content-Disposition: attachment; filename*=utf-8''" . rawurlencode($filename)); } else { if (false !== strpos($mime, 'html')) { header('P3P: CP="' . $CONFIG['P3P'] . '"'); header('X-XSS-Protection: 1; mode=block'); } } $size = filesize($file); p::$ETag = $size . '-' . p::$LastModified . '-' . fileinode($file); p::$LastModified = filemtime($file); p::$binaryMode = true; p::disable(); class_exists('SESSION', false) && s::close(); class_exists('adapter_DB', false) && \adapter_DB::__free(); $gzip || ob_start(); $filter && ob_start(array(__CLASS__, 'ob_filterOutput'), 32768); // Transform relative URLs to absolute ones if ($gzip) { if (0 === strncasecmp($mime, 'text/css', 8)) { self::$filterRx = "@([\\s:]url\\(\\s*[\"']?)(?![/\\\\#\"']|[^\\)\n\r:/\"']+?:)@i"; ob_start(array(__CLASS__, 'filter'), 32768); } else { if (0 === strncasecmp($mime, 'text/html', 9) || 0 === strncasecmp($mime, 'text/x-component', 16)) { self::$filterRx = "@(<[^<>]+?\\s(?:href|src)\\s*=\\s*[\"']?)(?![/\\\\#\"']|[^\n\r:/\"']+?:)@i"; ob_start(array(__CLASS__, 'filter'), 32768); } } } if ($filter) { $h = fopen($file, 'rb'); echo $starting_data = fread($h, 256); // For p::ob_filterOutput to fix IE if ($gzip) { if ($head) { ob_end_clean(); } $data = ''; $starting_data = false; } else { ob_end_flush(); $data = ob_get_clean(); $size += strlen($data) - strlen($starting_data); $starting_data = $data == $starting_data; } } else { $starting_data = true; } if (!$head) { if ($starting_data && $CONFIG['xsendfile']) { header(sprintf($CONFIG['xsendfile'], $file)); } else { if ($range = $starting_data && !$gzip) { header('Accept-Ranges: bytes'); $range = isset($_SERVER['HTTP_RANGE']) ? p\HttpRange::negociate($size, p::$ETag, p::$LastModified) : false; } else { header('Accept-Ranges: none'); } set_time_limit(0); ignore_user_abort(false); if ($range) { unset(p::$headers['content-type']); p\HttpRange::sendChunks($range, $h, $mime, $size); } else { $gzip || header('Content-Length: ' . $size); echo $data; feof($h) || fpassthru($h); } } } $filter && fclose($h); }