00001 <?php
00002
00003
00021 define('FILE_DOWNLOADS_PUBLIC', 1);
00022
00029 define('FILE_DOWNLOADS_PRIVATE', 2);
00030
00034 define('FILE_CREATE_DIRECTORY', 1);
00035
00039 define('FILE_MODIFY_PERMISSIONS', 2);
00040
00044 define('FILE_EXISTS_RENAME', 0);
00045
00049 define('FILE_EXISTS_REPLACE', 1);
00050
00054 define('FILE_EXISTS_ERROR', 2);
00055
00062 define('FILE_STATUS_TEMPORARY', 0);
00063
00071 define('FILE_STATUS_PERMANENT', 1);
00072
00079 function file_create_url($path) {
00080
00081 if (strpos($path, file_directory_path() . '/') === 0) {
00082 $path = trim(substr($path, strlen(file_directory_path())), '\\/');
00083 }
00084 switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
00085 case FILE_DOWNLOADS_PUBLIC:
00086 return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $path);
00087 case FILE_DOWNLOADS_PRIVATE:
00088 return url('system/files/' . $path, array('absolute' => TRUE));
00089 }
00090 }
00091
00102 function file_create_path($dest = 0) {
00103 $file_path = file_directory_path();
00104 if (!$dest) {
00105 return $file_path;
00106 }
00107
00108 if (file_check_location($dest, $file_path)) {
00109 return $dest;
00110 }
00111
00112 else if (file_check_location($dest, file_directory_temp())) {
00113 return $dest;
00114 }
00115
00116 else if (file_check_location($file_path . '/' . $dest, $file_path)) {
00117 return $file_path . '/' . $dest;
00118 }
00119
00120 return FALSE;
00121 }
00122
00136 function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
00137 $directory = rtrim($directory, '/\\');
00138
00139
00140 if (!is_dir($directory)) {
00141 if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory)) {
00142 drupal_set_message(t('The directory %directory has been created.', array('%directory' => $directory)));
00143 @chmod($directory, 0775);
00144 }
00145 else {
00146 if ($form_item) {
00147 form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory)));
00148 }
00149 return FALSE;
00150 }
00151 }
00152
00153
00154 if (!is_writable($directory)) {
00155 if (($mode & FILE_MODIFY_PERMISSIONS) && @chmod($directory, 0775)) {
00156 drupal_set_message(t('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory)));
00157 }
00158 else {
00159 form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
00160 watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR);
00161 return FALSE;
00162 }
00163 }
00164
00165 if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) {
00166 $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
00167 if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) {
00168 fclose($fp);
00169 chmod($directory . '/.htaccess', 0664);
00170 }
00171 else {
00172 $variables = array('%directory' => $directory, '!htaccess' => '<br />' . nl2br(check_plain($htaccess_lines)));
00173 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));
00174 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);
00175 }
00176 }
00177
00178 return TRUE;
00179 }
00180
00189 function file_check_path(&$path) {
00190
00191 if (file_check_directory($path)) {
00192 return '';
00193 }
00194
00195
00196 $filename = basename($path);
00197 $path = dirname($path);
00198 if (file_check_directory($path)) {
00199 return $filename;
00200 }
00201
00202 return FALSE;
00203 }
00204
00219 function file_check_location($source, $directory = '') {
00220 $check = realpath($source);
00221 if ($check) {
00222 $source = $check;
00223 }
00224 else {
00225
00226 $source = realpath(dirname($source)) . '/' . basename($source);
00227 }
00228 $directory = realpath($directory);
00229 if ($directory && strpos($source, $directory) !== 0) {
00230 return 0;
00231 }
00232 return $source;
00233 }
00234
00254 function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
00255 $dest = file_create_path($dest);
00256
00257 $directory = $dest;
00258 $basename = file_check_path($directory);
00259
00260
00261 if ($basename === FALSE) {
00262 $source = is_object($source) ? $source->filepath : $source;
00263 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');
00264 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);
00265 return 0;
00266 }
00267
00268
00269 if (is_object($source)) {
00270 $file = $source;
00271 $source = $file->filepath;
00272 if (!$basename) {
00273 $basename = $file->filename;
00274 }
00275 }
00276
00277 $source = realpath($source);
00278 if (!file_exists($source)) {
00279 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');
00280 return 0;
00281 }
00282
00283
00284 $basename = $basename ? $basename : basename($source);
00285 $dest = $directory . '/' . $basename;
00286
00287
00288
00289
00290 if ($source != realpath($dest)) {
00291 if (!$dest = file_destination($dest, $replace)) {
00292 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');
00293 return FALSE;
00294 }
00295
00296 if (!@copy($source, $dest)) {
00297 drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error');
00298 return 0;
00299 }
00300
00301
00302
00303
00304
00305 @chmod($dest, 0664);
00306 }
00307
00308 if (isset($file) && is_object($file)) {
00309 $file->filename = $basename;
00310 $file->filepath = $dest;
00311 $source = $file;
00312 }
00313 else {
00314 $source = $dest;
00315 }
00316
00317 return 1;
00318 }
00319
00333 function file_destination($destination, $replace) {
00334 if (file_exists($destination)) {
00335 switch ($replace) {
00336 case FILE_EXISTS_RENAME:
00337 $basename = basename($destination);
00338 $directory = dirname($destination);
00339 $destination = file_create_filename($basename, $directory);
00340 break;
00341
00342 case FILE_EXISTS_ERROR:
00343 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');
00344 return FALSE;
00345 }
00346 }
00347 return $destination;
00348 }
00349
00368 function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
00369 $path_original = is_object($source) ? $source->filepath : $source;
00370
00371 if (file_copy($source, $dest, $replace)) {
00372 $path_current = is_object($source) ? $source->filepath : $source;
00373
00374 if ($path_original == $path_current || file_delete($path_original)) {
00375 return 1;
00376 }
00377 drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error');
00378 }
00379 return 0;
00380 }
00381
00393 function file_munge_filename($filename, $extensions, $alerts = TRUE) {
00394 $original = $filename;
00395
00396
00397 if (!variable_get('allow_insecure_uploads', 0)) {
00398 $whitelist = array_unique(explode(' ', trim($extensions)));
00399
00400
00401
00402 $filename_parts = explode('.', $filename);
00403 $new_filename = array_shift($filename_parts);
00404 $final_extension = array_pop($filename_parts);
00405
00406
00407
00408
00409 foreach ($filename_parts as $filename_part) {
00410 $new_filename .= '.' . $filename_part;
00411 if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
00412 $new_filename .= '_';
00413 }
00414 }
00415 $filename = $new_filename . '.' . $final_extension;
00416
00417 if ($alerts && $original != $filename) {
00418 drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $filename)));
00419 }
00420 }
00421
00422 return $filename;
00423 }
00424
00431 function file_unmunge_filename($filename) {
00432 return str_replace('_.', '.', $filename);
00433 }
00434
00443 function file_create_filename($basename, $directory) {
00444 $dest = $directory . '/' . $basename;
00445
00446 if (file_exists($dest)) {
00447
00448 if ($pos = strrpos($basename, '.')) {
00449 $name = substr($basename, 0, $pos);
00450 $ext = substr($basename, $pos);
00451 }
00452 else {
00453 $name = $basename;
00454 }
00455
00456 $counter = 0;
00457 do {
00458 $dest = $directory . '/' . $name . '_' . $counter++ . $ext;
00459 } while (file_exists($dest));
00460 }
00461
00462 return $dest;
00463 }
00464
00471 function file_delete($path) {
00472 if (is_file($path)) {
00473 return unlink($path);
00474 }
00475 }
00476
00484 function file_space_used($uid = NULL) {
00485 if (isset($uid)) {
00486 return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid));
00487 }
00488 return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}'));
00489 }
00490
00518 function file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME) {
00519 global $user;
00520 static $upload_cache;
00521
00522
00523 $validators['file_validate_name_length'] = array();
00524
00525
00526
00527 if (isset($upload_cache[$source])) {
00528 return $upload_cache[$source];
00529 }
00530
00531
00532 if (isset($_FILES['files']) && $_FILES['files']['name'][$source] && is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
00533
00534
00535 switch ($_FILES['files']['error'][$source]) {
00536
00537 case UPLOAD_ERR_OK:
00538 break;
00539
00540 case UPLOAD_ERR_INI_SIZE:
00541 case UPLOAD_ERR_FORM_SIZE:
00542 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');
00543 return 0;
00544
00545 case UPLOAD_ERR_PARTIAL:
00546 case UPLOAD_ERR_NO_FILE:
00547 drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $source)), 'error');
00548 return 0;
00549
00550
00551 default:
00552 drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)), 'error');
00553 return 0;
00554 }
00555
00556
00557
00558 $extensions = '';
00559 foreach ($user->roles as $rid => $name) {
00560 $extensions .= ' ' . variable_get("upload_extensions_$rid",
00561 variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
00562 }
00563
00564
00565 $file = new stdClass();
00566 $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
00567 $file->filepath = $_FILES['files']['tmp_name'][$source];
00568 $file->filemime = $_FILES['files']['type'][$source];
00569
00570
00571 if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
00572 $file->filemime = 'text/plain';
00573 $file->filepath .= '.txt';
00574 $file->filename .= '.txt';
00575 }
00576
00577
00578
00579 if (empty($dest) || file_check_path($dest) === FALSE) {
00580 $dest = file_directory_temp();
00581 }
00582
00583 $file->source = $source;
00584 $file->destination = file_destination(file_create_path($dest . '/' . $file->filename), $replace);
00585 $file->filesize = $_FILES['files']['size'][$source];
00586
00587
00588 $errors = array();
00589 foreach ($validators as $function => $args) {
00590 array_unshift($args, $file);
00591 $errors = array_merge($errors, call_user_func_array($function, $args));
00592 }
00593
00594
00595 if (!empty($errors)) {
00596 $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename));
00597 if (count($errors) > 1) {
00598 $message .= '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
00599 }
00600 else {
00601 $message .= ' ' . array_pop($errors);
00602 }
00603 form_set_error($source, $message);
00604 return 0;
00605 }
00606
00607
00608
00609 $file->filepath = $file->destination;
00610 if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) {
00611 form_set_error($source, t('File upload error. Could not move uploaded file.'));
00612 watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->filepath));
00613 return 0;
00614 }
00615
00616
00617 $file->uid = $user->uid;
00618 $file->status = FILE_STATUS_TEMPORARY;
00619 $file->timestamp = time();
00620 drupal_write_record('files', $file);
00621
00622
00623 $upload_cache[$source] = $file;
00624 return $file;
00625 }
00626 return 0;
00627 }
00628
00637 function file_validate_name_length($file) {
00638 $errors = array();
00639
00640 if (strlen($file->filename) > 255) {
00641 $errors[] = t('Its name exceeds the 255 characters limit. Please rename the file and try again.');
00642 }
00643 return $errors;
00644 }
00645
00657 function file_validate_extensions($file, $extensions) {
00658 global $user;
00659
00660 $errors = array();
00661
00662
00663 if ($user->uid != 1) {
00664 $regex = '/\.(' . ereg_replace(' +', '|', preg_quote($extensions)) . ')$/i';
00665 if (!preg_match($regex, $file->filename)) {
00666 $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions));
00667 }
00668 }
00669 return $errors;
00670 }
00671
00687 function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
00688 global $user;
00689
00690 $errors = array();
00691
00692
00693 if ($user->uid != 1) {
00694 if ($file_limit && $file->filesize > $file_limit) {
00695 $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
00696 }
00697
00698 $total_size = file_space_used($user->uid) + $file->filesize;
00699 if ($user_limit && $total_size > $user_limit) {
00700 $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)));
00701 }
00702 }
00703 return $errors;
00704 }
00705
00714 function file_validate_is_image(&$file) {
00715 $errors = array();
00716
00717 $info = image_get_info($file->filepath);
00718 if (!$info || empty($info['extension'])) {
00719 $errors[] = t('Only JPEG, PNG and GIF images are allowed.');
00720 }
00721
00722 return $errors;
00723 }
00724
00743 function file_validate_image_resolution(&$file, $maximum_dimensions = 0, $minimum_dimensions = 0) {
00744 $errors = array();
00745
00746
00747 if ($info = image_get_info($file->filepath)) {
00748 if ($maximum_dimensions) {
00749
00750 list($width, $height) = explode('x', $maximum_dimensions);
00751 if ($info['width'] > $width || $info['height'] > $height) {
00752
00753 if (image_get_toolkit() && image_scale($file->filepath, $file->filepath, $width, $height)) {
00754 drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions)));
00755
00756
00757 clearstatcache();
00758 $info = image_get_info($file->filepath);
00759 $file->filesize = $info['file_size'];
00760 }
00761 else {
00762 $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions));
00763 }
00764 }
00765 }
00766
00767 if ($minimum_dimensions) {
00768
00769 list($width, $height) = explode('x', $minimum_dimensions);
00770 if ($info['width'] < $width || $info['height'] < $height) {
00771 $errors[] = t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => $minimum_dimensions));
00772 }
00773 }
00774 }
00775
00776 return $errors;
00777 }
00778
00791 function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) {
00792 $temp = file_directory_temp();
00793
00794 $file = tempnam(realpath($temp), 'file');
00795 if (!$fp = fopen($file, 'wb')) {
00796 drupal_set_message(t('The file could not be created.'), 'error');
00797 return 0;
00798 }
00799 fwrite($fp, $data);
00800 fclose($fp);
00801
00802 if (!file_move($file, $dest, $replace)) {
00803 return 0;
00804 }
00805
00806 return $file;
00807 }
00808
00817 function file_set_status(&$file, $status) {
00818 if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) {
00819 $file->status = $status;
00820 return TRUE;
00821 }
00822 return FALSE;
00823 }
00824
00832 function file_transfer($source, $headers) {
00833 ob_end_clean();
00834
00835 foreach ($headers as $header) {
00836
00837
00838
00839 $header = preg_replace('/\r?\n(?!\t| )/', '', $header);
00840 drupal_set_header($header);
00841 }
00842
00843 $source = file_create_path($source);
00844
00845
00846 if ($fd = fopen($source, 'rb')) {
00847 while (!feof($fd)) {
00848 print fread($fd, 1024);
00849 }
00850 fclose($fd);
00851 }
00852 else {
00853 drupal_not_found();
00854 }
00855 exit();
00856 }
00857
00865 function file_download() {
00866
00867 $args = func_get_args();
00868 $filepath = implode('/', $args);
00869
00870
00871 if (isset($_GET['file'])) {
00872 $filepath = $_GET['file'];
00873 }
00874
00875 if (file_exists(file_create_path($filepath))) {
00876 $headers = module_invoke_all('file_download', $filepath);
00877 if (in_array(-1, $headers)) {
00878 return drupal_access_denied();
00879 }
00880 if (count($headers)) {
00881 file_transfer($filepath, $headers);
00882 }
00883 }
00884 return drupal_not_found();
00885 }
00886
00887
00920 function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename', $min_depth = 0, $depth = 0) {
00921 $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
00922 $files = array();
00923
00924 if (is_dir($dir) && $handle = opendir($dir)) {
00925 while (false !== ($file = readdir($handle))) {
00926 if (!in_array($file, $nomask) && $file[0] != '.') {
00927 if (is_dir("$dir/$file") && $recurse) {
00928
00929 $files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files);
00930 }
00931 elseif ($depth >= $min_depth && ereg($mask, $file)) {
00932
00933 $filename = "$dir/$file";
00934 $basename = basename($file);
00935 $name = substr($basename, 0, strrpos($basename, '.'));
00936 $files[$$key] = new stdClass();
00937 $files[$$key]->filename = $filename;
00938 $files[$$key]->basename = $basename;
00939 $files[$$key]->name = $name;
00940 if ($callback) {
00941 $callback($filename);
00942 }
00943 }
00944 }
00945 }
00946
00947 closedir($handle);
00948 }
00949
00950 return $files;
00951 }
00952
00958 function file_directory_temp() {
00959 $temporary_directory = variable_get('file_directory_temp', NULL);
00960
00961 if (is_null($temporary_directory)) {
00962 $directories = array();
00963
00964
00965 if (ini_get('upload_tmp_dir')) {
00966 $directories[] = ini_get('upload_tmp_dir');
00967 }
00968
00969
00970 if (substr(PHP_OS, 0, 3) == 'WIN') {
00971 $directories[] = 'c:\\windows\\temp';
00972 $directories[] = 'c:\\winnt\\temp';
00973 $path_delimiter = '\\';
00974 }
00975 else {
00976 $directories[] = '/tmp';
00977 $path_delimiter = '/';
00978 }
00979
00980 foreach ($directories as $directory) {
00981 if (!$temporary_directory && is_dir($directory)) {
00982 $temporary_directory = $directory;
00983 }
00984 }
00985
00986
00987 $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter . 'tmp';
00988 variable_set('file_directory_temp', $temporary_directory);
00989 }
00990
00991 return $temporary_directory;
00992 }
00993
00999 function file_directory_path() {
01000 return variable_get('file_directory_path', conf_path() . '/files');
01001 }
01002
01009 function file_upload_max_size() {
01010 static $max_size = -1;
01011
01012 if ($max_size < 0) {
01013 $upload_max = parse_size(ini_get('upload_max_filesize'));
01014 $post_max = parse_size(ini_get('post_max_size'));
01015 $max_size = ($upload_max < $post_max) ? $upload_max : $post_max;
01016 }
01017 return $max_size;
01018 }
01019