Fix #11417: Allow EVENT_MENU_MAIN plugin events to return null
[mantis/radio.git] / file_download.php
blob32aa24bb0624bea5b90aa084a8afce3e9624d559
1 <?php
2 # MantisBT - A PHP based bugtracking system
4 # MantisBT is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 2 of the License, or
7 # (at your option) any later version.
9 # MantisBT is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Add file and redirect to the referring page
20 * @package MantisBT
21 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
22 * @copyright Copyright (C) 2002 - 2010 MantisBT Team - mantisbt-dev@lists.sourceforge.net
23 * @link http://www.mantisbt.org
25 * @uses core.php
26 * @uses access_api.php
27 * @uses authentication_api.php
28 * @uses bug_api.php
29 * @uses config_api.php
30 * @uses constant_inc.php
31 * @uses database_api.php
32 * @uses file_api.php
33 * @uses gpc_api.php
34 * @uses http_api.php
35 * @uses utility_api.php
38 $g_bypass_headers = true; # suppress headers as we will send our own later
39 define( 'COMPRESSION_DISABLED', true );
41 require_once( 'core.php' );
42 require_api( 'access_api.php' );
43 require_api( 'authentication_api.php' );
44 require_api( 'bug_api.php' );
45 require_api( 'config_api.php' );
46 require_api( 'constant_inc.php' );
47 require_api( 'database_api.php' );
48 require_api( 'file_api.php' );
49 require_api( 'gpc_api.php' );
50 require_api( 'http_api.php' );
51 require_api( 'utility_api.php' );
53 auth_ensure_user_authenticated();
55 $f_file_id = gpc_get_int( 'file_id' );
56 $f_type = gpc_get_string( 'type' );
58 $c_file_id = (integer)$f_file_id;
60 # we handle the case where the file is attached to a bug
61 # or attached to a project as a project doc.
62 $query = '';
63 switch ( $f_type ) {
64 case 'bug':
65 $t_bug_file_table = db_get_table( 'bug_file' );
66 $query = "SELECT *
67 FROM $t_bug_file_table
68 WHERE id=" . db_param();
69 break;
70 case 'doc':
71 $t_project_file_table = db_get_table( 'project_file' );
72 $query = "SELECT *
73 FROM $t_project_file_table
74 WHERE id=" . db_param();
75 break;
76 default:
77 access_denied();
79 $result = db_query_bound( $query, Array( $c_file_id ) );
80 $row = db_fetch_array( $result );
81 extract( $row, EXTR_PREFIX_ALL, 'v' );
83 if ( $f_type == 'bug' ) {
84 $t_project_id = bug_get_field( $v_bug_id, 'project_id' );
85 } else {
86 $t_project_id = $v_project_id;
89 # Check access rights
90 switch ( $f_type ) {
91 case 'bug':
92 if ( !file_can_download_bug_attachments( $v_bug_id ) ) {
93 access_denied();
95 break;
96 case 'doc':
97 # Check if project documentation feature is enabled.
98 if ( OFF == config_get( 'enable_project_documentation' ) ) {
99 access_denied();
102 access_ensure_project_level( config_get( 'view_proj_doc_threshold' ), $v_project_id );
103 break;
106 # throw away output buffer contents (and disable it) to protect download
107 while ( @ob_end_clean() );
109 if ( ini_get( 'zlib.output_compression' ) && function_exists( 'ini_set' ) ) {
110 ini_set( 'zlib.output_compression', false );
113 # Make sure that IE can download the attachments under https.
114 header( 'Pragma: public' );
116 # To fix an IE bug which causes problems when downloading
117 # attached files via HTTPS, we disable the "Pragma: no-cache"
118 # command when IE is used over HTTPS.
119 global $g_allow_file_cache;
120 if ( ( isset( $_SERVER["HTTPS"] ) && ( "on" == utf8_strtolower( $_SERVER["HTTPS"] ) ) ) && is_browser_internet_explorer() ) {
121 # Suppress "Pragma: no-cache" header.
122 } else {
123 if ( !isset( $g_allow_file_cache ) ) {
124 header( 'Pragma: no-cache' );
127 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s \G\M\T', time() ) );
129 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s \G\M\T', $v_date_added ) );
131 $t_filename = file_get_display_name( $v_filename );
132 $t_show_inline = false;
133 $t_inline_files = explode( ',', config_get( 'inline_file_exts' ) );
134 if ( $t_inline_files !== false && !is_blank( $t_inline_files[0] ) ) {
135 if ( in_array( utf8_strtolower( file_get_extension( $t_filename ) ), $t_inline_files ) ) {
136 $t_show_inline = true;
140 http_content_disposition_header( $t_filename, $t_show_inline );
142 header( 'Content-Length: ' . $v_filesize );
144 # If finfo is available (always true for PHP >= 5.3.0) we can use it to determine the MIME type of files
145 $finfo_available = false;
146 if ( class_exists( 'finfo' ) ) {
147 $t_info_file = config_get( 'fileinfo_magic_db_file' );
149 if ( is_blank( $t_info_file ) ) {
150 $finfo = new finfo( FILEINFO_MIME );
151 } else {
152 $finfo = new finfo( FILEINFO_MIME, $t_info_file );
155 if ( $finfo ) {
156 $finfo_available = true;
160 $t_content_type = $v_file_type;
162 # dump file content to the connection.
163 switch ( config_get( 'file_upload_method' ) ) {
164 case DISK:
165 $t_local_disk_file = file_normalize_attachment_path( $v_diskfile, $t_project_id );
167 if ( file_exists( $t_local_disk_file ) ) {
168 if ( $finfo_available ) {
169 $t_file_info_type = $finfo->file( $t_local_disk_file );
171 if ( $t_file_info_type !== false ) {
172 $t_content_type = $t_file_info_type;
176 header( 'Content-Type: ' . $t_content_type );
177 if ( config_get( 'file_download_xsendfile_enabled' ) ) {
178 $t_xsendfile_header_name = config_get( 'file_download_xsendfile_header_name' );
179 header( $t_xsendfile_header_name . ': ' . $t_local_disk_file );
180 } else {
181 file_send_chunk( $t_local_disk_file );
184 break;
185 case FTP:
186 $t_local_disk_file = file_normalize_attachment_path( $v_diskfile, $t_project_id );
188 if ( !file_exists( $t_local_disk_file ) ) {
189 $ftp = file_ftp_connect();
190 file_ftp_get ( $ftp, $t_local_disk_file, $v_diskfile );
191 file_ftp_disconnect( $ftp );
194 if ( $finfo_available ) {
195 $t_file_info_type = $finfo->file( $t_local_disk_file );
197 if ( $t_file_info_type !== false ) {
198 $t_content_type = $t_file_info_type;
202 header( 'Content-Type: ' . $t_content_type );
203 readfile( $t_local_disk_file );
204 break;
205 default:
206 if ( $finfo_available ) {
207 $t_file_info_type = $finfo->buffer( $v_content );
209 if ( $t_file_info_type !== false ) {
210 $t_content_type = $t_file_info_type;
214 header( 'Content-Type: ' . $t_content_type );
215 echo $v_content;
217 exit();
219 function file_send_chunk($filename, $start = 0, $maxlength = 0 ) {
220 static $s_safe_mode = null;
221 $chunksize = 4*131072;
222 $buffer = '';
223 $offset = $start;
225 if( $s_safe_mode == null ) {
226 $s_safe_mode = ini_get('safe_mode');
229 while (true) {
230 if ( $s_safe_mode == false) {
231 @set_time_limit(60*60); //reset time limit to 60 min - should be enough for 1 MB chunk
233 $buffer = file_get_contents($filename, 0, null, $offset, ( ($maxlength > 0 && $maxlength < $chunksize) ? $maxlength : $chunksize ) );
234 if ( $buffer === false ) {
235 if( $maxlength > 0 ) {
236 $buffer = file_get_contents($filename, 0, null, $offset, $maxlength );
237 } else {
238 $buffer = file_get_contents($filename, 0, null, $offset );
240 echo $buffer;
241 flush();
242 exit(); // end of file
244 echo $buffer;
245 flush();
246 $offset += $chunksize;
247 $maxlength -= $chunksize;
248 unset($buffer);
249 $buffer = null;
251 return;