webmaster@1
|
1 <?php |
webmaster@13
|
2 // $Id: file.inc,v 1.121.2.5 2008/10/20 09:42:31 goba Exp $ |
webmaster@1
|
3 |
webmaster@1
|
4 /** |
webmaster@1
|
5 * @file |
webmaster@1
|
6 * API for handling file uploads and server file management. |
webmaster@1
|
7 */ |
webmaster@1
|
8 |
webmaster@1
|
9 /** |
webmaster@1
|
10 * @defgroup file File interface |
webmaster@1
|
11 * @{ |
webmaster@1
|
12 * Common file handling functions. |
webmaster@1
|
13 */ |
webmaster@1
|
14 |
webmaster@1
|
15 define('FILE_DOWNLOADS_PUBLIC', 1); |
webmaster@1
|
16 define('FILE_DOWNLOADS_PRIVATE', 2); |
webmaster@1
|
17 define('FILE_CREATE_DIRECTORY', 1); |
webmaster@1
|
18 define('FILE_MODIFY_PERMISSIONS', 2); |
webmaster@1
|
19 define('FILE_EXISTS_RENAME', 0); |
webmaster@1
|
20 define('FILE_EXISTS_REPLACE', 1); |
webmaster@1
|
21 define('FILE_EXISTS_ERROR', 2); |
webmaster@1
|
22 |
webmaster@1
|
23 /** |
webmaster@1
|
24 * A files status can be one of two values: temporary or permanent. The status |
webmaster@1
|
25 * for each file Drupal manages is stored in the {files} tables. If the status |
webmaster@1
|
26 * is temporary Drupal's file garbage collection will delete the file and |
webmaster@1
|
27 * remove it from the files table after a set period of time. |
webmaster@1
|
28 * |
webmaster@1
|
29 * If you wish to add custom statuses for use by contrib modules please expand as |
webmaster@1
|
30 * binary flags and consider the first 8 bits reserved. (0,1,2,4,8,16,32,64,128) |
webmaster@1
|
31 */ |
webmaster@1
|
32 define('FILE_STATUS_TEMPORARY', 0); |
webmaster@1
|
33 define('FILE_STATUS_PERMANENT', 1); |
webmaster@1
|
34 |
webmaster@1
|
35 /** |
webmaster@1
|
36 * Create the download path to a file. |
webmaster@1
|
37 * |
webmaster@1
|
38 * @param $path A string containing the path of the file to generate URL for. |
webmaster@1
|
39 * @return A string containing a URL that can be used to download the file. |
webmaster@1
|
40 */ |
webmaster@1
|
41 function file_create_url($path) { |
webmaster@1
|
42 // Strip file_directory_path from $path. We only include relative paths in urls. |
webmaster@1
|
43 if (strpos($path, file_directory_path() .'/') === 0) { |
webmaster@1
|
44 $path = trim(substr($path, strlen(file_directory_path())), '\\/'); |
webmaster@1
|
45 } |
webmaster@1
|
46 switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) { |
webmaster@1
|
47 case FILE_DOWNLOADS_PUBLIC: |
webmaster@1
|
48 return $GLOBALS['base_url'] .'/'. file_directory_path() .'/'. str_replace('\\', '/', $path); |
webmaster@1
|
49 case FILE_DOWNLOADS_PRIVATE: |
webmaster@1
|
50 return url('system/files/'. $path, array('absolute' => TRUE)); |
webmaster@1
|
51 } |
webmaster@1
|
52 } |
webmaster@1
|
53 |
webmaster@1
|
54 /** |
webmaster@1
|
55 * Make sure the destination is a complete path and resides in the file system |
webmaster@1
|
56 * directory, if it is not prepend the file system directory. |
webmaster@1
|
57 * |
webmaster@1
|
58 * @param $dest A string containing the path to verify. If this value is |
webmaster@1
|
59 * omitted, Drupal's 'files' directory will be used. |
webmaster@1
|
60 * @return A string containing the path to file, with file system directory |
webmaster@1
|
61 * appended if necessary, or FALSE if the path is invalid (i.e. outside the |
webmaster@1
|
62 * configured 'files' or temp directories). |
webmaster@1
|
63 */ |
webmaster@1
|
64 function file_create_path($dest = 0) { |
webmaster@1
|
65 $file_path = file_directory_path(); |
webmaster@1
|
66 if (!$dest) { |
webmaster@1
|
67 return $file_path; |
webmaster@1
|
68 } |
webmaster@1
|
69 // file_check_location() checks whether the destination is inside the Drupal files directory. |
webmaster@1
|
70 if (file_check_location($dest, $file_path)) { |
webmaster@1
|
71 return $dest; |
webmaster@1
|
72 } |
webmaster@1
|
73 // check if the destination is instead inside the Drupal temporary files directory. |
webmaster@1
|
74 else if (file_check_location($dest, file_directory_temp())) { |
webmaster@1
|
75 return $dest; |
webmaster@1
|
76 } |
webmaster@1
|
77 // Not found, try again with prefixed directory path. |
webmaster@1
|
78 else if (file_check_location($file_path .'/'. $dest, $file_path)) { |
webmaster@1
|
79 return $file_path .'/'. $dest; |
webmaster@1
|
80 } |
webmaster@1
|
81 // File not found. |
webmaster@1
|
82 return FALSE; |
webmaster@1
|
83 } |
webmaster@1
|
84 |
webmaster@1
|
85 /** |
webmaster@1
|
86 * Check that the directory exists and is writable. Directories need to |
webmaster@1
|
87 * have execute permissions to be considered a directory by FTP servers, etc. |
webmaster@1
|
88 * |
webmaster@1
|
89 * @param $directory A string containing the name of a directory path. |
webmaster@1
|
90 * @param $mode A Boolean value to indicate if the directory should be created |
webmaster@1
|
91 * if it does not exist or made writable if it is read-only. |
webmaster@1
|
92 * @param $form_item An optional string containing the name of a form item that |
webmaster@1
|
93 * any errors will be attached to. This is useful for settings forms that |
webmaster@1
|
94 * require the user to specify a writable directory. If it can't be made to |
webmaster@1
|
95 * work, a form error will be set preventing them from saving the settings. |
webmaster@1
|
96 * @return FALSE when directory not found, or TRUE when directory exists. |
webmaster@1
|
97 */ |
webmaster@1
|
98 function file_check_directory(&$directory, $mode = 0, $form_item = NULL) { |
webmaster@1
|
99 $directory = rtrim($directory, '/\\'); |
webmaster@1
|
100 |
webmaster@1
|
101 // Check if directory exists. |
webmaster@1
|
102 if (!is_dir($directory)) { |
webmaster@1
|
103 if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory)) { |
webmaster@1
|
104 drupal_set_message(t('The directory %directory has been created.', array('%directory' => $directory))); |
webmaster@1
|
105 @chmod($directory, 0775); // Necessary for non-webserver users. |
webmaster@1
|
106 } |
webmaster@1
|
107 else { |
webmaster@1
|
108 if ($form_item) { |
webmaster@1
|
109 form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory))); |
webmaster@1
|
110 } |
webmaster@1
|
111 return FALSE; |
webmaster@1
|
112 } |
webmaster@1
|
113 } |
webmaster@1
|
114 |
webmaster@1
|
115 // Check to see if the directory is writable. |
webmaster@1
|
116 if (!is_writable($directory)) { |
webmaster@1
|
117 if (($mode & FILE_MODIFY_PERMISSIONS) && @chmod($directory, 0775)) { |
webmaster@1
|
118 drupal_set_message(t('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory))); |
webmaster@1
|
119 } |
webmaster@1
|
120 else { |
webmaster@1
|
121 form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory))); |
webmaster@1
|
122 watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR); |
webmaster@1
|
123 return FALSE; |
webmaster@1
|
124 } |
webmaster@1
|
125 } |
webmaster@1
|
126 |
webmaster@1
|
127 if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) { |
webmaster@1
|
128 $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks"; |
webmaster@1
|
129 if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) { |
webmaster@1
|
130 fclose($fp); |
webmaster@1
|
131 chmod($directory .'/.htaccess', 0664); |
webmaster@1
|
132 } |
webmaster@1
|
133 else { |
webmaster@1
|
134 $variables = array('%directory' => $directory, '!htaccess' => '<br />'. nl2br(check_plain($htaccess_lines))); |
webmaster@1
|
135 form_set_error($form_item, t("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables)); |
webmaster@1
|
136 watchdog('security', "Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables, WATCHDOG_ERROR); |
webmaster@1
|
137 } |
webmaster@1
|
138 } |
webmaster@1
|
139 |
webmaster@1
|
140 return TRUE; |
webmaster@1
|
141 } |
webmaster@1
|
142 |
webmaster@1
|
143 /** |
webmaster@1
|
144 * Checks path to see if it is a directory, or a dir/file. |
webmaster@1
|
145 * |
webmaster@1
|
146 * @param $path A string containing a file path. This will be set to the |
webmaster@1
|
147 * directory's path. |
webmaster@1
|
148 * @return If the directory is not in a Drupal writable directory, FALSE is |
webmaster@1
|
149 * returned. Otherwise, the base name of the path is returned. |
webmaster@1
|
150 */ |
webmaster@1
|
151 function file_check_path(&$path) { |
webmaster@1
|
152 // Check if path is a directory. |
webmaster@1
|
153 if (file_check_directory($path)) { |
webmaster@1
|
154 return ''; |
webmaster@1
|
155 } |
webmaster@1
|
156 |
webmaster@1
|
157 // Check if path is a possible dir/file. |
webmaster@1
|
158 $filename = basename($path); |
webmaster@1
|
159 $path = dirname($path); |
webmaster@1
|
160 if (file_check_directory($path)) { |
webmaster@1
|
161 return $filename; |
webmaster@1
|
162 } |
webmaster@1
|
163 |
webmaster@1
|
164 return FALSE; |
webmaster@1
|
165 } |
webmaster@1
|
166 |
webmaster@1
|
167 /** |
webmaster@1
|
168 * Check if a file is really located inside $directory. Should be used to make |
webmaster@1
|
169 * sure a file specified is really located within the directory to prevent |
webmaster@1
|
170 * exploits. |
webmaster@1
|
171 * |
webmaster@1
|
172 * @code |
webmaster@1
|
173 * // Returns FALSE: |
webmaster@1
|
174 * file_check_location('/www/example.com/files/../../../etc/passwd', '/www/example.com/files'); |
webmaster@1
|
175 * @endcode |
webmaster@1
|
176 * |
webmaster@1
|
177 * @param $source A string set to the file to check. |
webmaster@1
|
178 * @param $directory A string where the file should be located. |
webmaster@1
|
179 * @return 0 for invalid path or the real path of the source. |
webmaster@1
|
180 */ |
webmaster@1
|
181 function file_check_location($source, $directory = '') { |
webmaster@1
|
182 $check = realpath($source); |
webmaster@1
|
183 if ($check) { |
webmaster@1
|
184 $source = $check; |
webmaster@1
|
185 } |
webmaster@1
|
186 else { |
webmaster@1
|
187 // This file does not yet exist |
webmaster@1
|
188 $source = realpath(dirname($source)) .'/'. basename($source); |
webmaster@1
|
189 } |
webmaster@1
|
190 $directory = realpath($directory); |
webmaster@1
|
191 if ($directory && strpos($source, $directory) !== 0) { |
webmaster@1
|
192 return 0; |
webmaster@1
|
193 } |
webmaster@1
|
194 return $source; |
webmaster@1
|
195 } |
webmaster@1
|
196 |
webmaster@1
|
197 /** |
webmaster@1
|
198 * Copies a file to a new location. This is a powerful function that in many ways |
webmaster@1
|
199 * performs like an advanced version of copy(). |
webmaster@1
|
200 * - Checks if $source and $dest are valid and readable/writable. |
webmaster@1
|
201 * - Performs a file copy if $source is not equal to $dest. |
webmaster@1
|
202 * - If file already exists in $dest either the call will error out, replace the |
webmaster@1
|
203 * file or rename the file based on the $replace parameter. |
webmaster@1
|
204 * |
webmaster@1
|
205 * @param $source A string specifying the file location of the original file. |
webmaster@1
|
206 * This parameter will contain the resulting destination filename in case of |
webmaster@1
|
207 * success. |
webmaster@1
|
208 * @param $dest A string containing the directory $source should be copied to. |
webmaster@1
|
209 * If this value is omitted, Drupal's 'files' directory will be used. |
webmaster@1
|
210 * @param $replace Replace behavior when the destination file already exists. |
webmaster@1
|
211 * - FILE_EXISTS_REPLACE - Replace the existing file |
webmaster@1
|
212 * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique |
webmaster@1
|
213 * - FILE_EXISTS_ERROR - Do nothing and return FALSE. |
webmaster@1
|
214 * @return True for success, FALSE for failure. |
webmaster@1
|
215 */ |
webmaster@1
|
216 function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) { |
webmaster@1
|
217 $dest = file_create_path($dest); |
webmaster@1
|
218 |
webmaster@1
|
219 $directory = $dest; |
webmaster@1
|
220 $basename = file_check_path($directory); |
webmaster@1
|
221 |
webmaster@1
|
222 // Make sure we at least have a valid directory. |
webmaster@1
|
223 if ($basename === FALSE) { |
webmaster@1
|
224 $source = is_object($source) ? $source->filepath : $source; |
webmaster@1
|
225 drupal_set_message(t('The selected file %file could not be uploaded, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $dest)), 'error'); |
webmaster@1
|
226 watchdog('file system', 'The selected file %file could not be uploaded, because the destination %directory could not be found, or because its permissions do not allow the file to be written.', array('%file' => $source, '%directory' => $dest), WATCHDOG_ERROR); |
webmaster@1
|
227 return 0; |
webmaster@1
|
228 } |
webmaster@1
|
229 |
webmaster@1
|
230 // Process a file upload object. |
webmaster@1
|
231 if (is_object($source)) { |
webmaster@1
|
232 $file = $source; |
webmaster@1
|
233 $source = $file->filepath; |
webmaster@1
|
234 if (!$basename) { |
webmaster@1
|
235 $basename = $file->filename; |
webmaster@1
|
236 } |
webmaster@1
|
237 } |
webmaster@1
|
238 |
webmaster@1
|
239 $source = realpath($source); |
webmaster@1
|
240 if (!file_exists($source)) { |
webmaster@1
|
241 drupal_set_message(t('The selected file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $source)), 'error'); |
webmaster@1
|
242 return 0; |
webmaster@1
|
243 } |
webmaster@1
|
244 |
webmaster@1
|
245 // If the destination file is not specified then use the filename of the source file. |
webmaster@1
|
246 $basename = $basename ? $basename : basename($source); |
webmaster@1
|
247 $dest = $directory .'/'. $basename; |
webmaster@1
|
248 |
webmaster@1
|
249 // Make sure source and destination filenames are not the same, makes no sense |
webmaster@1
|
250 // to copy it if they are. In fact copying the file will most likely result in |
webmaster@1
|
251 // a 0 byte file. Which is bad. Real bad. |
webmaster@1
|
252 if ($source != realpath($dest)) { |
webmaster@1
|
253 if (!$dest = file_destination($dest, $replace)) { |
webmaster@1
|
254 drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $source)), 'error'); |
webmaster@1
|
255 return FALSE; |
webmaster@1
|
256 } |
webmaster@1
|
257 |
webmaster@1
|
258 if (!@copy($source, $dest)) { |
webmaster@1
|
259 drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error'); |
webmaster@1
|
260 return 0; |
webmaster@1
|
261 } |
webmaster@1
|
262 |
webmaster@1
|
263 // Give everyone read access so that FTP'd users or |
webmaster@1
|
264 // non-webserver users can see/read these files, |
webmaster@1
|
265 // and give group write permissions so group members |
webmaster@1
|
266 // can alter files uploaded by the webserver. |
webmaster@1
|
267 @chmod($dest, 0664); |
webmaster@1
|
268 } |
webmaster@1
|
269 |
webmaster@1
|
270 if (isset($file) && is_object($file)) { |
webmaster@1
|
271 $file->filename = $basename; |
webmaster@1
|
272 $file->filepath = $dest; |
webmaster@1
|
273 $source = $file; |
webmaster@1
|
274 } |
webmaster@1
|
275 else { |
webmaster@1
|
276 $source = $dest; |
webmaster@1
|
277 } |
webmaster@1
|
278 |
webmaster@1
|
279 return 1; // Everything went ok. |
webmaster@1
|
280 } |
webmaster@1
|
281 |
webmaster@1
|
282 /** |
webmaster@1
|
283 * Determines the destination path for a file depending on how replacement of |
webmaster@1
|
284 * existing files should be handled. |
webmaster@1
|
285 * |
webmaster@1
|
286 * @param $destination A string specifying the desired path. |
webmaster@1
|
287 * @param $replace Replace behavior when the destination file already exists. |
webmaster@1
|
288 * - FILE_EXISTS_REPLACE - Replace the existing file |
webmaster@1
|
289 * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is |
webmaster@1
|
290 * unique |
webmaster@1
|
291 * - FILE_EXISTS_ERROR - Do nothing and return FALSE. |
webmaster@1
|
292 * @return The destination file path or FALSE if the file already exists and |
webmaster@1
|
293 * FILE_EXISTS_ERROR was specified. |
webmaster@1
|
294 */ |
webmaster@1
|
295 function file_destination($destination, $replace) { |
webmaster@1
|
296 if (file_exists($destination)) { |
webmaster@1
|
297 switch ($replace) { |
webmaster@1
|
298 case FILE_EXISTS_RENAME: |
webmaster@1
|
299 $basename = basename($destination); |
webmaster@1
|
300 $directory = dirname($destination); |
webmaster@1
|
301 $destination = file_create_filename($basename, $directory); |
webmaster@1
|
302 break; |
webmaster@1
|
303 |
webmaster@1
|
304 case FILE_EXISTS_ERROR: |
webmaster@1
|
305 drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $destination)), 'error'); |
webmaster@1
|
306 return FALSE; |
webmaster@1
|
307 } |
webmaster@1
|
308 } |
webmaster@1
|
309 return $destination; |
webmaster@1
|
310 } |
webmaster@1
|
311 |
webmaster@1
|
312 /** |
webmaster@1
|
313 * Moves a file to a new location. |
webmaster@1
|
314 * - Checks if $source and $dest are valid and readable/writable. |
webmaster@1
|
315 * - Performs a file move if $source is not equal to $dest. |
webmaster@1
|
316 * - If file already exists in $dest either the call will error out, replace the |
webmaster@1
|
317 * file or rename the file based on the $replace parameter. |
webmaster@1
|
318 * |
webmaster@1
|
319 * @param $source A string specifying the file location of the original file. |
webmaster@1
|
320 * This parameter will contain the resulting destination filename in case of |
webmaster@1
|
321 * success. |
webmaster@1
|
322 * @param $dest A string containing the directory $source should be copied to. |
webmaster@1
|
323 * If this value is omitted, Drupal's 'files' directory will be used. |
webmaster@1
|
324 * @param $replace Replace behavior when the destination file already exists. |
webmaster@1
|
325 * - FILE_EXISTS_REPLACE - Replace the existing file |
webmaster@1
|
326 * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique |
webmaster@1
|
327 * - FILE_EXISTS_ERROR - Do nothing and return FALSE. |
webmaster@1
|
328 * @return True for success, FALSE for failure. |
webmaster@1
|
329 */ |
webmaster@1
|
330 function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) { |
webmaster@1
|
331 $path_original = is_object($source) ? $source->filepath : $source; |
webmaster@1
|
332 |
webmaster@1
|
333 if (file_copy($source, $dest, $replace)) { |
webmaster@1
|
334 $path_current = is_object($source) ? $source->filepath : $source; |
webmaster@1
|
335 |
webmaster@1
|
336 if ($path_original == $path_current || file_delete($path_original)) { |
webmaster@1
|
337 return 1; |
webmaster@1
|
338 } |
webmaster@1
|
339 drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error'); |
webmaster@1
|
340 } |
webmaster@1
|
341 return 0; |
webmaster@1
|
342 } |
webmaster@1
|
343 |
webmaster@1
|
344 /** |
webmaster@1
|
345 * Munge the filename as needed for security purposes. For instance the file |
webmaster@1
|
346 * name "exploit.php.pps" would become "exploit.php_.pps". |
webmaster@1
|
347 * |
webmaster@1
|
348 * @param $filename The name of a file to modify. |
webmaster@1
|
349 * @param $extensions A space separated list of extensions that should not |
webmaster@1
|
350 * be altered. |
webmaster@1
|
351 * @param $alerts Whether alerts (watchdog, drupal_set_message()) should be |
webmaster@1
|
352 * displayed. |
webmaster@1
|
353 * @return $filename The potentially modified $filename. |
webmaster@1
|
354 */ |
webmaster@1
|
355 function file_munge_filename($filename, $extensions, $alerts = TRUE) { |
webmaster@1
|
356 $original = $filename; |
webmaster@1
|
357 |
webmaster@1
|
358 // Allow potentially insecure uploads for very savvy users and admin |
webmaster@1
|
359 if (!variable_get('allow_insecure_uploads', 0)) { |
webmaster@1
|
360 $whitelist = array_unique(explode(' ', trim($extensions))); |
webmaster@1
|
361 |
webmaster@1
|
362 // Split the filename up by periods. The first part becomes the basename |
webmaster@1
|
363 // the last part the final extension. |
webmaster@1
|
364 $filename_parts = explode('.', $filename); |
webmaster@1
|
365 $new_filename = array_shift($filename_parts); // Remove file basename. |
webmaster@1
|
366 $final_extension = array_pop($filename_parts); // Remove final extension. |
webmaster@1
|
367 |
webmaster@1
|
368 // Loop through the middle parts of the name and add an underscore to the |
webmaster@1
|
369 // end of each section that could be a file extension but isn't in the list |
webmaster@1
|
370 // of allowed extensions. |
webmaster@1
|
371 foreach ($filename_parts as $filename_part) { |
webmaster@1
|
372 $new_filename .= '.'. $filename_part; |
webmaster@1
|
373 if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) { |
webmaster@1
|
374 $new_filename .= '_'; |
webmaster@1
|
375 } |
webmaster@1
|
376 } |
webmaster@1
|
377 $filename = $new_filename .'.'. $final_extension; |
webmaster@1
|
378 |
webmaster@1
|
379 if ($alerts && $original != $filename) { |
webmaster@1
|
380 drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $filename))); |
webmaster@1
|
381 } |
webmaster@1
|
382 } |
webmaster@1
|
383 |
webmaster@1
|
384 return $filename; |
webmaster@1
|
385 } |
webmaster@1
|
386 |
webmaster@1
|
387 /** |
webmaster@1
|
388 * Undo the effect of upload_munge_filename(). |
webmaster@1
|
389 * |
webmaster@1
|
390 * @param $filename string filename |
webmaster@1
|
391 * @return string |
webmaster@1
|
392 */ |
webmaster@1
|
393 function file_unmunge_filename($filename) { |
webmaster@1
|
394 return str_replace('_.', '.', $filename); |
webmaster@1
|
395 } |
webmaster@1
|
396 |
webmaster@1
|
397 /** |
webmaster@1
|
398 * Create a full file path from a directory and filename. If a file with the |
webmaster@1
|
399 * specified name already exists, an alternative will be used. |
webmaster@1
|
400 * |
webmaster@1
|
401 * @param $basename string filename |
webmaster@1
|
402 * @param $directory string directory |
webmaster@1
|
403 * @return |
webmaster@1
|
404 */ |
webmaster@1
|
405 function file_create_filename($basename, $directory) { |
webmaster@1
|
406 $dest = $directory .'/'. $basename; |
webmaster@1
|
407 |
webmaster@1
|
408 if (file_exists($dest)) { |
webmaster@1
|
409 // Destination file already exists, generate an alternative. |
webmaster@1
|
410 if ($pos = strrpos($basename, '.')) { |
webmaster@1
|
411 $name = substr($basename, 0, $pos); |
webmaster@1
|
412 $ext = substr($basename, $pos); |
webmaster@1
|
413 } |
webmaster@1
|
414 else { |
webmaster@1
|
415 $name = $basename; |
webmaster@1
|
416 } |
webmaster@1
|
417 |
webmaster@1
|
418 $counter = 0; |
webmaster@1
|
419 do { |
webmaster@1
|
420 $dest = $directory .'/'. $name .'_'. $counter++ . $ext; |
webmaster@1
|
421 } while (file_exists($dest)); |
webmaster@1
|
422 } |
webmaster@1
|
423 |
webmaster@1
|
424 return $dest; |
webmaster@1
|
425 } |
webmaster@1
|
426 |
webmaster@1
|
427 /** |
webmaster@1
|
428 * Delete a file. |
webmaster@1
|
429 * |
webmaster@1
|
430 * @param $path A string containing a file path. |
webmaster@1
|
431 * @return TRUE for success, FALSE for failure. |
webmaster@1
|
432 */ |
webmaster@1
|
433 function file_delete($path) { |
webmaster@1
|
434 if (is_file($path)) { |
webmaster@1
|
435 return unlink($path); |
webmaster@1
|
436 } |
webmaster@1
|
437 } |
webmaster@1
|
438 |
webmaster@1
|
439 /** |
webmaster@1
|
440 * Determine total disk space used by a single user or the whole filesystem. |
webmaster@1
|
441 * |
webmaster@1
|
442 * @param $uid |
webmaster@1
|
443 * An optional user id. A NULL value returns the total space used |
webmaster@1
|
444 * by all files. |
webmaster@1
|
445 */ |
webmaster@1
|
446 function file_space_used($uid = NULL) { |
webmaster@1
|
447 if (isset($uid)) { |
webmaster@1
|
448 return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid)); |
webmaster@1
|
449 } |
webmaster@1
|
450 return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}')); |
webmaster@1
|
451 } |
webmaster@1
|
452 |
webmaster@1
|
453 /** |
webmaster@1
|
454 * Saves a file upload to a new location. The source file is validated as a |
webmaster@1
|
455 * proper upload and handled as such. |
webmaster@1
|
456 * |
webmaster@1
|
457 * The file will be added to the files table as a temporary file. Temporary files |
webmaster@1
|
458 * are periodically cleaned. To make the file permanent file call |
webmaster@1
|
459 * file_set_status() to change its status. |
webmaster@1
|
460 * |
webmaster@1
|
461 * @param $source |
webmaster@1
|
462 * A string specifying the name of the upload field to save. |
webmaster@1
|
463 * @param $validators |
webmaster@1
|
464 * An optional, associative array of callback functions used to validate the |
webmaster@1
|
465 * file. The keys are function names and the values arrays of callback |
webmaster@1
|
466 * parameters which will be passed in after the user and file objects. The |
webmaster@1
|
467 * functions should return an array of error messages, an empty array |
webmaster@1
|
468 * indicates that the file passed validation. The functions will be called in |
webmaster@1
|
469 * the order specified. |
webmaster@1
|
470 * @param $dest |
webmaster@1
|
471 * A string containing the directory $source should be copied to. If this is |
webmaster@1
|
472 * not provided or is not writable, the temporary directory will be used. |
webmaster@1
|
473 * @param $replace |
webmaster@1
|
474 * A boolean indicating whether an existing file of the same name in the |
webmaster@1
|
475 * destination directory should overwritten. A false value will generate a |
webmaster@1
|
476 * new, unique filename in the destination directory. |
webmaster@1
|
477 * @return |
webmaster@1
|
478 * An object containing the file information, or 0 in the event of an error. |
webmaster@1
|
479 */ |
webmaster@1
|
480 function file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME) { |
webmaster@1
|
481 global $user; |
webmaster@1
|
482 static $upload_cache; |
webmaster@1
|
483 |
webmaster@1
|
484 // Add in our check of the the file name length. |
webmaster@1
|
485 $validators['file_validate_name_length'] = array(); |
webmaster@1
|
486 |
webmaster@1
|
487 // Return cached objects without processing since the file will have |
webmaster@1
|
488 // already been processed and the paths in _FILES will be invalid. |
webmaster@1
|
489 if (isset($upload_cache[$source])) { |
webmaster@1
|
490 return $upload_cache[$source]; |
webmaster@1
|
491 } |
webmaster@1
|
492 |
webmaster@1
|
493 // If a file was uploaded, process it. |
webmaster@1
|
494 if (isset($_FILES['files']) && $_FILES['files']['name'][$source] && is_uploaded_file($_FILES['files']['tmp_name'][$source])) { |
webmaster@1
|
495 // Check for file upload errors and return FALSE if a |
webmaster@1
|
496 // lower level system error occurred. |
webmaster@1
|
497 switch ($_FILES['files']['error'][$source]) { |
webmaster@1
|
498 // @see http://php.net/manual/en/features.file-upload.errors.php |
webmaster@1
|
499 case UPLOAD_ERR_OK: |
webmaster@1
|
500 break; |
webmaster@1
|
501 |
webmaster@1
|
502 case UPLOAD_ERR_INI_SIZE: |
webmaster@1
|
503 case UPLOAD_ERR_FORM_SIZE: |
webmaster@1
|
504 drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $source, '%maxsize' => format_size(file_upload_max_size()))), 'error'); |
webmaster@1
|
505 return 0; |
webmaster@1
|
506 |
webmaster@1
|
507 case UPLOAD_ERR_PARTIAL: |
webmaster@1
|
508 case UPLOAD_ERR_NO_FILE: |
webmaster@1
|
509 drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $source)), 'error'); |
webmaster@1
|
510 return 0; |
webmaster@1
|
511 |
webmaster@1
|
512 // Unknown error |
webmaster@1
|
513 default: |
webmaster@1
|
514 drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)), 'error'); |
webmaster@1
|
515 return 0; |
webmaster@1
|
516 } |
webmaster@1
|
517 |
webmaster@1
|
518 // Build the list of non-munged extensions. |
webmaster@1
|
519 // @todo: this should not be here. we need to figure out the right place. |
webmaster@1
|
520 $extensions = ''; |
webmaster@1
|
521 foreach ($user->roles as $rid => $name) { |
webmaster@1
|
522 $extensions .= ' '. variable_get("upload_extensions_$rid", |
webmaster@1
|
523 variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp')); |
webmaster@1
|
524 } |
webmaster@1
|
525 |
webmaster@1
|
526 // Begin building file object. |
webmaster@1
|
527 $file = new stdClass(); |
webmaster@1
|
528 $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions); |
webmaster@1
|
529 $file->filepath = $_FILES['files']['tmp_name'][$source]; |
webmaster@9
|
530 $file->filemime = file_get_mimetype($file->filename); |
webmaster@1
|
531 |
webmaster@1
|
532 // Rename potentially executable files, to help prevent exploits. |
webmaster@1
|
533 if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { |
webmaster@1
|
534 $file->filemime = 'text/plain'; |
webmaster@1
|
535 $file->filepath .= '.txt'; |
webmaster@1
|
536 $file->filename .= '.txt'; |
webmaster@1
|
537 } |
webmaster@1
|
538 |
webmaster@1
|
539 // If the destination is not provided, or is not writable, then use the |
webmaster@1
|
540 // temporary directory. |
webmaster@1
|
541 if (empty($dest) || file_check_path($dest) === FALSE) { |
webmaster@1
|
542 $dest = file_directory_temp(); |
webmaster@1
|
543 } |
webmaster@1
|
544 |
webmaster@1
|
545 $file->source = $source; |
webmaster@1
|
546 $file->destination = file_destination(file_create_path($dest .'/'. $file->filename), $replace); |
webmaster@1
|
547 $file->filesize = $_FILES['files']['size'][$source]; |
webmaster@1
|
548 |
webmaster@1
|
549 // Call the validation functions. |
webmaster@1
|
550 $errors = array(); |
webmaster@1
|
551 foreach ($validators as $function => $args) { |
webmaster@1
|
552 array_unshift($args, $file); |
webmaster@1
|
553 $errors = array_merge($errors, call_user_func_array($function, $args)); |
webmaster@1
|
554 } |
webmaster@1
|
555 |
webmaster@1
|
556 // Check for validation errors. |
webmaster@1
|
557 if (!empty($errors)) { |
webmaster@1
|
558 $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename)); |
webmaster@1
|
559 if (count($errors) > 1) { |
webmaster@1
|
560 $message .= '<ul><li>'. implode('</li><li>', $errors) .'</li></ul>'; |
webmaster@1
|
561 } |
webmaster@1
|
562 else { |
webmaster@1
|
563 $message .= ' '. array_pop($errors); |
webmaster@1
|
564 } |
webmaster@1
|
565 form_set_error($source, $message); |
webmaster@1
|
566 return 0; |
webmaster@1
|
567 } |
webmaster@1
|
568 |
webmaster@1
|
569 // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary directory. |
webmaster@1
|
570 // This overcomes open_basedir restrictions for future file operations. |
webmaster@1
|
571 $file->filepath = $file->destination; |
webmaster@1
|
572 if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) { |
webmaster@1
|
573 form_set_error($source, t('File upload error. Could not move uploaded file.')); |
webmaster@1
|
574 watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->filepath)); |
webmaster@1
|
575 return 0; |
webmaster@1
|
576 } |
webmaster@1
|
577 |
webmaster@1
|
578 // If we made it this far it's safe to record this file in the database. |
webmaster@1
|
579 $file->uid = $user->uid; |
webmaster@1
|
580 $file->status = FILE_STATUS_TEMPORARY; |
webmaster@1
|
581 $file->timestamp = time(); |
webmaster@1
|
582 drupal_write_record('files', $file); |
webmaster@1
|
583 |
webmaster@1
|
584 // Add file to the cache. |
webmaster@1
|
585 $upload_cache[$source] = $file; |
webmaster@1
|
586 return $file; |
webmaster@1
|
587 } |
webmaster@1
|
588 return 0; |
webmaster@1
|
589 } |
webmaster@1
|
590 |
webmaster@1
|
591 /** |
webmaster@1
|
592 * Check for files with names longer than we can store in the database. |
webmaster@1
|
593 * |
webmaster@1
|
594 * @param $file |
webmaster@1
|
595 * A Drupal file object. |
webmaster@1
|
596 * @return |
webmaster@1
|
597 * An array. If the file name is too long, it will contain an error message. |
webmaster@1
|
598 */ |
webmaster@1
|
599 function file_validate_name_length($file) { |
webmaster@1
|
600 $errors = array(); |
webmaster@1
|
601 |
webmaster@1
|
602 if (strlen($file->filename) > 255) { |
webmaster@1
|
603 $errors[] = t('Its name exceeds the 255 characters limit. Please rename the file and try again.'); |
webmaster@1
|
604 } |
webmaster@1
|
605 return $errors; |
webmaster@1
|
606 } |
webmaster@1
|
607 |
webmaster@1
|
608 /** |
webmaster@1
|
609 * Check that the filename ends with an allowed extension. This check is not |
webmaster@1
|
610 * enforced for the user #1. |
webmaster@1
|
611 * |
webmaster@1
|
612 * @param $file |
webmaster@1
|
613 * A Drupal file object. |
webmaster@1
|
614 * @param $extensions |
webmaster@1
|
615 * A string with a space separated |
webmaster@1
|
616 * @return |
webmaster@1
|
617 * An array. If the file extension is not allowed, it will contain an error message. |
webmaster@1
|
618 */ |
webmaster@1
|
619 function file_validate_extensions($file, $extensions) { |
webmaster@1
|
620 global $user; |
webmaster@1
|
621 |
webmaster@1
|
622 $errors = array(); |
webmaster@1
|
623 |
webmaster@1
|
624 // Bypass validation for uid = 1. |
webmaster@1
|
625 if ($user->uid != 1) { |
webmaster@1
|
626 $regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i'; |
webmaster@1
|
627 if (!preg_match($regex, $file->filename)) { |
webmaster@1
|
628 $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions)); |
webmaster@1
|
629 } |
webmaster@1
|
630 } |
webmaster@1
|
631 return $errors; |
webmaster@1
|
632 } |
webmaster@1
|
633 |
webmaster@1
|
634 /** |
webmaster@1
|
635 * Check that the file's size is below certain limits. This check is not |
webmaster@1
|
636 * enforced for the user #1. |
webmaster@1
|
637 * |
webmaster@1
|
638 * @param $file |
webmaster@1
|
639 * A Drupal file object. |
webmaster@1
|
640 * @param $file_limit |
webmaster@1
|
641 * An integer specifying the maximum file size in bytes. Zero indicates that |
webmaster@1
|
642 * no limit should be enforced. |
webmaster@1
|
643 * @param $$user_limit |
webmaster@1
|
644 * An integer specifying the maximum number of bytes the user is allowed. Zero |
webmaster@1
|
645 * indicates that no limit should be enforced. |
webmaster@1
|
646 * @return |
webmaster@1
|
647 * An array. If the file size exceeds limits, it will contain an error message. |
webmaster@1
|
648 */ |
webmaster@1
|
649 function file_validate_size($file, $file_limit = 0, $user_limit = 0) { |
webmaster@1
|
650 global $user; |
webmaster@1
|
651 |
webmaster@1
|
652 $errors = array(); |
webmaster@1
|
653 |
webmaster@1
|
654 // Bypass validation for uid = 1. |
webmaster@1
|
655 if ($user->uid != 1) { |
webmaster@1
|
656 if ($file_limit && $file->filesize > $file_limit) { |
webmaster@1
|
657 $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit))); |
webmaster@1
|
658 } |
webmaster@1
|
659 |
webmaster@1
|
660 $total_size = file_space_used($user->uid) + $file->filesize; |
webmaster@1
|
661 if ($user_limit && $total_size > $user_limit) { |
webmaster@1
|
662 $errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit))); |
webmaster@1
|
663 } |
webmaster@1
|
664 } |
webmaster@1
|
665 return $errors; |
webmaster@1
|
666 } |
webmaster@1
|
667 |
webmaster@1
|
668 /** |
webmaster@1
|
669 * Check that the file is recognized by image_get_info() as an image. |
webmaster@1
|
670 * |
webmaster@1
|
671 * @param $file |
webmaster@1
|
672 * A Drupal file object. |
webmaster@1
|
673 * @return |
webmaster@1
|
674 * An array. If the file is not an image, it will contain an error message. |
webmaster@1
|
675 */ |
webmaster@1
|
676 function file_validate_is_image(&$file) { |
webmaster@1
|
677 $errors = array(); |
webmaster@1
|
678 |
webmaster@1
|
679 $info = image_get_info($file->filepath); |
webmaster@1
|
680 if (!$info || empty($info['extension'])) { |
webmaster@1
|
681 $errors[] = t('Only JPEG, PNG and GIF images are allowed.'); |
webmaster@1
|
682 } |
webmaster@1
|
683 |
webmaster@1
|
684 return $errors; |
webmaster@1
|
685 } |
webmaster@1
|
686 |
webmaster@1
|
687 /** |
webmaster@1
|
688 * If the file is an image verify that its dimensions are within the specified |
webmaster@1
|
689 * maximum and minimum dimensions. Non-image files will be ignored. |
webmaster@1
|
690 * |
webmaster@1
|
691 * @param $file |
webmaster@1
|
692 * A Drupal file object. This function may resize the file affecting its size. |
webmaster@1
|
693 * @param $maximum_dimensions |
webmaster@1
|
694 * An optional string in the form WIDTHxHEIGHT e.g. '640x480' or '85x85'. If |
webmaster@1
|
695 * an image toolkit is installed the image will be resized down to these |
webmaster@1
|
696 * dimensions. A value of 0 indicates no restriction on size, so resizing |
webmaster@1
|
697 * will be attempted. |
webmaster@1
|
698 * @param $minimum_dimensions |
webmaster@1
|
699 * An optional string in the form WIDTHxHEIGHT. This will check that the image |
webmaster@1
|
700 * meets a minimum size. A value of 0 indicates no restriction. |
webmaster@1
|
701 * @return |
webmaster@1
|
702 * An array. If the file is an image and did not meet the requirements, it |
webmaster@1
|
703 * will contain an error message. |
webmaster@1
|
704 */ |
webmaster@1
|
705 function file_validate_image_resolution(&$file, $maximum_dimensions = 0, $minimum_dimensions = 0) { |
webmaster@1
|
706 $errors = array(); |
webmaster@1
|
707 |
webmaster@1
|
708 // Check first that the file is an image. |
webmaster@1
|
709 if ($info = image_get_info($file->filepath)) { |
webmaster@1
|
710 if ($maximum_dimensions) { |
webmaster@1
|
711 // Check that it is smaller than the given dimensions. |
webmaster@1
|
712 list($width, $height) = explode('x', $maximum_dimensions); |
webmaster@1
|
713 if ($info['width'] > $width || $info['height'] > $height) { |
webmaster@1
|
714 // Try to resize the image to fit the dimensions. |
webmaster@1
|
715 if (image_get_toolkit() && image_scale($file->filepath, $file->filepath, $width, $height)) { |
webmaster@1
|
716 drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions))); |
webmaster@1
|
717 |
webmaster@1
|
718 // Clear the cached filesize and refresh the image information. |
webmaster@1
|
719 clearstatcache(); |
webmaster@1
|
720 $info = image_get_info($file->filepath); |
webmaster@1
|
721 $file->filesize = $info['file_size']; |
webmaster@1
|
722 } |
webmaster@1
|
723 else { |
webmaster@1
|
724 $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions)); |
webmaster@1
|
725 } |
webmaster@1
|
726 } |
webmaster@1
|
727 } |
webmaster@1
|
728 |
webmaster@1
|
729 if ($minimum_dimensions) { |
webmaster@1
|
730 // Check that it is larger than the given dimensions. |
webmaster@1
|
731 list($width, $height) = explode('x', $minimum_dimensions); |
webmaster@1
|
732 if ($info['width'] < $width || $info['height'] < $height) { |
webmaster@1
|
733 $errors[] = t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => $minimum_dimensions)); |
webmaster@1
|
734 } |
webmaster@1
|
735 } |
webmaster@1
|
736 } |
webmaster@1
|
737 |
webmaster@1
|
738 return $errors; |
webmaster@1
|
739 } |
webmaster@1
|
740 |
webmaster@1
|
741 /** |
webmaster@1
|
742 * Save a string to the specified destination. |
webmaster@1
|
743 * |
webmaster@1
|
744 * @param $data A string containing the contents of the file. |
webmaster@1
|
745 * @param $dest A string containing the destination location. |
webmaster@1
|
746 * @param $replace Replace behavior when the destination file already exists. |
webmaster@1
|
747 * - FILE_EXISTS_REPLACE - Replace the existing file |
webmaster@1
|
748 * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique |
webmaster@1
|
749 * - FILE_EXISTS_ERROR - Do nothing and return FALSE. |
webmaster@1
|
750 * |
webmaster@1
|
751 * @return A string containing the resulting filename or 0 on error |
webmaster@1
|
752 */ |
webmaster@1
|
753 function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) { |
webmaster@1
|
754 $temp = file_directory_temp(); |
webmaster@1
|
755 // On Windows, tempnam() requires an absolute path, so we use realpath(). |
webmaster@1
|
756 $file = tempnam(realpath($temp), 'file'); |
webmaster@1
|
757 if (!$fp = fopen($file, 'wb')) { |
webmaster@1
|
758 drupal_set_message(t('The file could not be created.'), 'error'); |
webmaster@1
|
759 return 0; |
webmaster@1
|
760 } |
webmaster@1
|
761 fwrite($fp, $data); |
webmaster@1
|
762 fclose($fp); |
webmaster@1
|
763 |
webmaster@1
|
764 if (!file_move($file, $dest, $replace)) { |
webmaster@1
|
765 return 0; |
webmaster@1
|
766 } |
webmaster@1
|
767 |
webmaster@1
|
768 return $file; |
webmaster@1
|
769 } |
webmaster@1
|
770 |
webmaster@1
|
771 /** |
webmaster@1
|
772 * Set the status of a file. |
webmaster@1
|
773 * |
webmaster@1
|
774 * @param file A Drupal file object |
webmaster@1
|
775 * @param status A status value to set the file to. |
webmaster@1
|
776 * @return FALSE on failure, TRUE on success and $file->status will contain the |
webmaster@1
|
777 * status. |
webmaster@1
|
778 */ |
webmaster@1
|
779 function file_set_status(&$file, $status) { |
webmaster@1
|
780 if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) { |
webmaster@1
|
781 $file->status = $status; |
webmaster@1
|
782 return TRUE; |
webmaster@1
|
783 } |
webmaster@1
|
784 return FALSE; |
webmaster@1
|
785 } |
webmaster@1
|
786 |
webmaster@1
|
787 /** |
webmaster@1
|
788 * Transfer file using http to client. Pipes a file through Drupal to the |
webmaster@1
|
789 * client. |
webmaster@1
|
790 * |
webmaster@1
|
791 * @param $source File to transfer. |
webmaster@1
|
792 * @param $headers An array of http headers to send along with file. |
webmaster@1
|
793 */ |
webmaster@1
|
794 function file_transfer($source, $headers) { |
webmaster@13
|
795 if (ob_get_level()) { |
webmaster@13
|
796 ob_end_clean(); |
webmaster@13
|
797 } |
webmaster@1
|
798 |
webmaster@1
|
799 foreach ($headers as $header) { |
webmaster@1
|
800 // To prevent HTTP header injection, we delete new lines that are |
webmaster@1
|
801 // not followed by a space or a tab. |
webmaster@1
|
802 // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 |
webmaster@1
|
803 $header = preg_replace('/\r?\n(?!\t| )/', '', $header); |
webmaster@1
|
804 drupal_set_header($header); |
webmaster@1
|
805 } |
webmaster@1
|
806 |
webmaster@1
|
807 $source = file_create_path($source); |
webmaster@1
|
808 |
webmaster@1
|
809 // Transfer file in 1024 byte chunks to save memory usage. |
webmaster@1
|
810 if ($fd = fopen($source, 'rb')) { |
webmaster@1
|
811 while (!feof($fd)) { |
webmaster@1
|
812 print fread($fd, 1024); |
webmaster@1
|
813 } |
webmaster@1
|
814 fclose($fd); |
webmaster@1
|
815 } |
webmaster@1
|
816 else { |
webmaster@1
|
817 drupal_not_found(); |
webmaster@1
|
818 } |
webmaster@1
|
819 exit(); |
webmaster@1
|
820 } |
webmaster@1
|
821 |
webmaster@1
|
822 /** |
webmaster@1
|
823 * Call modules that implement hook_file_download() to find out if a file is |
webmaster@1
|
824 * accessible and what headers it should be transferred with. If a module |
webmaster@1
|
825 * returns -1 drupal_access_denied() will be returned. If one or more modules |
webmaster@1
|
826 * returned headers the download will start with the returned headers. If no |
webmaster@1
|
827 * modules respond drupal_not_found() will be returned. |
webmaster@1
|
828 */ |
webmaster@1
|
829 function file_download() { |
webmaster@1
|
830 // Merge remainder of arguments from GET['q'], into relative file path. |
webmaster@1
|
831 $args = func_get_args(); |
webmaster@1
|
832 $filepath = implode('/', $args); |
webmaster@1
|
833 |
webmaster@1
|
834 // Maintain compatibility with old ?file=paths saved in node bodies. |
webmaster@1
|
835 if (isset($_GET['file'])) { |
webmaster@1
|
836 $filepath = $_GET['file']; |
webmaster@1
|
837 } |
webmaster@1
|
838 |
webmaster@1
|
839 if (file_exists(file_create_path($filepath))) { |
webmaster@1
|
840 $headers = module_invoke_all('file_download', $filepath); |
webmaster@1
|
841 if (in_array(-1, $headers)) { |
webmaster@1
|
842 return drupal_access_denied(); |
webmaster@1
|
843 } |
webmaster@1
|
844 if (count($headers)) { |
webmaster@1
|
845 file_transfer($filepath, $headers); |
webmaster@1
|
846 } |
webmaster@1
|
847 } |
webmaster@1
|
848 return drupal_not_found(); |
webmaster@1
|
849 } |
webmaster@1
|
850 |
webmaster@1
|
851 |
webmaster@1
|
852 /** |
webmaster@1
|
853 * Finds all files that match a given mask in a given directory. |
webmaster@1
|
854 * Directories and files beginning with a period are excluded; this |
webmaster@1
|
855 * prevents hidden files and directories (such as SVN working directories) |
webmaster@1
|
856 * from being scanned. |
webmaster@1
|
857 * |
webmaster@1
|
858 * @param $dir |
webmaster@1
|
859 * The base directory for the scan, without trailing slash. |
webmaster@1
|
860 * @param $mask |
webmaster@1
|
861 * The regular expression of the files to find. |
webmaster@1
|
862 * @param $nomask |
webmaster@1
|
863 * An array of files/directories to ignore. |
webmaster@1
|
864 * @param $callback |
webmaster@1
|
865 * The callback function to call for each match. |
webmaster@1
|
866 * @param $recurse |
webmaster@1
|
867 * When TRUE, the directory scan will recurse the entire tree |
webmaster@1
|
868 * starting at the provided directory. |
webmaster@1
|
869 * @param $key |
webmaster@1
|
870 * The key to be used for the returned array of files. Possible |
webmaster@1
|
871 * values are "filename", for the path starting with $dir, |
webmaster@1
|
872 * "basename", for the basename of the file, and "name" for the name |
webmaster@1
|
873 * of the file without an extension. |
webmaster@1
|
874 * @param $min_depth |
webmaster@1
|
875 * Minimum depth of directories to return files from. |
webmaster@1
|
876 * @param $depth |
webmaster@1
|
877 * Current depth of recursion. This parameter is only used internally and should not be passed. |
webmaster@1
|
878 * |
webmaster@1
|
879 * @return |
webmaster@1
|
880 * An associative array (keyed on the provided key) of objects with |
webmaster@1
|
881 * "path", "basename", and "name" members corresponding to the |
webmaster@1
|
882 * matching files. |
webmaster@1
|
883 */ |
webmaster@1
|
884 function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename', $min_depth = 0, $depth = 0) { |
webmaster@1
|
885 $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename'); |
webmaster@1
|
886 $files = array(); |
webmaster@1
|
887 |
webmaster@1
|
888 if (is_dir($dir) && $handle = opendir($dir)) { |
webmaster@11
|
889 while (FALSE !== ($file = readdir($handle))) { |
webmaster@1
|
890 if (!in_array($file, $nomask) && $file[0] != '.') { |
webmaster@1
|
891 if (is_dir("$dir/$file") && $recurse) { |
webmaster@1
|
892 // Give priority to files in this folder by merging them in after any subdirectory files. |
webmaster@1
|
893 $files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files); |
webmaster@1
|
894 } |
webmaster@1
|
895 elseif ($depth >= $min_depth && ereg($mask, $file)) { |
webmaster@1
|
896 // Always use this match over anything already set in $files with the same $$key. |
webmaster@1
|
897 $filename = "$dir/$file"; |
webmaster@1
|
898 $basename = basename($file); |
webmaster@1
|
899 $name = substr($basename, 0, strrpos($basename, '.')); |
webmaster@1
|
900 $files[$$key] = new stdClass(); |
webmaster@1
|
901 $files[$$key]->filename = $filename; |
webmaster@1
|
902 $files[$$key]->basename = $basename; |
webmaster@1
|
903 $files[$$key]->name = $name; |
webmaster@1
|
904 if ($callback) { |
webmaster@1
|
905 $callback($filename); |
webmaster@1
|
906 } |
webmaster@1
|
907 } |
webmaster@1
|
908 } |
webmaster@1
|
909 } |
webmaster@1
|
910 |
webmaster@1
|
911 closedir($handle); |
webmaster@1
|
912 } |
webmaster@1
|
913 |
webmaster@1
|
914 return $files; |
webmaster@1
|
915 } |
webmaster@1
|
916 |
webmaster@1
|
917 /** |
webmaster@1
|
918 * Determine the default temporary directory. |
webmaster@1
|
919 * |
webmaster@1
|
920 * @return A string containing a temp directory. |
webmaster@1
|
921 */ |
webmaster@1
|
922 function file_directory_temp() { |
webmaster@1
|
923 $temporary_directory = variable_get('file_directory_temp', NULL); |
webmaster@1
|
924 |
webmaster@1
|
925 if (is_null($temporary_directory)) { |
webmaster@1
|
926 $directories = array(); |
webmaster@1
|
927 |
webmaster@1
|
928 // Has PHP been set with an upload_tmp_dir? |
webmaster@1
|
929 if (ini_get('upload_tmp_dir')) { |
webmaster@1
|
930 $directories[] = ini_get('upload_tmp_dir'); |
webmaster@1
|
931 } |
webmaster@1
|
932 |
webmaster@1
|
933 // Operating system specific dirs. |
webmaster@1
|
934 if (substr(PHP_OS, 0, 3) == 'WIN') { |
webmaster@1
|
935 $directories[] = 'c:\\windows\\temp'; |
webmaster@1
|
936 $directories[] = 'c:\\winnt\\temp'; |
webmaster@1
|
937 $path_delimiter = '\\'; |
webmaster@1
|
938 } |
webmaster@1
|
939 else { |
webmaster@1
|
940 $directories[] = '/tmp'; |
webmaster@1
|
941 $path_delimiter = '/'; |
webmaster@1
|
942 } |
webmaster@1
|
943 |
webmaster@1
|
944 foreach ($directories as $directory) { |
webmaster@1
|
945 if (!$temporary_directory && is_dir($directory)) { |
webmaster@1
|
946 $temporary_directory = $directory; |
webmaster@1
|
947 } |
webmaster@1
|
948 } |
webmaster@1
|
949 |
webmaster@1
|
950 // if a directory has been found, use it, otherwise default to 'files/tmp' or 'files\\tmp'; |
webmaster@1
|
951 $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter .'tmp'; |
webmaster@1
|
952 variable_set('file_directory_temp', $temporary_directory); |
webmaster@1
|
953 } |
webmaster@1
|
954 |
webmaster@1
|
955 return $temporary_directory; |
webmaster@1
|
956 } |
webmaster@1
|
957 |
webmaster@1
|
958 /** |
webmaster@1
|
959 * Determine the default 'files' directory. |
webmaster@1
|
960 * |
webmaster@1
|
961 * @return A string containing the path to Drupal's 'files' directory. |
webmaster@1
|
962 */ |
webmaster@1
|
963 function file_directory_path() { |
webmaster@1
|
964 return variable_get('file_directory_path', conf_path() .'/files'); |
webmaster@1
|
965 } |
webmaster@1
|
966 |
webmaster@1
|
967 /** |
webmaster@1
|
968 * Determine the maximum file upload size by querying the PHP settings. |
webmaster@1
|
969 * |
webmaster@1
|
970 * @return |
webmaster@1
|
971 * A file size limit in bytes based on the PHP upload_max_filesize and post_max_size |
webmaster@1
|
972 */ |
webmaster@1
|
973 function file_upload_max_size() { |
webmaster@1
|
974 static $max_size = -1; |
webmaster@1
|
975 |
webmaster@1
|
976 if ($max_size < 0) { |
webmaster@1
|
977 $upload_max = parse_size(ini_get('upload_max_filesize')); |
webmaster@1
|
978 $post_max = parse_size(ini_get('post_max_size')); |
webmaster@1
|
979 $max_size = ($upload_max < $post_max) ? $upload_max : $post_max; |
webmaster@1
|
980 } |
webmaster@1
|
981 return $max_size; |
webmaster@1
|
982 } |
webmaster@1
|
983 |
webmaster@1
|
984 /** |
webmaster@9
|
985 * Determine an Internet Media Type, or MIME type from a filename. |
webmaster@9
|
986 * |
webmaster@9
|
987 * @param $filename |
webmaster@9
|
988 * Name of the file, including extension. |
webmaster@9
|
989 * @param $mapping |
webmaster@9
|
990 * An optional array of extension to media type mappings in the form |
webmaster@9
|
991 * 'extension1|extension2|...' => 'type'. |
webmaster@9
|
992 * |
webmaster@9
|
993 * @return |
webmaster@9
|
994 * The internet media type registered for the extension or application/octet-stream for unknown extensions. |
webmaster@9
|
995 */ |
webmaster@9
|
996 function file_get_mimetype($filename, $mapping = NULL) { |
webmaster@9
|
997 if (!is_array($mapping)) { |
webmaster@9
|
998 $mapping = variable_get('mime_extension_mapping', array( |
webmaster@9
|
999 'ez' => 'application/andrew-inset', |
webmaster@9
|
1000 'atom' => 'application/atom', |
webmaster@9
|
1001 'atomcat' => 'application/atomcat+xml', |
webmaster@9
|
1002 'atomsrv' => 'application/atomserv+xml', |
webmaster@9
|
1003 'cap|pcap' => 'application/cap', |
webmaster@9
|
1004 'cu' => 'application/cu-seeme', |
webmaster@9
|
1005 'tsp' => 'application/dsptype', |
webmaster@9
|
1006 'spl' => 'application/x-futuresplash', |
webmaster@9
|
1007 'hta' => 'application/hta', |
webmaster@9
|
1008 'jar' => 'application/java-archive', |
webmaster@9
|
1009 'ser' => 'application/java-serialized-object', |
webmaster@9
|
1010 'class' => 'application/java-vm', |
webmaster@9
|
1011 'hqx' => 'application/mac-binhex40', |
webmaster@9
|
1012 'cpt' => 'image/x-corelphotopaint', |
webmaster@9
|
1013 'nb' => 'application/mathematica', |
webmaster@9
|
1014 'mdb' => 'application/msaccess', |
webmaster@9
|
1015 'doc|dot' => 'application/msword', |
webmaster@9
|
1016 'bin' => 'application/octet-stream', |
webmaster@9
|
1017 'oda' => 'application/oda', |
webmaster@9
|
1018 'ogg|ogx' => 'application/ogg', |
webmaster@9
|
1019 'pdf' => 'application/pdf', |
webmaster@9
|
1020 'key' => 'application/pgp-keys', |
webmaster@9
|
1021 'pgp' => 'application/pgp-signature', |
webmaster@9
|
1022 'prf' => 'application/pics-rules', |
webmaster@9
|
1023 'ps|ai|eps' => 'application/postscript', |
webmaster@9
|
1024 'rar' => 'application/rar', |
webmaster@9
|
1025 'rdf' => 'application/rdf+xml', |
webmaster@9
|
1026 'rss' => 'application/rss+xml', |
webmaster@9
|
1027 'rtf' => 'application/rtf', |
webmaster@9
|
1028 'smi|smil' => 'application/smil', |
webmaster@9
|
1029 'wpd' => 'application/wordperfect', |
webmaster@9
|
1030 'wp5' => 'application/wordperfect5.1', |
webmaster@9
|
1031 'xhtml|xht' => 'application/xhtml+xml', |
webmaster@9
|
1032 'xml|xsl' => 'application/xml', |
webmaster@9
|
1033 'zip' => 'application/zip', |
webmaster@9
|
1034 'cdy' => 'application/vnd.cinderella', |
webmaster@9
|
1035 'kml' => 'application/vnd.google-earth.kml+xml', |
webmaster@9
|
1036 'kmz' => 'application/vnd.google-earth.kmz', |
webmaster@9
|
1037 'xul' => 'application/vnd.mozilla.xul+xml', |
webmaster@9
|
1038 'xls|xlb|xlt' => 'application/vnd.ms-excel', |
webmaster@9
|
1039 'cat' => 'application/vnd.ms-pki.seccat', |
webmaster@9
|
1040 'stl' => 'application/vnd.ms-pki.stl', |
webmaster@9
|
1041 'ppt|pps' => 'application/vnd.ms-powerpoint', |
webmaster@9
|
1042 'odc' => 'application/vnd.oasis.opendocument.chart', |
webmaster@9
|
1043 'odb' => 'application/vnd.oasis.opendocument.database', |
webmaster@9
|
1044 'odf' => 'application/vnd.oasis.opendocument.formula', |
webmaster@9
|
1045 'odg' => 'application/vnd.oasis.opendocument.graphics', |
webmaster@9
|
1046 'otg' => 'application/vnd.oasis.opendocument.graphics-template', |
webmaster@9
|
1047 'odi' => 'application/vnd.oasis.opendocument.image', |
webmaster@9
|
1048 'odp' => 'application/vnd.oasis.opendocument.presentation', |
webmaster@9
|
1049 'otp' => 'application/vnd.oasis.opendocument.presentation-template', |
webmaster@9
|
1050 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', |
webmaster@9
|
1051 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', |
webmaster@9
|
1052 'odt' => 'application/vnd.oasis.opendocument.text', |
webmaster@9
|
1053 'odm' => 'application/vnd.oasis.opendocument.text-master', |
webmaster@9
|
1054 'ott' => 'application/vnd.oasis.opendocument.text-template', |
webmaster@9
|
1055 'oth' => 'application/vnd.oasis.opendocument.text-web', |
webmaster@9
|
1056 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', |
webmaster@9
|
1057 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
webmaster@9
|
1058 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', |
webmaster@9
|
1059 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', |
webmaster@9
|
1060 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', |
webmaster@9
|
1061 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', |
webmaster@9
|
1062 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', |
webmaster@9
|
1063 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', |
webmaster@9
|
1064 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', |
webmaster@9
|
1065 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', |
webmaster@9
|
1066 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', |
webmaster@9
|
1067 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', |
webmaster@9
|
1068 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', |
webmaster@9
|
1069 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', |
webmaster@9
|
1070 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
webmaster@9
|
1071 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', |
webmaster@9
|
1072 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', |
webmaster@9
|
1073 'cod' => 'application/vnd.rim.cod', |
webmaster@9
|
1074 'mmf' => 'application/vnd.smaf', |
webmaster@9
|
1075 'sdc' => 'application/vnd.stardivision.calc', |
webmaster@9
|
1076 'sds' => 'application/vnd.stardivision.chart', |
webmaster@9
|
1077 'sda' => 'application/vnd.stardivision.draw', |
webmaster@9
|
1078 'sdd' => 'application/vnd.stardivision.impress', |
webmaster@9
|
1079 'sdf' => 'application/vnd.stardivision.math', |
webmaster@9
|
1080 'sdw' => 'application/vnd.stardivision.writer', |
webmaster@9
|
1081 'sgl' => 'application/vnd.stardivision.writer-global', |
webmaster@9
|
1082 'sxc' => 'application/vnd.sun.xml.calc', |
webmaster@9
|
1083 'stc' => 'application/vnd.sun.xml.calc.template', |
webmaster@9
|
1084 'sxd' => 'application/vnd.sun.xml.draw', |
webmaster@9
|
1085 'std' => 'application/vnd.sun.xml.draw.template', |
webmaster@9
|
1086 'sxi' => 'application/vnd.sun.xml.impress', |
webmaster@9
|
1087 'sti' => 'application/vnd.sun.xml.impress.template', |
webmaster@9
|
1088 'sxm' => 'application/vnd.sun.xml.math', |
webmaster@9
|
1089 'sxw' => 'application/vnd.sun.xml.writer', |
webmaster@9
|
1090 'sxg' => 'application/vnd.sun.xml.writer.global', |
webmaster@9
|
1091 'stw' => 'application/vnd.sun.xml.writer.template', |
webmaster@9
|
1092 'sis' => 'application/vnd.symbian.install', |
webmaster@9
|
1093 'vsd' => 'application/vnd.visio', |
webmaster@9
|
1094 'wbxml' => 'application/vnd.wap.wbxml', |
webmaster@9
|
1095 'wmlc' => 'application/vnd.wap.wmlc', |
webmaster@9
|
1096 'wmlsc' => 'application/vnd.wap.wmlscriptc', |
webmaster@9
|
1097 'wk' => 'application/x-123', |
webmaster@9
|
1098 '7z' => 'application/x-7z-compressed', |
webmaster@9
|
1099 'abw' => 'application/x-abiword', |
webmaster@9
|
1100 'dmg' => 'application/x-apple-diskimage', |
webmaster@9
|
1101 'bcpio' => 'application/x-bcpio', |
webmaster@9
|
1102 'torrent' => 'application/x-bittorrent', |
webmaster@9
|
1103 'cab' => 'application/x-cab', |
webmaster@9
|
1104 'cbr' => 'application/x-cbr', |
webmaster@9
|
1105 'cbz' => 'application/x-cbz', |
webmaster@9
|
1106 'cdf' => 'application/x-cdf', |
webmaster@9
|
1107 'vcd' => 'application/x-cdlink', |
webmaster@9
|
1108 'pgn' => 'application/x-chess-pgn', |
webmaster@9
|
1109 'cpio' => 'application/x-cpio', |
webmaster@9
|
1110 'csh' => 'text/x-csh', |
webmaster@9
|
1111 'deb|udeb' => 'application/x-debian-package', |
webmaster@9
|
1112 'dcr|dir|dxr' => 'application/x-director', |
webmaster@9
|
1113 'dms' => 'application/x-dms', |
webmaster@9
|
1114 'wad' => 'application/x-doom', |
webmaster@9
|
1115 'dvi' => 'application/x-dvi', |
webmaster@9
|
1116 'rhtml' => 'application/x-httpd-eruby', |
webmaster@9
|
1117 'flac' => 'application/x-flac', |
webmaster@9
|
1118 'pfa|pfb|gsf|pcf|pcf.Z' => 'application/x-font', |
webmaster@9
|
1119 'mm' => 'application/x-freemind', |
webmaster@9
|
1120 'gnumeric' => 'application/x-gnumeric', |
webmaster@9
|
1121 'sgf' => 'application/x-go-sgf', |
webmaster@9
|
1122 'gcf' => 'application/x-graphing-calculator', |
webmaster@9
|
1123 'gtar|tgz|taz' => 'application/x-gtar', |
webmaster@9
|
1124 'hdf' => 'application/x-hdf', |
webmaster@9
|
1125 'phtml|pht|php' => 'application/x-httpd-php', |
webmaster@9
|
1126 'phps' => 'application/x-httpd-php-source', |
webmaster@9
|
1127 'php3' => 'application/x-httpd-php3', |
webmaster@9
|
1128 'php3p' => 'application/x-httpd-php3-preprocessed', |
webmaster@9
|
1129 'php4' => 'application/x-httpd-php4', |
webmaster@9
|
1130 'ica' => 'application/x-ica', |
webmaster@9
|
1131 'ins|isp' => 'application/x-internet-signup', |
webmaster@9
|
1132 'iii' => 'application/x-iphone', |
webmaster@9
|
1133 'iso' => 'application/x-iso9660-image', |
webmaster@9
|
1134 'jnlp' => 'application/x-java-jnlp-file', |
webmaster@9
|
1135 'js' => 'application/x-javascript', |
webmaster@9
|
1136 'jmz' => 'application/x-jmol', |
webmaster@9
|
1137 'chrt' => 'application/x-kchart', |
webmaster@9
|
1138 'kil' => 'application/x-killustrator', |
webmaster@9
|
1139 'skp|skd|skt|skm' => 'application/x-koan', |
webmaster@9
|
1140 'kpr|kpt' => 'application/x-kpresenter', |
webmaster@9
|
1141 'ksp' => 'application/x-kspread', |
webmaster@9
|
1142 'kwd|kwt' => 'application/x-kword', |
webmaster@9
|
1143 'latex' => 'application/x-latex', |
webmaster@9
|
1144 'lha' => 'application/x-lha', |
webmaster@9
|
1145 'lyx' => 'application/x-lyx', |
webmaster@9
|
1146 'lzh' => 'application/x-lzh', |
webmaster@9
|
1147 'lzx' => 'application/x-lzx', |
webmaster@9
|
1148 'frm|maker|frame|fm|fb|book|fbdoc' => 'application/x-maker', |
webmaster@9
|
1149 'mif' => 'application/x-mif', |
webmaster@9
|
1150 'wmd' => 'application/x-ms-wmd', |
webmaster@9
|
1151 'wmz' => 'application/x-ms-wmz', |
webmaster@9
|
1152 'com|exe|bat|dll' => 'application/x-msdos-program', |
webmaster@9
|
1153 'msi' => 'application/x-msi', |
webmaster@9
|
1154 'nc' => 'application/x-netcdf', |
webmaster@9
|
1155 'pac' => 'application/x-ns-proxy-autoconfig', |
webmaster@9
|
1156 'nwc' => 'application/x-nwc', |
webmaster@9
|
1157 'o' => 'application/x-object', |
webmaster@9
|
1158 'oza' => 'application/x-oz-application', |
webmaster@9
|
1159 'p7r' => 'application/x-pkcs7-certreqresp', |
webmaster@9
|
1160 'crl' => 'application/x-pkcs7-crl', |
webmaster@9
|
1161 'pyc|pyo' => 'application/x-python-code', |
webmaster@9
|
1162 'qtl' => 'application/x-quicktimeplayer', |
webmaster@9
|
1163 'rpm' => 'application/x-redhat-package-manager', |
webmaster@9
|
1164 'sh' => 'text/x-sh', |
webmaster@9
|
1165 'shar' => 'application/x-shar', |
webmaster@9
|
1166 'swf|swfl' => 'application/x-shockwave-flash', |
webmaster@9
|
1167 'sit|sitx' => 'application/x-stuffit', |
webmaster@9
|
1168 'sv4cpio' => 'application/x-sv4cpio', |
webmaster@9
|
1169 'sv4crc' => 'application/x-sv4crc', |
webmaster@9
|
1170 'tar' => 'application/x-tar', |
webmaster@9
|
1171 'tcl' => 'application/x-tcl', |
webmaster@9
|
1172 'gf' => 'application/x-tex-gf', |
webmaster@9
|
1173 'pk' => 'application/x-tex-pk', |
webmaster@9
|
1174 'texinfo|texi' => 'application/x-texinfo', |
webmaster@9
|
1175 '~|%|bak|old|sik' => 'application/x-trash', |
webmaster@9
|
1176 't|tr|roff' => 'application/x-troff', |
webmaster@9
|
1177 'man' => 'application/x-troff-man', |
webmaster@9
|
1178 'me' => 'application/x-troff-me', |
webmaster@9
|
1179 'ms' => 'application/x-troff-ms', |
webmaster@9
|
1180 'ustar' => 'application/x-ustar', |
webmaster@9
|
1181 'src' => 'application/x-wais-source', |
webmaster@9
|
1182 'wz' => 'application/x-wingz', |
webmaster@9
|
1183 'crt' => 'application/x-x509-ca-cert', |
webmaster@9
|
1184 'xcf' => 'application/x-xcf', |
webmaster@9
|
1185 'fig' => 'application/x-xfig', |
webmaster@9
|
1186 'xpi' => 'application/x-xpinstall', |
webmaster@9
|
1187 'au|snd' => 'audio/basic', |
webmaster@9
|
1188 'mid|midi|kar' => 'audio/midi', |
webmaster@9
|
1189 'mpga|mpega|mp2|mp3|m4a' => 'audio/mpeg', |
webmaster@9
|
1190 'm3u' => 'audio/x-mpegurl', |
webmaster@9
|
1191 'oga|spx' => 'audio/ogg', |
webmaster@9
|
1192 'sid' => 'audio/prs.sid', |
webmaster@9
|
1193 'aif|aiff|aifc' => 'audio/x-aiff', |
webmaster@9
|
1194 'gsm' => 'audio/x-gsm', |
webmaster@9
|
1195 'wma' => 'audio/x-ms-wma', |
webmaster@9
|
1196 'wax' => 'audio/x-ms-wax', |
webmaster@9
|
1197 'ra|rm|ram' => 'audio/x-pn-realaudio', |
webmaster@9
|
1198 'ra' => 'audio/x-realaudio', |
webmaster@9
|
1199 'pls' => 'audio/x-scpls', |
webmaster@9
|
1200 'sd2' => 'audio/x-sd2', |
webmaster@9
|
1201 'wav' => 'audio/x-wav', |
webmaster@9
|
1202 'alc' => 'chemical/x-alchemy', |
webmaster@9
|
1203 'cac|cache' => 'chemical/x-cache', |
webmaster@9
|
1204 'csf' => 'chemical/x-cache-csf', |
webmaster@9
|
1205 'cbin|cascii|ctab' => 'chemical/x-cactvs-binary', |
webmaster@9
|
1206 'cdx' => 'chemical/x-cdx', |
webmaster@9
|
1207 'cer' => 'chemical/x-cerius', |
webmaster@9
|
1208 'c3d' => 'chemical/x-chem3d', |
webmaster@9
|
1209 'chm' => 'chemical/x-chemdraw', |
webmaster@9
|
1210 'cif' => 'chemical/x-cif', |
webmaster@9
|
1211 'cmdf' => 'chemical/x-cmdf', |
webmaster@9
|
1212 'cml' => 'chemical/x-cml', |
webmaster@9
|
1213 'cpa' => 'chemical/x-compass', |
webmaster@9
|
1214 'bsd' => 'chemical/x-crossfire', |
webmaster@9
|
1215 'csml|csm' => 'chemical/x-csml', |
webmaster@9
|
1216 'ctx' => 'chemical/x-ctx', |
webmaster@9
|
1217 'cxf|cef' => 'chemical/x-cxf', |
webmaster@9
|
1218 'emb|embl' => 'chemical/x-embl-dl-nucleotide', |
webmaster@9
|
1219 'spc' => 'chemical/x-galactic-spc', |
webmaster@9
|
1220 'inp|gam|gamin' => 'chemical/x-gamess-input', |
webmaster@9
|
1221 'fch|fchk' => 'chemical/x-gaussian-checkpoint', |
webmaster@9
|
1222 'cub' => 'chemical/x-gaussian-cube', |
webmaster@9
|
1223 'gau|gjc|gjf' => 'chemical/x-gaussian-input', |
webmaster@9
|
1224 'gal' => 'chemical/x-gaussian-log', |
webmaster@9
|
1225 'gcg' => 'chemical/x-gcg8-sequence', |
webmaster@9
|
1226 'gen' => 'chemical/x-genbank', |
webmaster@9
|
1227 'hin' => 'chemical/x-hin', |
webmaster@9
|
1228 'istr|ist' => 'chemical/x-isostar', |
webmaster@9
|
1229 'jdx|dx' => 'chemical/x-jcamp-dx', |
webmaster@9
|
1230 'kin' => 'chemical/x-kinemage', |
webmaster@9
|
1231 'mcm' => 'chemical/x-macmolecule', |
webmaster@9
|
1232 'mmd|mmod' => 'chemical/x-macromodel-input', |
webmaster@9
|
1233 'mol' => 'chemical/x-mdl-molfile', |
webmaster@9
|
1234 'rd' => 'chemical/x-mdl-rdfile', |
webmaster@9
|
1235 'rxn' => 'chemical/x-mdl-rxnfile', |
webmaster@9
|
1236 'sd|sdf' => 'chemical/x-mdl-sdfile', |
webmaster@9
|
1237 'tgf' => 'chemical/x-mdl-tgf', |
webmaster@9
|
1238 'mcif' => 'chemical/x-mmcif', |
webmaster@9
|
1239 'mol2' => 'chemical/x-mol2', |
webmaster@9
|
1240 'b' => 'chemical/x-molconn-Z', |
webmaster@9
|
1241 'gpt' => 'chemical/x-mopac-graph', |
webmaster@9
|
1242 'mop|mopcrt|mpc|dat|zmt' => 'chemical/x-mopac-input', |
webmaster@9
|
1243 'moo' => 'chemical/x-mopac-out', |
webmaster@9
|
1244 'mvb' => 'chemical/x-mopac-vib', |
webmaster@9
|
1245 'asn' => 'chemical/x-ncbi-asn1-spec', |
webmaster@9
|
1246 'prt|ent' => 'chemical/x-ncbi-asn1-ascii', |
webmaster@9
|
1247 'val|aso' => 'chemical/x-ncbi-asn1-binary', |
webmaster@9
|
1248 'pdb|ent' => 'chemical/x-pdb', |
webmaster@9
|
1249 'ros' => 'chemical/x-rosdal', |
webmaster@9
|
1250 'sw' => 'chemical/x-swissprot', |
webmaster@9
|
1251 'vms' => 'chemical/x-vamas-iso14976', |
webmaster@9
|
1252 'vmd' => 'chemical/x-vmd', |
webmaster@9
|
1253 'xtel' => 'chemical/x-xtel', |
webmaster@9
|
1254 'xyz' => 'chemical/x-xyz', |
webmaster@9
|
1255 'gif' => 'image/gif', |
webmaster@9
|
1256 'ief' => 'image/ief', |
webmaster@9
|
1257 'jpeg|jpg|jpe' => 'image/jpeg', |
webmaster@9
|
1258 'pcx' => 'image/pcx', |
webmaster@9
|
1259 'png' => 'image/png', |
webmaster@9
|
1260 'svg|svgz' => 'image/svg+xml', |
webmaster@9
|
1261 'tiff|tif' => 'image/tiff', |
webmaster@9
|
1262 'djvu|djv' => 'image/vnd.djvu', |
webmaster@9
|
1263 'wbmp' => 'image/vnd.wap.wbmp', |
webmaster@9
|
1264 'ras' => 'image/x-cmu-raster', |
webmaster@9
|
1265 'cdr' => 'image/x-coreldraw', |
webmaster@9
|
1266 'pat' => 'image/x-coreldrawpattern', |
webmaster@9
|
1267 'cdt' => 'image/x-coreldrawtemplate', |
webmaster@9
|
1268 'ico' => 'image/x-icon', |
webmaster@9
|
1269 'art' => 'image/x-jg', |
webmaster@9
|
1270 'jng' => 'image/x-jng', |
webmaster@9
|
1271 'bmp' => 'image/x-ms-bmp', |
webmaster@9
|
1272 'psd' => 'image/x-photoshop', |
webmaster@9
|
1273 'pnm' => 'image/x-portable-anymap', |
webmaster@9
|
1274 'pbm' => 'image/x-portable-bitmap', |
webmaster@9
|
1275 'pgm' => 'image/x-portable-graymap', |
webmaster@9
|
1276 'ppm' => 'image/x-portable-pixmap', |
webmaster@9
|
1277 'rgb' => 'image/x-rgb', |
webmaster@9
|
1278 'xbm' => 'image/x-xbitmap', |
webmaster@9
|
1279 'xpm' => 'image/x-xpixmap', |
webmaster@9
|
1280 'xwd' => 'image/x-xwindowdump', |
webmaster@9
|
1281 'eml' => 'message/rfc822', |
webmaster@9
|
1282 'igs|iges' => 'model/iges', |
webmaster@9
|
1283 'msh|mesh|silo' => 'model/mesh', |
webmaster@9
|
1284 'wrl|vrml' => 'model/vrml', |
webmaster@9
|
1285 'ics|icz' => 'text/calendar', |
webmaster@9
|
1286 'css' => 'text/css', |
webmaster@9
|
1287 'csv' => 'text/csv', |
webmaster@9
|
1288 '323' => 'text/h323', |
webmaster@9
|
1289 'html|htm|shtml' => 'text/html', |
webmaster@9
|
1290 'uls' => 'text/iuls', |
webmaster@9
|
1291 'mml' => 'text/mathml', |
webmaster@9
|
1292 'asc|txt|text|pot' => 'text/plain', |
webmaster@9
|
1293 'rtx' => 'text/richtext', |
webmaster@9
|
1294 'sct|wsc' => 'text/scriptlet', |
webmaster@9
|
1295 'tm|ts' => 'text/texmacs', |
webmaster@9
|
1296 'tsv' => 'text/tab-separated-values', |
webmaster@9
|
1297 'jad' => 'text/vnd.sun.j2me.app-descriptor', |
webmaster@9
|
1298 'wml' => 'text/vnd.wap.wml', |
webmaster@9
|
1299 'wmls' => 'text/vnd.wap.wmlscript', |
webmaster@9
|
1300 'bib' => 'text/x-bibtex', |
webmaster@9
|
1301 'boo' => 'text/x-boo', |
webmaster@9
|
1302 'h++|hpp|hxx|hh' => 'text/x-c++hdr', |
webmaster@9
|
1303 'c++|cpp|cxx|cc' => 'text/x-c++src', |
webmaster@9
|
1304 'h' => 'text/x-chdr', |
webmaster@9
|
1305 'htc' => 'text/x-component', |
webmaster@9
|
1306 'c' => 'text/x-csrc', |
webmaster@9
|
1307 'd' => 'text/x-dsrc', |
webmaster@9
|
1308 'diff|patch' => 'text/x-diff', |
webmaster@9
|
1309 'hs' => 'text/x-haskell', |
webmaster@9
|
1310 'java' => 'text/x-java', |
webmaster@9
|
1311 'lhs' => 'text/x-literate-haskell', |
webmaster@9
|
1312 'moc' => 'text/x-moc', |
webmaster@9
|
1313 'p|pas' => 'text/x-pascal', |
webmaster@9
|
1314 'gcd' => 'text/x-pcs-gcd', |
webmaster@9
|
1315 'pl|pm' => 'text/x-perl', |
webmaster@9
|
1316 'py' => 'text/x-python', |
webmaster@9
|
1317 'etx' => 'text/x-setext', |
webmaster@9
|
1318 'tcl|tk' => 'text/x-tcl', |
webmaster@9
|
1319 'tex|ltx|sty|cls' => 'text/x-tex', |
webmaster@9
|
1320 'vcs' => 'text/x-vcalendar', |
webmaster@9
|
1321 'vcf' => 'text/x-vcard', |
webmaster@9
|
1322 '3gp' => 'video/3gpp', |
webmaster@9
|
1323 'dl' => 'video/dl', |
webmaster@9
|
1324 'dif|dv' => 'video/dv', |
webmaster@9
|
1325 'fli' => 'video/fli', |
webmaster@9
|
1326 'gl' => 'video/gl', |
webmaster@9
|
1327 'mpeg|mpg|mpe' => 'video/mpeg', |
webmaster@9
|
1328 'mp4' => 'video/mp4', |
webmaster@9
|
1329 'ogv' => 'video/ogg', |
webmaster@9
|
1330 'qt|mov' => 'video/quicktime', |
webmaster@9
|
1331 'mxu' => 'video/vnd.mpegurl', |
webmaster@9
|
1332 'lsf|lsx' => 'video/x-la-asf', |
webmaster@9
|
1333 'mng' => 'video/x-mng', |
webmaster@9
|
1334 'asf|asx' => 'video/x-ms-asf', |
webmaster@9
|
1335 'wm' => 'video/x-ms-wm', |
webmaster@9
|
1336 'wmv' => 'video/x-ms-wmv', |
webmaster@9
|
1337 'wmx' => 'video/x-ms-wmx', |
webmaster@9
|
1338 'wvx' => 'video/x-ms-wvx', |
webmaster@9
|
1339 'avi' => 'video/x-msvideo', |
webmaster@9
|
1340 'movie' => 'video/x-sgi-movie', |
webmaster@9
|
1341 'ice' => 'x-conference/x-cooltalk', |
webmaster@9
|
1342 'sisx' => 'x-epoc/x-sisx-app', |
webmaster@9
|
1343 'vrm|vrml|wrl' => 'x-world/x-vrml', |
webmaster@9
|
1344 'xps' => 'application/vnd.ms-xpsdocument', |
webmaster@9
|
1345 )); |
webmaster@9
|
1346 } |
webmaster@9
|
1347 foreach ($mapping as $ext_preg => $mime_match) { |
webmaster@9
|
1348 if (preg_match('!\.('. $ext_preg .')$!i', $filename)) { |
webmaster@9
|
1349 return $mime_match; |
webmaster@9
|
1350 } |
webmaster@9
|
1351 } |
webmaster@9
|
1352 |
webmaster@9
|
1353 return 'application/octet-stream'; |
webmaster@9
|
1354 } |
webmaster@9
|
1355 |
webmaster@9
|
1356 /** |
webmaster@1
|
1357 * @} End of "defgroup file". |
webmaster@1
|
1358 */ |