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