file.inc

  1. 7.x drupal/includes/file.inc
  2. 5.x drupal/includes/file.inc
  3. 6.x drupal/includes/file.inc
  4. 8.x drupal/core/includes/file.inc

API for handling file uploads and server file management.

Functions

Namesort descending Description
file_check_directory Check that the directory exists and is writable. Directories need to have execute permissions to be considered a directory by FTP servers, etc.
file_check_location Check if a file is really located inside $directory. Should be used to make sure a file specified is really located within the directory to prevent exploits.
file_check_path Checks path to see if it is a directory, or a dir/file.
file_check_upload Verify an uploaded file.
file_copy Copies a file to a new location. This is a powerful function that in many ways performs like an advanced version of copy().
file_create_filename Create a full file path from a directory and filename. If a file with the specified name already exists, an alternative will be used.
file_create_path Make sure the destination is a complete path and resides in the file system directory, if it is not prepend the file system directory.
file_create_url Create the download path to a file.
file_delete Delete a file.
file_directory_path Determine the default 'files' directory.
file_directory_temp Determine the default temporary directory.
file_download
file_get_mimetype Determine an Internet Media Type, or MIME type from a filename.
file_move Moves a file to a new location.
file_save_data Save a string to the specified destination.
file_save_upload Saves a file upload to a new location. The source file is validated as a proper upload and handled as such.
file_scan_directory Finds all files that match a given mask in a given directory. Directories and files beginning with a period are excluded; this prevents hidden files and directories (such as SVN working directories) from being scanned.
file_transfer Transfer file using http to client. Pipes a file through Drupal to the client.
file_upload_max_size Determine the maximum file upload size by querying the PHP settings.

Constants

File

