📄 download.php.tmp
字号:
* @access public * @return void * @param string $disposition whether to send the download * inline or as attachment * @param string $file_name the filename to display in * the browser's download window * * <b>Example:</b> * <code> * $HTTP_Download->setContentDisposition( * HTTP_DOWNLOAD_ATTACHMENT, * 'download.tgz' * ); * </code> */ function setContentDisposition( $disposition = HTTP_DOWNLOAD_ATTACHMENT, $file_name = null) { $cd = $disposition; if (isset($file_name)) { $cd .= '; filename="' . $file_name . '"'; } elseif ($this->file) { $cd .= '; filename="' . basename($this->file) . '"'; } $this->headers['Content-Disposition'] = $cd; } /** * Set content type of the download * * Default content type of the download will be 'application/x-octetstream'. * Returns PEAR_Error (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) if * $content_type doesn't seem to be valid. * * @access public * @return mixed Returns true on success or PEAR_Error on failure. * @param string $content_type content type of file for download */ function setContentType($content_type = 'application/x-octetstream') { if (!preg_match('/^[a-z]+\w*\/[a-z]+[\w.;= -]*$/', $content_type)) { return PEAR::raiseError( "Invalid content type '$content_type' supplied.", HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE ); } $this->headers['Content-Type'] = $content_type; return true; } /** * Guess content type of file * * First we try to use PEAR::MIME_Type, if installed, to detect the content * type, else we check if ext/mime_magic is loaded and properly configured. * * Returns PEAR_Error if: * o if PEAR::MIME_Type failed to detect a proper content type * (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) * o ext/magic.mime is not installed, or not properly configured * (HTTP_DOWNLOAD_E_NO_EXT_MMAGIC) * o mime_content_type() couldn't guess content type or returned * a content type considered to be bogus by setContentType() * (HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE) * * @access public * @return mixed Returns true on success or PEAR_Error on failure. */ function guessContentType() { if (class_exists('MIME_Type') || @include_once 'MIME/Type.php') { if (PEAR::isError($mime_type = MIME_Type::autoDetect($this->file))) { return PEAR::raiseError($mime_type->getMessage(), HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE); } return $this->setContentType($mime_type); } if (!function_exists('mime_content_type')) { return PEAR::raiseError( 'This feature requires ext/mime_magic!', HTTP_DOWNLOAD_E_NO_EXT_MMAGIC ); } if (!is_file(ini_get('mime_magic.magicfile'))) { return PEAR::raiseError( 'ext/mime_magic is loaded but not properly configured!', HTTP_DOWNLOAD_E_NO_EXT_MMAGIC ); } if (!$content_type = @mime_content_type($this->file)) { return PEAR::raiseError( 'Couldn\'t guess content type with mime_content_type().', HTTP_DOWNLOAD_E_INVALID_CONTENT_TYPE ); } return $this->setContentType($content_type); } /** * Send * * Returns PEAR_Error if: * o HTTP headers were already sent (HTTP_DOWNLOAD_E_HEADERS_SENT) * o HTTP Range was invalid (HTTP_DOWNLOAD_E_INVALID_REQUEST) * * @access public * @return mixed Returns true on success or PEAR_Error on failure. * @param bool $autoSetContentDisposition Whether to set the * Content-Disposition header if it isn't already. */ function send($autoSetContentDisposition = true) { if (headers_sent()) { return PEAR::raiseError( 'Headers already sent.', HTTP_DOWNLOAD_E_HEADERS_SENT ); } if (!ini_get('safe_mode')) { @set_time_limit(0); } if ($autoSetContentDisposition && !isset($this->headers['Content-Disposition'])) { $this->setContentDisposition(); } if ($this->cache) { $this->headers['ETag'] = $this->generateETag(); if ($this->isCached()) { $this->HTTP->sendStatusCode(304); $this->sendHeaders(); return true; } } else { unset($this->headers['Last-Modified']); } while (@ob_end_clean()); if ($this->gzip) { @ob_start('ob_gzhandler'); } else { ob_start(); } $this->sentBytes = 0; if ($this->isRangeRequest()) { $this->HTTP->sendStatusCode(206); $chunks = $this->getChunks(); } else { $this->HTTP->sendStatusCode(200); $chunks = array(array(0, $this->size)); if (!$this->gzip && count(ob_list_handlers()) < 2) { $this->headers['Content-Length'] = $this->size; } } if (PEAR::isError($e = $this->sendChunks($chunks))) { ob_end_clean(); $this->HTTP->sendStatusCode(416); return $e; } ob_end_flush(); flush(); return true; } /** * Static send * * @see HTTP_Download::HTTP_Download() * @see HTTP_Download::send() * * @static * @access public * @return mixed Returns true on success or PEAR_Error on failure. * @param array $params associative array of parameters * @param bool $guess whether HTTP_Download::guessContentType() * should be called */ function staticSend($params, $guess = false) { $d = &new HTTP_Download(); $e = $d->setParams($params); if (PEAR::isError($e)) { return $e; } if ($guess) { $e = $d->guessContentType(); if (PEAR::isError($e)) { return $e; } } return $d->send(); } /** * Send a bunch of files or directories as an archive * * Example: * <code> * require_once 'HTTP/Download.php'; * HTTP_Download::sendArchive( * 'myArchive.tgz', * '/var/ftp/pub/mike', * HTTP_DOWNLOAD_TGZ, * '', * '/var/ftp/pub' * ); * </code> * * @see Archive_Tar::createModify() * @deprecated use HTTP_Download_Archive::send() * @static * @access public * @return mixed Returns true on success or PEAR_Error on failure. * @param string $name name the sent archive should have * @param mixed $files files/directories * @param string $type archive type * @param string $add_path path that should be prepended to the files * @param string $strip_path path that should be stripped from the files */ function sendArchive( $name, $files, $type = HTTP_DOWNLOAD_TGZ, $add_path = '', $strip_path = '') { require_once 'HTTP/Download/Archive.php'; return HTTP_Download_Archive::send($name, $files, $type, $add_path, $strip_path); } // }}} // {{{ protected methods /** * Generate ETag * * @access protected * @return string */ function generateETag() { if (!$this->etag) { if ($this->data) { $md5 = md5($this->data); } else { $fst = is_resource($this->handle) ? fstat($this->handle) : stat($this->file); $md5 = md5($fst['mtime'] .'='. $fst['ino'] .'='. $fst['size']); } $this->etag = '"' . $md5 . '-' . crc32($md5) . '"'; } return $this->etag; } /** * Send multiple chunks * * @access protected * @return mixed Returns true on success or PEAR_Error on failure. * @param array $chunks */ function sendChunks($chunks) { if (count($chunks) == 1) { return $this->sendChunk(array_shift($chunks)); } $bound = uniqid('HTTP_DOWNLOAD-', true); $cType = $this->headers['Content-Type']; $this->headers['Content-Type'] = 'multipart/byteranges; boundary=' . $bound; $this->sendHeaders(); foreach ($chunks as $chunk){ if (PEAR::isError($e = $this->sendChunk($chunk, $cType, $bound))) { return $e; } } #echo "\r\n--$bound--\r\n"; return true; } /** * Send chunk of data * * @access protected * @return mixed Returns true on success or PEAR_Error on failure. * @param array $chunk start and end offset of the chunk to send * @param string $cType actual content type * @param string $bound boundary for multipart/byteranges */ function sendChunk($chunk, $cType = null, $bound = null) { list($offset, $lastbyte) = $chunk; $length = ($lastbyte - $offset) + 1; if ($length < 1) { return PEAR::raiseError( "Error processing range request: $offset-$lastbyte/$length", HTTP_DOWNLOAD_E_INVALID_REQUEST ); } $range = $offset . '-' . $lastbyte . '/' . $this->size; if (isset($cType, $bound)) { echo "\r\n--$bound\r\n", "Content-Type: $cType\r\n", "Content-Range: bytes $range\r\n\r\n"; } else { if ($this->isRangeRequest()) { $this->headers['Content-Range'] = 'bytes '. $range; } $this->sendHeaders(); } if ($this->data) { while (($length -= $this->bufferSize) > 0) { $this->flush(substr($this->data, $offset, $this->bufferSize)); $this->throttleDelay and $this->sleep(); $offset += $this->bufferSize; } if ($length) { $this->flush(substr($this->data, $offset, $this->bufferSize + $length)); } } else { if (!is_resource($this->handle)) { $this->handle = fopen($this->file, 'rb'); } fseek($this->handle, $offset); while (($length -= $this->bufferSize) > 0) { $this->flush(fread($this->handle, $this->bufferSize)); $this->throttleDelay and $this->sleep(); } if ($length) { $this->flush(fread($this->handle, $this->bufferSize + $length)); } } return true; } /** * Get chunks to send * * @access protected * @return array */ function getChunks() { $parts = array(); foreach (explode(',', $this->getRanges()) as $chunk){ list($o, $e) = explode('-', $chunk); if ($e >= $this->size || (empty($e) && $e !== 0 && $e !== '0')) { $e = $this->size - 1; } if (empty($o) && $o !== 0 && $o !== '0') { $o = $this->size - $e; $e = $this->size - 1; } $parts[] = array($o, $e); } return $parts; } /** * Check if range is requested * * @access protected * @return bool */ function isRangeRequest() { if (!isset($_SERVER['HTTP_RANGE'])) { return false; } return $this->isValidRange(); } /** * Get range request * * @access protected * @return array */ function getRanges() { return preg_match('/^bytes=((\d*-\d*,? ?)+)$/', @$_SERVER['HTTP_RANGE'], $matches) ? $matches[1] : array(); } /** * Check if entity is cached * * @access protected * @return bool */ function isCached() { return ( (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $this->lastModified == strtotime(current($a = explode( ';', $_SERVER['HTTP_IF_MODIFIED_SINCE'])))) || (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $this->compareAsterisk('HTTP_IF_NONE_MATCH', $this->etag)) ); } /** * Check if entity hasn't changed * * @access protected * @return bool */ function isValidRange() { if (isset($_SERVER['HTTP_IF_MATCH']) && !$this->compareAsterisk('HTTP_IF_MATCH', $this->etag)) { return false; } if (isset($_SERVER['HTTP_IF_RANGE']) && $_SERVER['HTTP_IF_RANGE'] !== $this->etag && strtotime($_SERVER['HTTP_IF_RANGE']) !== $this->lastModified) { return false; } if (isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE'])) { $lm = array_shift(explode(';', $_SERVER['HTTP_IF_UNMODIFIED_SINCE'])); if (strtotime($lm) !== $this->lastModified) { return false; } } if (isset($_SERVER['HTTP_UNLESS_MODIFIED_SINCE'])) { $lm = array_shift(explode(';', $_SERVER['HTTP_UNLESS_MODIFIED_SINCE'])); if (strtotime($lm) !== $this->lastModified) { return false; } } return true; } /** * Compare against an asterisk or check for equality * * @access protected * @return bool * @param string key for the $_SERVER array * @param string string to compare */ function compareAsterisk($svar, $compare) { foreach (array_map('trim', explode(',', $_SERVER[$svar])) as $request) { if ($request === '*' || $request === $compare) { return true; } } return false; } /** * Send HTTP headers * * @access protected * @return void */ function sendHeaders() { foreach ($this->headers as $header => $value) { $this->HTTP->setHeader($header, $value); } $this->HTTP->sendHeaders(); /* NSAPI won't output anything if we did this */ if (strncasecmp(PHP_SAPI, 'nsapi', 5)) { ob_flush(); flush(); } } /** * Flush * * @access protected * @return void * @param string $data */ function flush($data = '') { if ($dlen = strlen($data)) { $this->sentBytes += $dlen; echo $data; } ob_flush(); flush(); } /** * Sleep * * @access protected * @return void */ function sleep() { if (OS_WINDOWS) { com_message_pump($this->throttleDelay); } else { usleep($this->throttleDelay * 1000); } } // }}}}?>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -