<?php
namespace download;

class ForceDownload
{
	/**
	 * Force Download
	 *
	 * Generates headers that force a download to happen
	 *
	 * @param	string	filename
	 * @param	mixed	the data to be downloaded
	 * @param	bool	whether to try and send the actual file MIME type
	 * @return	void
	 */
	public function force_download($filename = '', $data = '', $set_mime = FALSE)
	{
		if ($filename === '' OR $data === '')
		{
			return;
		}
		elseif ($data === NULL)
		{
			if ( ! @is_file($filename) OR ($filesize = @filesize($filename)) === FALSE)
			{
				return;
			}

			$filepath = $filename;
			$filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename));
			$filename = end($filename);
		}
		else
		{
			$filesize = strlen($data);
		}

		// Set the default MIME type to send
		$mime = 'application/octet-stream';

		$x = explode('.', $filename);
		$extension = end($x);

		if ($set_mime === TRUE)
		{
			if (count($x) === 1 OR $extension === '')
			{
				/* If we're going to detect the MIME type,
				 * we'll need a file extension.
				 */
				return;
			}

			// Load the mime types
			$mimes =& self::get_mimes();

			// Only change the default MIME if we can find one
			if (isset($mimes[$extension]))
			{
				$mime = is_array($mimes[$extension]) ? $mimes[$extension][0] : $mimes[$extension];
			}
		}

		/* It was reported that browsers on Android 2.1 (and possibly older as well)
		 * need to have the filename extension upper-cased in order to be able to
		 * download it.
		 *
		 * Reference: http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
		 */
		if (count($x) !== 1 && isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Android\s(1|2\.[01])/', $_SERVER['HTTP_USER_AGENT']))
		{
			$x[count($x) - 1] = strtoupper($extension);
			$filename = implode('.', $x);
		}

		if ($data === NULL && ($fp = @fopen($filepath, 'rb')) === FALSE)
		{
			return;
		}

		// Clean output buffer
		if (ob_get_level() !== 0 && @ob_end_clean() === FALSE)
		{
			@ob_clean();
		}

		// Generate the server headers
		header('Content-Type: '.$mime);
		header('Content-Disposition: attachment; filename="'.$filename.'"');
		header('Expires: 0');
		header('Content-Transfer-Encoding: binary');
		header('Content-Length: '.$filesize);
		header('Cache-Control: private, no-transform, no-store, must-revalidate');

		// If we have raw data - just dump it
		if ($data !== NULL)
		{
			exit($data);
		}

		// Flush 1MB chunks of data
		while ( ! feof($fp) && ($data = fread($fp, 1048576)) !== FALSE)
		{
			echo $data;
		}

		fclose($fp);
		exit;
	}

    public static function &get_mimes()
    {
        static $_mimes;

        if (empty($_mimes))
        {
            $_mimes = array(
                'hqx'	=>	array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
                'cpt'	=>	'application/mac-compactpro',
                'csv'	=>	array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'),
                'bin'	=>	array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
                'dms'	=>	'application/octet-stream',
                'lha'	=>	'application/octet-stream',
                'lzh'	=>	'application/octet-stream',
                'exe'	=>	array('application/octet-stream', 'application/x-msdownload'),
                'class'	=>	'application/octet-stream',
                'psd'	=>	array('application/x-photoshop', 'image/vnd.adobe.photoshop'),
                'so'	=>	'application/octet-stream',
                'sea'	=>	'application/octet-stream',
                'dll'	=>	'application/octet-stream',
                'oda'	=>	'application/oda',
                'pdf'	=>	array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'),
                'ai'	=>	array('application/pdf', 'application/postscript'),
                'eps'	=>	'application/postscript',
                'ps'	=>	'application/postscript',
                'smi'	=>	'application/smil',
                'smil'	=>	'application/smil',
                'mif'	=>	'application/vnd.mif',
                'xls'	=>	array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'),
                'ppt'	=>	array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'),
                'pptx'	=> 	array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'),
                'wbxml'	=>	'application/wbxml',
                'wmlc'	=>	'application/wmlc',
                'dcr'	=>	'application/x-director',
                'dir'	=>	'application/x-director',
                'dxr'	=>	'application/x-director',
                'dvi'	=>	'application/x-dvi',
                'gtar'	=>	'application/x-gtar',
                'gz'	=>	'application/x-gzip',
                'gzip'  =>	'application/x-gzip',
                'php'	=>	array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'),
                'php4'	=>	'application/x-httpd-php',
                'php3'	=>	'application/x-httpd-php',
                'phtml'	=>	'application/x-httpd-php',
                'phps'	=>	'application/x-httpd-php-source',
                'js'	=>	array('application/x-javascript', 'text/plain'),
                'swf'	=>	'application/x-shockwave-flash',
                'sit'	=>	'application/x-stuffit',
                'tar'	=>	'application/x-tar',
                'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
                'z'	=>	'application/x-compress',
                'xhtml'	=>	'application/xhtml+xml',
                'xht'	=>	'application/xhtml+xml',
                'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'),
                'rar'	=>	array('application/x-rar', 'application/rar', 'application/x-rar-compressed'),
                'mid'	=>	'audio/midi',
                'midi'	=>	'audio/midi',
                'mpga'	=>	'audio/mpeg',
                'mp2'	=>	'audio/mpeg',
                'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
                'aif'	=>	array('audio/x-aiff', 'audio/aiff'),
                'aiff'	=>	array('audio/x-aiff', 'audio/aiff'),
                'aifc'	=>	'audio/x-aiff',
                'ram'	=>	'audio/x-pn-realaudio',
                'rm'	=>	'audio/x-pn-realaudio',
                'rpm'	=>	'audio/x-pn-realaudio-plugin',
                'ra'	=>	'audio/x-realaudio',
                'rv'	=>	'video/vnd.rn-realvideo',
                'wav'	=>	array('audio/x-wav', 'audio/wave', 'audio/wav'),
                'bmp'	=>	array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'),
                'gif'	=>	'image/gif',
                'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
                'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
                'jpe'	=>	array('image/jpeg', 'image/pjpeg'),
                'png'	=>	array('image/png',  'image/x-png'),
                'tiff'	=>	'image/tiff',
                'tif'	=>	'image/tiff',
                'css'	=>	array('text/css', 'text/plain'),
                'html'	=>	array('text/html', 'text/plain'),
                'htm'	=>	array('text/html', 'text/plain'),
                'shtml'	=>	array('text/html', 'text/plain'),
                'txt'	=>	'text/plain',
                'text'	=>	'text/plain',
                'log'	=>	array('text/plain', 'text/x-log'),
                'rtx'	=>	'text/richtext',
                'rtf'	=>	'text/rtf',
                'xml'	=>	array('application/xml', 'text/xml', 'text/plain'),
                'xsl'	=>	array('application/xml', 'text/xsl', 'text/xml'),
                'mpeg'	=>	'video/mpeg',
                'mpg'	=>	'video/mpeg',
                'mpe'	=>	'video/mpeg',
                'qt'	=>	'video/quicktime',
                'mov'	=>	'video/quicktime',
                'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
                'movie'	=>	'video/x-sgi-movie',
                'doc'	=>	array('application/msword', 'application/vnd.ms-office'),
                'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'),
                'dot'	=>	array('application/msword', 'application/vnd.ms-office'),
                'dotx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
                'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'),
                'word'	=>	array('application/msword', 'application/octet-stream'),
                'xl'	=>	'application/excel',
                'eml'	=>	'message/rfc822',
                'json'  =>	array('application/json', 'text/json'),
                'pem'   =>	array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
                'p10'   =>	array('application/x-pkcs10', 'application/pkcs10'),
                'p12'   =>	'application/x-pkcs12',
                'p7a'   =>	'application/x-pkcs7-signature',
                'p7c'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
                'p7m'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
                'p7r'   =>	'application/x-pkcs7-certreqresp',
                'p7s'   =>	'application/pkcs7-signature',
                'crt'   =>	array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
                'crl'   =>	array('application/pkix-crl', 'application/pkcs-crl'),
                'der'   =>	'application/x-x509-ca-cert',
                'kdb'   =>	'application/octet-stream',
                'pgp'   =>	'application/pgp',
                'gpg'   =>	'application/gpg-keys',
                'sst'   =>	'application/octet-stream',
                'csr'   =>	'application/octet-stream',
                'rsa'   =>	'application/x-pkcs7',
                'cer'   =>	array('application/pkix-cert', 'application/x-x509-ca-cert'),
                '3g2'   =>	'video/3gpp2',
                '3gp'   =>	array('video/3gp', 'video/3gpp'),
                'mp4'   =>	'video/mp4',
                'm4a'   =>	'audio/x-m4a',
                'f4v'   =>	'video/mp4',
                'webm'	=>	'video/webm',
                'aac'   =>	'audio/x-acc',
                'm4u'   =>	'application/vnd.mpegurl',
                'm3u'   =>	'text/plain',
                'xspf'  =>	'application/xspf+xml',
                'vlc'   =>	'application/videolan',
                'wmv'   =>	array('video/x-ms-wmv', 'video/x-ms-asf'),
                'au'    =>	'audio/x-au',
                'ac3'   =>	'audio/ac3',
                'flac'  =>	'audio/x-flac',
                'ogg'   =>	'audio/ogg',
                'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
                'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
                'ics'	=>	'text/calendar',
                'ical'	=>	'text/calendar',
                'zsh'	=>	'text/x-scriptzsh',
                '7zip'	=>	array('application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'),
                'cdr'	=>	array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'),
                'wma'	=>	array('audio/x-ms-wma', 'video/x-ms-asf'),
                'jar'	=>	array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'),
                'svg'	=>	array('image/svg+xml', 'application/xml', 'text/xml'),
                'vcf'	=>	'text/x-vcard',
                'srt'	=>	array('text/srt', 'text/plain'),
                'vtt'	=>	array('text/vtt', 'text/plain'),
                'ico'	=>	array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon')
            );
        }

        return $_mimes;
    }
}

调用

public function down(){
	$down = new ForceDownload();
	$down->force_download('uploads/xx.pdf',NULL,TRUE);
}

ThinkPHP 5 使用方法

放到 extend/download/ 文件夹下,即 extend/download/ForceDownload.php

实例化 $down = new \download\ForceDownload();

调用  $down->force_download(‘uploads/xx.pdf’,NULL,TRUE);

发表评论

电子邮件地址不会被公开。 必填项已用*标注