drupal/includes/file.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * API for handling file uploads and server file management.
  5. */
  6. /**
  7. * @defgroup file File interface
  8. * @{
  9. * Common file handling functions.
  10. */
  11. define('FILE_DOWNLOADS_PUBLIC', 1);
  12. define('FILE_DOWNLOADS_PRIVATE', 2);
  13. define('FILE_CREATE_DIRECTORY', 1);
  14. define('FILE_MODIFY_PERMISSIONS', 2);
  15. define('FILE_EXISTS_RENAME', 0);
  16. define('FILE_EXISTS_REPLACE', 1);
  17. define('FILE_EXISTS_ERROR', 2);
  18. /**
  19. * Create the download path to a file.
  20. *
  21. * @param $path A string containing the path of the file to generate URL for.
  22. * @return A string containing a URL that can be used to download the file.
  23. */
  24. function file_create_url($path) {
  25. // Strip file_directory_path from $path. We only include relative paths in urls.
  26. if (strpos($path, file_directory_path() . '/') === 0) {
  27. $path = trim(substr($path, strlen(file_directory_path())), '\\/');
  28. }
  29. switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
  30. case FILE_DOWNLOADS_PUBLIC:
  31. return $GLOBALS['base_url'] .'/'. file_directory_path() .'/'. str_replace('\\', '/', $path);
  32. case FILE_DOWNLOADS_PRIVATE:
  33. return url('system/files/'. $path, NULL, NULL, TRUE);
  34. }
  35. }
  36. /**
  37. * Make sure the destination is a complete path and resides in the file system
  38. * directory, if it is not prepend the file system directory.
  39. *
  40. * @param $dest A string containing the path to verify. If this value is
  41. * omitted, Drupal's 'files' directory will be used.
  42. * @return A string containing the path to file, with file system directory
  43. * appended if necessary, or FALSE if the path is invalid (i.e. outside the
  44. * configured 'files' or temp directories).
  45. */
  46. function file_create_path($dest = 0) {
  47. $file_path = file_directory_path();
  48. if (!$dest) {
  49. return $file_path;
  50. }
  51. // file_check_location() checks whether the destination is inside the Drupal files directory.
  52. if (file_check_location($dest, $file_path)) {
  53. return $dest;
  54. }
  55. // check if the destination is instead inside the Drupal temporary files directory.
  56. else if (file_check_location($dest, file_directory_temp())) {
  57. return $dest;
  58. }
  59. // Not found, try again with prefixed directory path.
  60. else if (file_check_location($file_path . '/' . $dest, $file_path)) {
  61. return $file_path . '/' . $dest;
  62. }
  63. // File not found.
  64. return FALSE;
  65. }
  66. /**
  67. * Check that the directory exists and is writable. Directories need to
  68. * have execute permissions to be considered a directory by FTP servers, etc.
  69. *
  70. * @param $directory A string containing the name of a directory path.
  71. * @param $mode A Boolean value to indicate if the directory should be created
  72. * if it does not exist or made writable if it is read-only.
  73. * @param $form_item An optional string containing the name of a form item that
  74. * any errors will be attached to. This is useful for settings forms that
  75. * require the user to specify a writable directory. If it can't be made to
  76. * work, a form error will be set preventing them from saving the settings.
  77. * @return FALSE when directory not found, or TRUE when directory exists.
  78. */
  79. function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
  80. $directory = rtrim($directory, '/\\');
  81. // Check if directory exists.
  82. if (!is_dir($directory)) {
  83. if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory)) {
  84. drupal_set_message(t('The directory %directory has been created.', array('%directory' => $directory)));
  85. @chmod($directory, 0775); // Necessary for non-webserver users.
  86. }
  87. else {
  88. if ($form_item) {
  89. form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory)));
  90. }
  91. return FALSE;
  92. }
  93. }
  94. // Check to see if the directory is writable.
  95. if (!is_writable($directory)) {
  96. if (($mode & FILE_MODIFY_PERMISSIONS) && @chmod($directory, 0775)) {
  97. drupal_set_message(t('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory)));
  98. }
  99. else {
  100. form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
  101. watchdog('file system', t('The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory)), WATCHDOG_ERROR);
  102. return FALSE;
  103. }
  104. }
  105. if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) {
  106. $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
  107. if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) {
  108. fclose($fp);
  109. chmod($directory .'/.htaccess', 0664);
  110. }
  111. else {
  112. $message = 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>", array('%directory' => $directory, '!htaccess' => '<br />'. nl2br(check_plain($htaccess_lines))));
  113. form_set_error($form_item, $message);
  114. watchdog('security', $message, WATCHDOG_ERROR);
  115. }
  116. }
  117. return TRUE;
  118. }
  119. /**
  120. * Checks path to see if it is a directory, or a dir/file.
  121. *
  122. * @param $path A string containing a file path. This will be set to the
  123. * directory's path.
  124. * @return If the directory is not in a Drupal writable directory, FALSE is
  125. * returned. Otherwise, the base name of the path is returned.
  126. */
  127. function file_check_path(&$path) {
  128. // Check if path is a directory.
  129. if (file_check_directory($path)) {
  130. return '';
  131. }
  132. // Check if path is a possible dir/file.
  133. $filename = basename($path);
  134. $path = dirname($path);
  135. if (file_check_directory($path)) {
  136. return $filename;
  137. }
  138. return FALSE;
  139. }
  140. /**
  141. * Verify an uploaded file.
  142. *
  143. * Check if $source is a valid file upload. If so, move the file to the
  144. * temporary directory and return it as an object.
  145. *
  146. * @param $source
  147. * An upload source (the name of the upload form item), or a file.
  148. * @return
  149. * FALSE for an invalid file or upload. A file object for valid
  150. * uploads/files.
  151. */
  152. function file_check_upload($source = 'upload') {
  153. // Cache for uploaded files. Since the data in _FILES is modified
  154. // by this function, we cache the result.
  155. static $upload_cache;
  156. // Test source to see if it is an object.
  157. if (is_object($source)) {
  158. // Validate the file path if an object was passed in instead of
  159. // an upload key.
  160. if (is_file($source->filepath)) {
  161. return $source;
  162. }
  163. else {
  164. return FALSE;
  165. }
  166. }
  167. // Return cached objects without processing since the file will have
  168. // already been processed and the paths in _FILES will be invalid.
  169. if (isset($upload_cache[$source])) {
  170. return $upload_cache[$source];
  171. }
  172. // If a file was uploaded, process it.
  173. if ($_FILES["files"]["name"][$source] && is_uploaded_file($_FILES["files"]["tmp_name"][$source])) {
  174. // Check for file upload errors and return FALSE if a
  175. // lower level system error occurred.
  176. switch ($_FILES["files"]["error"][$source]) {
  177. // @see http://php.net/manual/en/features.file-upload.errors.php
  178. case UPLOAD_ERR_OK:
  179. break;
  180. case UPLOAD_ERR_INI_SIZE:
  181. case UPLOAD_ERR_FORM_SIZE:
  182. drupal_set_message(t('The file %file could not be saved, because it exceeds the maximum allowed size for uploads.', array('%file' => $source)), 'error');
  183. return 0;
  184. case UPLOAD_ERR_PARTIAL:
  185. case UPLOAD_ERR_NO_FILE:
  186. drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $source)), 'error');
  187. return 0;
  188. // Unknown error
  189. default:
  190. drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)),'error');
  191. return 0;
  192. }
  193. // Begin building file object.
  194. $file = new stdClass();
  195. $file->filename = trim(basename($_FILES["files"]["name"][$source]), '.');
  196. // Create temporary name/path for newly uploaded files. On Windows, tempnam()
  197. // requires an absolute path, so we use realpath().
  198. $file->filepath = tempnam(realpath(file_directory_temp()), 'tmp_');
  199. $file->filemime = file_get_mimetype($file->filename);
  200. // Rename potentially executable files, to help prevent exploits.
  201. if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
  202. $file->filemime = 'text/plain';
  203. $file->filepath .= '.txt';
  204. $file->filename .= '.txt';
  205. }
  206. // Move uploaded files from php's upload_tmp_dir to Drupal's file temp.
  207. // This overcomes open_basedir restrictions for future file operations.
  208. if (!move_uploaded_file($_FILES["files"]["tmp_name"][$source], $file->filepath)) {
  209. drupal_set_message(t('File upload error. Could not move uploaded file.'));
  210. watchdog('file', t('Upload Error. Could not move uploaded file (%file) to destination (%destination).', array('%file' => $_FILES["files"]["tmp_name"][$source], '%destination' => $file->filepath)));
  211. return FALSE;
  212. }
  213. $file->filesize = $_FILES["files"]["size"][$source];
  214. $file->source = $source;
  215. // Add processed file to the cache.
  216. $upload_cache[$source] = $file;
  217. return $file;
  218. }
  219. else {
  220. // In case of previews return previous file object.
  221. if (file_exists($_SESSION['file_uploads'][$source]->filepath)) {
  222. return $_SESSION['file_uploads'][$source];
  223. }
  224. }
  225. // If nothing was done, return FALSE.
  226. return FALSE;
  227. }
  228. /**
  229. * Check if a file is really located inside $directory. Should be used to make
  230. * sure a file specified is really located within the directory to prevent
  231. * exploits.
  232. *
  233. * @code
  234. * // Returns FALSE:
  235. * file_check_location('/www/example.com/files/../../../etc/passwd', '/www/example.com/files');
  236. * @endcode
  237. *
  238. * @param $source A string set to the file to check.
  239. * @param $directory A string where the file should be located.
  240. * @return 0 for invalid path or the real path of the source.
  241. */
  242. function file_check_location($source, $directory = '') {
  243. $check = realpath($source);
  244. if ($check) {
  245. $source = $check;
  246. }
  247. else {
  248. // This file does not yet exist
  249. $source = realpath(dirname($source)) .'/'. basename($source);
  250. }
  251. $directory = realpath($directory);
  252. if ($directory && strpos($source, $directory) !== 0) {
  253. return 0;
  254. }
  255. return $source;
  256. }
  257. /**
  258. * Copies a file to a new location. This is a powerful function that in many ways
  259. * performs like an advanced version of copy().
  260. * - Checks if $source and $dest are valid and readable/writable.
  261. * - Performs a file copy if $source is not equal to $dest.
  262. * - If file already exists in $dest either the call will error out, replace the
  263. * file or rename the file based on the $replace parameter.
  264. *
  265. * @param $source A string specifying the file location of the original file.
  266. * This parameter will contain the resulting destination filename in case of
  267. * success.
  268. * @param $dest A string containing the directory $source should be copied to.
  269. * If this value is omitted, Drupal's 'files' directory will be used.
  270. * @param $replace Replace behavior when the destination file already exists.
  271. * - FILE_EXISTS_REPLACE - Replace the existing file
  272. * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
  273. * - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  274. * @return True for success, FALSE for failure.
  275. */
  276. function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
  277. $dest = file_create_path($dest);
  278. $directory = $dest;
  279. $basename = file_check_path($directory);
  280. // Make sure we at least have a valid directory.
  281. if ($basename === FALSE) {
  282. $source = is_object($source) ? $source->filepath : $source;
  283. 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');
  284. watchdog('file system', t('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);
  285. return 0;
  286. }
  287. // Process a file upload object.
  288. if (is_object($source)) {
  289. $file = $source;
  290. $source = $file->filepath;
  291. if (!$basename) {
  292. $basename = $file->filename;
  293. }
  294. }
  295. $source = realpath($source);
  296. if (!file_exists($source)) {
  297. 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');
  298. return 0;
  299. }
  300. // If the destination file is not specified then use the filename of the source file.
  301. $basename = $basename ? $basename : basename($source);
  302. $dest = $directory .'/'. $basename;
  303. // Make sure source and destination filenames are not the same, makes no sense
  304. // to copy it if they are. In fact copying the file will most likely result in
  305. // a 0 byte file. Which is bad. Real bad.
  306. if ($source != realpath($dest)) {
  307. if (file_exists($dest)) {
  308. switch ($replace) {
  309. case FILE_EXISTS_RENAME:
  310. // Destination file already exists and we can't replace is so we try and
  311. // and find a new filename.
  312. if ($pos = strrpos($basename, '.')) {
  313. $name = substr($basename, 0, $pos);
  314. $ext = substr($basename, $pos);
  315. }
  316. else {
  317. $name = $basename;
  318. }
  319. $counter = 0;
  320. do {
  321. $dest = $directory .'/'. $name .'_'. $counter++ . $ext;
  322. } while (file_exists($dest));
  323. break;
  324. case FILE_EXISTS_ERROR:
  325. 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');
  326. return 0;
  327. }
  328. }
  329. if (!@copy($source, $dest)) {
  330. drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error');
  331. return 0;
  332. }
  333. // Give everyone read access so that FTP'd users or
  334. // non-webserver users can see/read these files.
  335. @chmod($dest, 0664);
  336. }
  337. if (is_object($file)) {
  338. $file->filename = $basename;
  339. $file->filepath = $dest;
  340. $source = $file;
  341. }
  342. else {
  343. $source = $dest;
  344. }
  345. return 1; // Everything went ok.
  346. }
  347. /**
  348. * Moves a file to a new location.
  349. * - Checks if $source and $dest are valid and readable/writable.
  350. * - Performs a file move if $source is not equal to $dest.
  351. * - If file already exists in $dest either the call will error out, replace the
  352. * file or rename the file based on the $replace parameter.
  353. *
  354. * @param $source A string specifying the file location of the original file.
  355. * This parameter will contain the resulting destination filename in case of
  356. * success.
  357. * @param $dest A string containing the directory $source should be copied to.
  358. * If this value is omitted, Drupal's 'files' directory will be used.
  359. * @param $replace Replace behavior when the destination file already exists.
  360. * - FILE_EXISTS_REPLACE - Replace the existing file
  361. * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
  362. * - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  363. * @return True for success, FALSE for failure.
  364. */
  365. function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
  366. $path_original = is_object($source) ? $source->filepath : $source;
  367. if (file_copy($source, $dest, $replace)) {
  368. $path_current = is_object($source) ? $source->filepath : $source;
  369. if ($path_original == $path_current || file_delete($path_original)) {
  370. return 1;
  371. }
  372. drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error');
  373. }
  374. return 0;
  375. }
  376. /**
  377. * Create a full file path from a directory and filename. If a file with the
  378. * specified name already exists, an alternative will be used.
  379. *
  380. * @param $basename string filename
  381. * @param $directory string directory
  382. * @return
  383. */
  384. function file_create_filename($basename, $directory) {
  385. $dest = $directory .'/'. $basename;
  386. if (file_exists($dest)) {
  387. // Destination file already exists, generate an alternative.
  388. if ($pos = strrpos($basename, '.')) {
  389. $name = substr($basename, 0, $pos);
  390. $ext = substr($basename, $pos);
  391. }
  392. else {
  393. $name = $basename;
  394. }
  395. $counter = 0;
  396. do {
  397. $dest = $directory .'/'. $name .'_'. $counter++ . $ext;
  398. } while (file_exists($dest));
  399. }
  400. return $dest;
  401. }
  402. /**
  403. * Delete a file.
  404. *
  405. * @param $path A string containing a file path.
  406. * @return True for success, FALSE for failure.
  407. */
  408. function file_delete($path) {
  409. if (is_file($path)) {
  410. return unlink($path);
  411. }
  412. }
  413. /**
  414. * Saves a file upload to a new location. The source file is validated as a
  415. * proper upload and handled as such.
  416. *
  417. * @param $source A string specifying the name of the upload field to save.
  418. * This parameter will contain the resulting destination filename in case of
  419. * success.
  420. * @param $dest A string containing the directory $source should be copied to,
  421. * will use the temporary directory in case no other value is set.
  422. * @param $replace A boolean, set to TRUE if the destination should be replaced
  423. * when in use, but when FALSE append a _X to the filename.
  424. * @return An object containing file info or 0 in case of error.
  425. */
  426. function file_save_upload($source, $dest = FALSE, $replace = FILE_EXISTS_RENAME) {
  427. // Make sure $source exists && is valid.
  428. if ($file = file_check_upload($source)) {
  429. // This should be refactored, file_check_upload has already
  430. // moved the file to the temporary folder.
  431. if (!$dest) {
  432. $dest = file_directory_temp();
  433. $temporary = 1;
  434. if (is_file($file->filepath)) {
  435. // If this file was uploaded by this user before replace the temporary copy.
  436. $replace = FILE_EXISTS_REPLACE;
  437. }
  438. }
  439. unset($_SESSION['file_uploads'][is_object($source) ? $source->source : $source]);
  440. if (file_move($file, $dest, $replace)) {
  441. if ($temporary) {
  442. $_SESSION['file_uploads'][is_object($source) ? $source->source : $source] = $file;
  443. }
  444. return $file;
  445. }
  446. return 0;
  447. }
  448. return 0;
  449. }
  450. /**
  451. * Save a string to the specified destination.
  452. *
  453. * @param $data A string containing the contents of the file.
  454. * @param $dest A string containing the destination location.
  455. * @param $replace Replace behavior when the destination file already exists.
  456. * - FILE_EXISTS_REPLACE - Replace the existing file
  457. * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
  458. * - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  459. *
  460. * @return A string containing the resulting filename or 0 on error
  461. */
  462. function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) {
  463. $temp = file_directory_temp();
  464. // On Windows, tempnam() requires an absolute path, so we use realpath().
  465. $file = tempnam(realpath($temp), 'file');
  466. if (!$fp = fopen($file, 'wb')) {
  467. drupal_set_message(t('The file could not be created.'), 'error');
  468. return 0;
  469. }
  470. fwrite($fp, $data);
  471. fclose($fp);
  472. if (!file_move($file, $dest, $replace)) {
  473. return 0;
  474. }
  475. return $file;
  476. }
  477. /**
  478. * Transfer file using http to client. Pipes a file through Drupal to the
  479. * client.
  480. *
  481. * @param $source File to transfer.
  482. * @param $headers An array of http headers to send along with file.
  483. */
  484. function file_transfer($source, $headers) {
  485. ob_end_clean();
  486. foreach ($headers as $header) {
  487. // To prevent HTTP header injection, we delete new lines that are
  488. // not followed by a space or a tab.
  489. // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
  490. $header = preg_replace('/\r?\n(?!\t| )/', '', $header);
  491. drupal_set_header($header);
  492. }
  493. $source = file_create_path($source);
  494. // Transfer file in 1024 byte chunks to save memory usage.
  495. if ($fd = fopen($source, 'rb')) {
  496. while (!feof($fd)) {
  497. print fread($fd, 1024);
  498. }
  499. fclose($fd);
  500. }
  501. else {
  502. drupal_not_found();
  503. }
  504. exit();
  505. }
  506. /**
  507. * Call modules that implement hook_file_download() to find out if a file is
  508. * accessible and what headers it should be transferred with. If a module
  509. * returns -1 drupal_access_denied() will be returned. If one or more modules
  510. * returned headers the download will start with the returned headers. If no
  511. * modules respond drupal_not_found() will be returned.
  512. */
  513. function file_download() {
  514. // Merge remainder of arguments from GET['q'], into relative file path.
  515. $args = func_get_args();
  516. $filepath = implode('/', $args);
  517. // Maintain compatibility with old ?file=paths saved in node bodies.
  518. if (isset($_GET['file'])) {
  519. $filepath = $_GET['file'];
  520. }
  521. if (file_exists(file_create_path($filepath))) {
  522. $headers = module_invoke_all('file_download', $filepath);
  523. if (in_array(-1, $headers)) {
  524. return drupal_access_denied();
  525. }
  526. if (count($headers)) {
  527. file_transfer($filepath, $headers);
  528. }
  529. }
  530. return drupal_not_found();
  531. }
  532. /**
  533. * Finds all files that match a given mask in a given directory.
  534. * Directories and files beginning with a period are excluded; this
  535. * prevents hidden files and directories (such as SVN working directories)
  536. * from being scanned.
  537. *
  538. * @param $dir
  539. * The base directory for the scan.
  540. * @param $mask
  541. * The regular expression of the files to find.
  542. * @param $nomask
  543. * An array of files/directories to ignore.
  544. * @param $callback
  545. * The callback function to call for each match.
  546. * @param $recurse
  547. * When TRUE, the directory scan will recurse the entire tree
  548. * starting at the provided directory.
  549. * @param $key
  550. * The key to be used for the returned array of files. Possible
  551. * values are "filename", for the path starting with $dir,
  552. * "basename", for the basename of the file, and "name" for the name
  553. * of the file without an extension.
  554. * @param $min_depth
  555. * Minimum depth of directories to return files from.
  556. * @param $depth
  557. * Current depth of recursion. This parameter is only used internally and should not be passed.
  558. *
  559. * @return
  560. * An associative array (keyed on the provided key) of objects with
  561. * "path", "basename", and "name" members corresponding to the
  562. * matching files.
  563. */
  564. function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename', $min_depth = 0, $depth = 0) {
  565. $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
  566. $files = array();
  567. if (is_dir($dir) && $handle = opendir($dir)) {
  568. while (FALSE !== ($file = readdir($handle))) {
  569. if (!in_array($file, $nomask) && $file[0] != '.') {
  570. if (is_dir("$dir/$file") && $recurse) {
  571. $files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1));
  572. }
  573. elseif ($depth >= $min_depth && ereg($mask, $file)) {
  574. $filename = "$dir/$file";
  575. $basename = basename($file);
  576. $name = substr($basename, 0, strrpos($basename, '.'));
  577. $files[$$key] = new stdClass();
  578. $files[$$key]->filename = $filename;
  579. $files[$$key]->basename = $basename;
  580. $files[$$key]->name = $name;
  581. if ($callback) {
  582. $callback($filename);
  583. }
  584. }
  585. }
  586. }
  587. closedir($handle);
  588. }
  589. return $files;
  590. }
  591. /**
  592. * Determine the default temporary directory.
  593. *
  594. * @return A string containing a temp directory.
  595. */
  596. function file_directory_temp() {
  597. $temporary_directory = variable_get('file_directory_temp', NULL);
  598. if (is_null($temporary_directory)) {
  599. $directories = array();
  600. // Has PHP been set with an upload_tmp_dir?
  601. if (ini_get('upload_tmp_dir')) {
  602. $directories[] = ini_get('upload_tmp_dir');
  603. }
  604. // Operating system specific dirs.
  605. if (substr(PHP_OS, 0, 3) == 'WIN') {
  606. $directories[] = 'c:\\windows\\temp';
  607. $directories[] = 'c:\\winnt\\temp';
  608. $path_delimiter = '\\';
  609. }
  610. else {
  611. $directories[] = '/tmp';
  612. $path_delimiter = '/';
  613. }
  614. foreach ($directories as $directory) {
  615. if (!$temporary_directory && is_dir($directory)) {
  616. $temporary_directory = $directory;
  617. }
  618. }
  619. // if a directory has been found, use it, otherwise default to 'files/tmp' or 'files\\tmp';
  620. $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter . 'tmp';
  621. variable_set('file_directory_temp', $temporary_directory);
  622. }
  623. return $temporary_directory;
  624. }
  625. /**
  626. * Determine the default 'files' directory.
  627. *
  628. * @return A string containing the path to Drupal's 'files' directory.
  629. */
  630. function file_directory_path() {
  631. return variable_get('file_directory_path', 'files');
  632. }
  633. /**
  634. * Determine the maximum file upload size by querying the PHP settings.
  635. *
  636. * @return
  637. * A file size limit in bytes based on the PHP upload_max_filesize and post_max_size
  638. */
  639. function file_upload_max_size() {
  640. static $max_size = -1;
  641. if ($max_size < 0) {
  642. $upload_max = parse_size(ini_get('upload_max_filesize'));
  643. $post_max = parse_size(ini_get('post_max_size'));
  644. $max_size = ($upload_max < $post_max) ? $upload_max : $post_max;
  645. }
  646. return $max_size;
  647. }
  648. /**
  649. * Determine an Internet Media Type, or MIME type from a filename.
  650. *
  651. * @param $filename
  652. * Name of the file, including extension.
  653. * @param $mapping
  654. * An optional array of extension to media type mappings in the form
  655. * 'extension1|extension2|...' => 'type'.
  656. *
  657. * @return
  658. * The internet media type registered for the extension or application/octet-stream for unknown extensions.
  659. */
  660. function file_get_mimetype($filename, $mapping = NULL) {
  661. if (!is_array($mapping)) {
  662. $mapping = variable_get('mime_extension_mapping', array(
  663. 'ez' => 'application/andrew-inset',
  664. 'atom' => 'application/atom',
  665. 'atomcat' => 'application/atomcat+xml',
  666. 'atomsrv' => 'application/atomserv+xml',
  667. 'cap|pcap' => 'application/cap',
  668. 'cu' => 'application/cu-seeme',
  669. 'tsp' => 'application/dsptype',
  670. 'spl' => 'application/x-futuresplash',
  671. 'hta' => 'application/hta',
  672. 'jar' => 'application/java-archive',
  673. 'ser' => 'application/java-serialized-object',
  674. 'class' => 'application/java-vm',
  675. 'hqx' => 'application/mac-binhex40',
  676. 'cpt' => 'image/x-corelphotopaint',
  677. 'nb' => 'application/mathematica',
  678. 'mdb' => 'application/msaccess',
  679. 'doc|dot' => 'application/msword',
  680. 'bin' => 'application/octet-stream',
  681. 'oda' => 'application/oda',
  682. 'ogg|ogx' => 'application/ogg',
  683. 'pdf' => 'application/pdf',
  684. 'key' => 'application/pgp-keys',
  685. 'pgp' => 'application/pgp-signature',
  686. 'prf' => 'application/pics-rules',
  687. 'ps|ai|eps' => 'application/postscript',
  688. 'rar' => 'application/rar',
  689. 'rdf' => 'application/rdf+xml',
  690. 'rss' => 'application/rss+xml',
  691. 'rtf' => 'application/rtf',
  692. 'smi|smil' => 'application/smil',
  693. 'wpd' => 'application/wordperfect',
  694. 'wp5' => 'application/wordperfect5.1',
  695. 'xhtml|xht' => 'application/xhtml+xml',
  696. 'xml|xsl' => 'application/xml',
  697. 'zip' => 'application/zip',
  698. 'cdy' => 'application/vnd.cinderella',
  699. 'kml' => 'application/vnd.google-earth.kml+xml',
  700. 'kmz' => 'application/vnd.google-earth.kmz',
  701. 'xul' => 'application/vnd.mozilla.xul+xml',
  702. 'xls|xlb|xlt' => 'application/vnd.ms-excel',
  703. 'cat' => 'application/vnd.ms-pki.seccat',
  704. 'stl' => 'application/vnd.ms-pki.stl',
  705. 'ppt|pps' => 'application/vnd.ms-powerpoint',
  706. 'odc' => 'application/vnd.oasis.opendocument.chart',
  707. 'odb' => 'application/vnd.oasis.opendocument.database',
  708. 'odf' => 'application/vnd.oasis.opendocument.formula',
  709. 'odg' => 'application/vnd.oasis.opendocument.graphics',
  710. 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
  711. 'odi' => 'application/vnd.oasis.opendocument.image',
  712. 'odp' => 'application/vnd.oasis.opendocument.presentation',
  713. 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
  714. 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
  715. 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
  716. 'odt' => 'application/vnd.oasis.opendocument.text',
  717. 'odm' => 'application/vnd.oasis.opendocument.text-master',
  718. 'ott' => 'application/vnd.oasis.opendocument.text-template',
  719. 'oth' => 'application/vnd.oasis.opendocument.text-web',
  720. 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
  721. 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  722. 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
  723. 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  724. 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
  725. 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
  726. 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
  727. 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
  728. 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  729. 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
  730. 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  731. 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
  732. 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
  733. 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
  734. 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  735. 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
  736. 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  737. 'cod' => 'application/vnd.rim.cod',
  738. 'mmf' => 'application/vnd.smaf',
  739. 'sdc' => 'application/vnd.stardivision.calc',
  740. 'sds' => 'application/vnd.stardivision.chart',
  741. 'sda' => 'application/vnd.stardivision.draw',
  742. 'sdd' => 'application/vnd.stardivision.impress',
  743. 'sdf' => 'application/vnd.stardivision.math',
  744. 'sdw' => 'application/vnd.stardivision.writer',
  745. 'sgl' => 'application/vnd.stardivision.writer-global',
  746. 'sxc' => 'application/vnd.sun.xml.calc',
  747. 'stc' => 'application/vnd.sun.xml.calc.template',
  748. 'sxd' => 'application/vnd.sun.xml.draw',
  749. 'std' => 'application/vnd.sun.xml.draw.template',
  750. 'sxi' => 'application/vnd.sun.xml.impress',
  751. 'sti' => 'application/vnd.sun.xml.impress.template',
  752. 'sxm' => 'application/vnd.sun.xml.math',
  753. 'sxw' => 'application/vnd.sun.xml.writer',
  754. 'sxg' => 'application/vnd.sun.xml.writer.global',
  755. 'stw' => 'application/vnd.sun.xml.writer.template',
  756. 'sis' => 'application/vnd.symbian.install',
  757. 'vsd' => 'application/vnd.visio',
  758. 'wbxml' => 'application/vnd.wap.wbxml',
  759. 'wmlc' => 'application/vnd.wap.wmlc',
  760. 'wmlsc' => 'application/vnd.wap.wmlscriptc',
  761. 'wk' => 'application/x-123',
  762. '7z' => 'application/x-7z-compressed',
  763. 'abw' => 'application/x-abiword',
  764. 'dmg' => 'application/x-apple-diskimage',
  765. 'bcpio' => 'application/x-bcpio',
  766. 'torrent' => 'application/x-bittorrent',
  767. 'cab' => 'application/x-cab',
  768. 'cbr' => 'application/x-cbr',
  769. 'cbz' => 'application/x-cbz',
  770. 'cdf' => 'application/x-cdf',
  771. 'vcd' => 'application/x-cdlink',
  772. 'pgn' => 'application/x-chess-pgn',
  773. 'cpio' => 'application/x-cpio',
  774. 'csh' => 'text/x-csh',
  775. 'deb|udeb' => 'application/x-debian-package',
  776. 'dcr|dir|dxr' => 'application/x-director',
  777. 'dms' => 'application/x-dms',
  778. 'wad' => 'application/x-doom',
  779. 'dvi' => 'application/x-dvi',
  780. 'rhtml' => 'application/x-httpd-eruby',
  781. 'flac' => 'application/x-flac',
  782. 'pfa|pfb|gsf|pcf|pcf.Z' => 'application/x-font',
  783. 'mm' => 'application/x-freemind',
  784. 'gnumeric' => 'application/x-gnumeric',
  785. 'sgf' => 'application/x-go-sgf',
  786. 'gcf' => 'application/x-graphing-calculator',
  787. 'gtar|tgz|taz' => 'application/x-gtar',
  788. 'hdf' => 'application/x-hdf',
  789. 'phtml|pht|php' => 'application/x-httpd-php',
  790. 'phps' => 'application/x-httpd-php-source',
  791. 'php3' => 'application/x-httpd-php3',
  792. 'php3p' => 'application/x-httpd-php3-preprocessed',
  793. 'php4' => 'application/x-httpd-php4',
  794. 'ica' => 'application/x-ica',
  795. 'ins|isp' => 'application/x-internet-signup',
  796. 'iii' => 'application/x-iphone',
  797. 'iso' => 'application/x-iso9660-image',
  798. 'jnlp' => 'application/x-java-jnlp-file',
  799. 'js' => 'application/x-javascript',
  800. 'jmz' => 'application/x-jmol',
  801. 'chrt' => 'application/x-kchart',
  802. 'kil' => 'application/x-killustrator',
  803. 'skp|skd|skt|skm' => 'application/x-koan',
  804. 'kpr|kpt' => 'application/x-kpresenter',
  805. 'ksp' => 'application/x-kspread',
  806. 'kwd|kwt' => 'application/x-kword',
  807. 'latex' => 'application/x-latex',
  808. 'lha' => 'application/x-lha',
  809. 'lyx' => 'application/x-lyx',
  810. 'lzh' => 'application/x-lzh',
  811. 'lzx' => 'application/x-lzx',
  812. 'frm|maker|frame|fm|fb|book|fbdoc' => 'application/x-maker',
  813. 'mif' => 'application/x-mif',
  814. 'wmd' => 'application/x-ms-wmd',
  815. 'wmz' => 'application/x-ms-wmz',
  816. 'com|exe|bat|dll' => 'application/x-msdos-program',
  817. 'msi' => 'application/x-msi',
  818. 'nc' => 'application/x-netcdf',
  819. 'pac' => 'application/x-ns-proxy-autoconfig',
  820. 'nwc' => 'application/x-nwc',
  821. 'o' => 'application/x-object',
  822. 'oza' => 'application/x-oz-application',
  823. 'p7r' => 'application/x-pkcs7-certreqresp',
  824. 'crl' => 'application/x-pkcs7-crl',
  825. 'pyc|pyo' => 'application/x-python-code',
  826. 'qtl' => 'application/x-quicktimeplayer',
  827. 'rpm' => 'application/x-redhat-package-manager',
  828. 'sh' => 'text/x-sh',
  829. 'shar' => 'application/x-shar',
  830. 'swf|swfl' => 'application/x-shockwave-flash',
  831. 'sit|sitx' => 'application/x-stuffit',
  832. 'sv4cpio' => 'application/x-sv4cpio',
  833. 'sv4crc' => 'application/x-sv4crc',
  834. 'tar' => 'application/x-tar',
  835. 'tcl' => 'application/x-tcl',
  836. 'gf' => 'application/x-tex-gf',
  837. 'pk' => 'application/x-tex-pk',
  838. 'texinfo|texi' => 'application/x-texinfo',
  839. '~|%|bak|old|sik' => 'application/x-trash',
  840. 't|tr|roff' => 'application/x-troff',
  841. 'man' => 'application/x-troff-man',
  842. 'me' => 'application/x-troff-me',
  843. 'ms' => 'application/x-troff-ms',
  844. 'ustar' => 'application/x-ustar',
  845. 'src' => 'application/x-wais-source',
  846. 'wz' => 'application/x-wingz',
  847. 'crt' => 'application/x-x509-ca-cert',
  848. 'xcf' => 'application/x-xcf',
  849. 'fig' => 'application/x-xfig',
  850. 'xpi' => 'application/x-xpinstall',
  851. 'au|snd' => 'audio/basic',
  852. 'mid|midi|kar' => 'audio/midi',
  853. 'mpga|mpega|mp2|mp3|m4a' => 'audio/mpeg',
  854. 'm3u' => 'audio/x-mpegurl',
  855. 'oga|spx' => 'audio/ogg',
  856. 'sid' => 'audio/prs.sid',
  857. 'aif|aiff|aifc' => 'audio/x-aiff',
  858. 'gsm' => 'audio/x-gsm',
  859. 'wma' => 'audio/x-ms-wma',
  860. 'wax' => 'audio/x-ms-wax',
  861. 'ra|rm|ram' => 'audio/x-pn-realaudio',
  862. 'ra' => 'audio/x-realaudio',
  863. 'pls' => 'audio/x-scpls',
  864. 'sd2' => 'audio/x-sd2',
  865. 'wav' => 'audio/x-wav',
  866. 'alc' => 'chemical/x-alchemy',
  867. 'cac|cache' => 'chemical/x-cache',
  868. 'csf' => 'chemical/x-cache-csf',
  869. 'cbin|cascii|ctab' => 'chemical/x-cactvs-binary',
  870. 'cdx' => 'chemical/x-cdx',
  871. 'cer' => 'chemical/x-cerius',
  872. 'c3d' => 'chemical/x-chem3d',
  873. 'chm' => 'chemical/x-chemdraw',
  874. 'cif' => 'chemical/x-cif',
  875. 'cmdf' => 'chemical/x-cmdf',
  876. 'cml' => 'chemical/x-cml',
  877. 'cpa' => 'chemical/x-compass',
  878. 'bsd' => 'chemical/x-crossfire',
  879. 'csml|csm' => 'chemical/x-csml',
  880. 'ctx' => 'chemical/x-ctx',
  881. 'cxf|cef' => 'chemical/x-cxf',
  882. 'emb|embl' => 'chemical/x-embl-dl-nucleotide',
  883. 'spc' => 'chemical/x-galactic-spc',
  884. 'inp|gam|gamin' => 'chemical/x-gamess-input',
  885. 'fch|fchk' => 'chemical/x-gaussian-checkpoint',
  886. 'cub' => 'chemical/x-gaussian-cube',
  887. 'gau|gjc|gjf' => 'chemical/x-gaussian-input',
  888. 'gal' => 'chemical/x-gaussian-log',
  889. 'gcg' => 'chemical/x-gcg8-sequence',
  890. 'gen' => 'chemical/x-genbank',
  891. 'hin' => 'chemical/x-hin',
  892. 'istr|ist' => 'chemical/x-isostar',
  893. 'jdx|dx' => 'chemical/x-jcamp-dx',
  894. 'kin' => 'chemical/x-kinemage',
  895. 'mcm' => 'chemical/x-macmolecule',
  896. 'mmd|mmod' => 'chemical/x-macromodel-input',
  897. 'mol' => 'chemical/x-mdl-molfile',
  898. 'rd' => 'chemical/x-mdl-rdfile',
  899. 'rxn' => 'chemical/x-mdl-rxnfile',
  900. 'sd|sdf' => 'chemical/x-mdl-sdfile',
  901. 'tgf' => 'chemical/x-mdl-tgf',
  902. 'mcif' => 'chemical/x-mmcif',
  903. 'mol2' => 'chemical/x-mol2',
  904. 'b' => 'chemical/x-molconn-Z',
  905. 'gpt' => 'chemical/x-mopac-graph',
  906. 'mop|mopcrt|mpc|dat|zmt' => 'chemical/x-mopac-input',
  907. 'moo' => 'chemical/x-mopac-out',
  908. 'mvb' => 'chemical/x-mopac-vib',
  909. 'asn' => 'chemical/x-ncbi-asn1-spec',
  910. 'prt|ent' => 'chemical/x-ncbi-asn1-ascii',
  911. 'val|aso' => 'chemical/x-ncbi-asn1-binary',
  912. 'pdb|ent' => 'chemical/x-pdb',
  913. 'ros' => 'chemical/x-rosdal',
  914. 'sw' => 'chemical/x-swissprot',
  915. 'vms' => 'chemical/x-vamas-iso14976',
  916. 'vmd' => 'chemical/x-vmd',
  917. 'xtel' => 'chemical/x-xtel',
  918. 'xyz' => 'chemical/x-xyz',
  919. 'gif' => 'image/gif',
  920. 'ief' => 'image/ief',
  921. 'jpeg|jpg|jpe' => 'image/jpeg',
  922. 'pcx' => 'image/pcx',
  923. 'png' => 'image/png',
  924. 'svg|svgz' => 'image/svg+xml',
  925. 'tiff|tif' => 'image/tiff',
  926. 'djvu|djv' => 'image/vnd.djvu',
  927. 'wbmp' => 'image/vnd.wap.wbmp',
  928. 'ras' => 'image/x-cmu-raster',
  929. 'cdr' => 'image/x-coreldraw',
  930. 'pat' => 'image/x-coreldrawpattern',
  931. 'cdt' => 'image/x-coreldrawtemplate',
  932. 'ico' => 'image/x-icon',
  933. 'art' => 'image/x-jg',
  934. 'jng' => 'image/x-jng',
  935. 'bmp' => 'image/x-ms-bmp',
  936. 'psd' => 'image/x-photoshop',
  937. 'pnm' => 'image/x-portable-anymap',
  938. 'pbm' => 'image/x-portable-bitmap',
  939. 'pgm' => 'image/x-portable-graymap',
  940. 'ppm' => 'image/x-portable-pixmap',
  941. 'rgb' => 'image/x-rgb',
  942. 'xbm' => 'image/x-xbitmap',
  943. 'xpm' => 'image/x-xpixmap',
  944. 'xwd' => 'image/x-xwindowdump',
  945. 'eml' => 'message/rfc822',
  946. 'igs|iges' => 'model/iges',
  947. 'msh|mesh|silo' => 'model/mesh',
  948. 'wrl|vrml' => 'model/vrml',
  949. 'ics|icz' => 'text/calendar',
  950. 'css' => 'text/css',
  951. 'csv' => 'text/csv',
  952. '323' => 'text/h323',
  953. 'html|htm|shtml' => 'text/html',
  954. 'uls' => 'text/iuls',
  955. 'mml' => 'text/mathml',
  956. 'asc|txt|text|pot' => 'text/plain',
  957. 'rtx' => 'text/richtext',
  958. 'sct|wsc' => 'text/scriptlet',
  959. 'tm|ts' => 'text/texmacs',
  960. 'tsv' => 'text/tab-separated-values',
  961. 'jad' => 'text/vnd.sun.j2me.app-descriptor',
  962. 'wml' => 'text/vnd.wap.wml',
  963. 'wmls' => 'text/vnd.wap.wmlscript',
  964. 'bib' => 'text/x-bibtex',
  965. 'boo' => 'text/x-boo',
  966. 'h++|hpp|hxx|hh' => 'text/x-c++hdr',
  967. 'c++|cpp|cxx|cc' => 'text/x-c++src',
  968. 'h' => 'text/x-chdr',
  969. 'htc' => 'text/x-component',
  970. 'c' => 'text/x-csrc',
  971. 'd' => 'text/x-dsrc',
  972. 'diff|patch' => 'text/x-diff',
  973. 'hs' => 'text/x-haskell',
  974. 'java' => 'text/x-java',
  975. 'lhs' => 'text/x-literate-haskell',
  976. 'moc' => 'text/x-moc',
  977. 'p|pas' => 'text/x-pascal',
  978. 'gcd' => 'text/x-pcs-gcd',
  979. 'pl|pm' => 'text/x-perl',
  980. 'py' => 'text/x-python',
  981. 'etx' => 'text/x-setext',
  982. 'tcl|tk' => 'text/x-tcl',
  983. 'tex|ltx|sty|cls' => 'text/x-tex',
  984. 'vcs' => 'text/x-vcalendar',
  985. 'vcf' => 'text/x-vcard',
  986. '3gp' => 'video/3gpp',
  987. 'dl' => 'video/dl',
  988. 'dif|dv' => 'video/dv',
  989. 'fli' => 'video/fli',
  990. 'gl' => 'video/gl',
  991. 'mpeg|mpg|mpe' => 'video/mpeg',
  992. 'mp4' => 'video/mp4',
  993. 'ogv' => 'video/ogg',
  994. 'qt|mov' => 'video/quicktime',
  995. 'mxu' => 'video/vnd.mpegurl',
  996. 'lsf|lsx' => 'video/x-la-asf',
  997. 'mng' => 'video/x-mng',
  998. 'asf|asx' => 'video/x-ms-asf',
  999. 'wm' => 'video/x-ms-wm',
  1000. 'wmv' => 'video/x-ms-wmv',
  1001. 'wmx' => 'video/x-ms-wmx',
  1002. 'wvx' => 'video/x-ms-wvx',
  1003. 'avi' => 'video/x-msvideo',
  1004. 'movie' => 'video/x-sgi-movie',
  1005. 'ice' => 'x-conference/x-cooltalk',
  1006. 'sisx' => 'x-epoc/x-sisx-app',
  1007. 'vrm|vrml|wrl' => 'x-world/x-vrml',
  1008. 'xps' => 'application/vnd.ms-xpsdocument',
  1009. ));
  1010. }
  1011. foreach ($mapping as $ext_preg => $mime_match) {
  1012. if (preg_match('!\.('. $ext_preg .')$!i', $filename)) {
  1013. return $mime_match;
  1014. }
  1015. }
  1016. return 'application/octet-stream';
  1017. }