Commit 15f289a8 authored by Dries's avatar Dries

- Added file handling.  Work by Kjartan.
parent c1898456
......@@ -935,6 +935,7 @@ function drupal_page_footer() {
include_once "includes/menu.inc";
include_once "includes/xmlrpc.inc";
include_once "includes/tablesort.inc";
include_once "includes/file.inc";
// set error handler:
set_error_handler("error_handler");
......
<?php
/** @file
* $Id$
*
* Common file handling functions
*
* @par Example:
* @code
* function module_validate($node) {
* if (!$node->file = file_save_upload('file')) {
* $error['file'] = t('File required.');
* }
* }
*
* function module_insert($node) {
* if ($node->file) {
* file_save($node->file);
* }
* }
* @endcode
*
*/
define('FILE_DOWNLOADS_PUBLIC', 1);
define('FILE_DOWNLOADS_PRIVATE', 2);
define('FILE_SEPARATOR', PHP_OS == 'WINNT' ? '\\' : '/');
/**
* Create the download path to a file.
*/
function file_create_url($path) {
switch (variable_get('file_downloads', FILE_DOWNLOADS_PRIVATE)) {
case FILE_DOWNLOADS_PUBLIC:
case FILE_DOWNLOADS_PRIVATE:
global $base_url;
if (strpos($path, variable_get('file_directory_path', 'files')) !== false) {
$path = trim(substr($path, strlen(variable_get('file_directory_path', 'files'))), '\\/');
}
return $base_url .'/'. variable_get('file_directory_path', 'files') .'/'. str_replace('\\', '/', $path);
case FILE_DOWNLOADS_PRIVATE:
return url('system/files', 'file='. $path);
}
}
/**
* Make sure the destination is a complete path, if it is not prepend the
* file system directory.
*/
function file_create_path($dest = 0) {
if (!$dest) {
return variable_get('file_directory_path', 'files');
}
$regex = (PHP_OS == 'WINNT' ? '.?:\\\\' : '/');
if (!file_check_location($dest, variable_get('file_directory_path', 'files')) && !preg_match("|^$regex|", $dest)) {
return variable_get('file_directory_path', 'files') . FILE_SEPARATOR . trim($dest, '\\/');
}
else {
return $dest;
}
}
/**
* Check that directory exists and is writable.
*
* @param $directory Path to extract and verify directory for.
* @return False when directory not found, or true when directory exists.
*/
function file_check_directory(&$directory) {
$directory = rtrim($directory, '/\\');
return is_dir($directory) && is_writable($directory);
}
/**
* Checks path to see if it is a directory, or a dir/file.
*
* @param $path
*/
function file_check_path(&$path) {
// Check if path is a directory.
if (file_check_directory($path)) {
return '';
}
// Check if path is a possible dir/file.
$filename = basename($path);
$path = dirname($path);
if (file_check_directory($path)) {
return $filename;
}
return false;
}
/**
* Check if $source is a valid file upload.
*
* @param $source
*/
function file_check_upload($source) {
if ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
$file->name = trim(basename($_FILES["edit"]["name"][$source]), '.');
$file->type = $_FILES["edit"]["type"][$source];
$file->path = $_FILES["edit"]["tmp_name"][$source];
$file->error = $_FILES["edit"]["error"][$source];
$file->size = $_FILES["edit"]["size"][$source];
return $file;
}
}
/**
* 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.
*
* @code
* // Returns false:
* file_check_location('/www/example.com/files/../../../etc/passwd', '/www/example.com/files');
* @endcode
*
* @param $source A string set to the file to check.
* @param $directory A string where the file should be located.
* @return 0 for invalid path or the real path of the source.
*/
function file_check_location($source, $directory = 0) {
$source = realpath($source);
if ($directory && strpos($source, $directory) !== 0) {
return 0;
}
return $source;
}
/**
* Saves a file to a new location. This is a powerful function that in many ways
* performs like an advanced version of copy().
* - Checks if $source and $dest are valid and readable/writable.
* - Performs a file copy if $source is not equal to $dest.
* - If file already exists in $dest it will append a number to the end of the
* filename, but before the file extension. It will increment the number until
* it finds a filename that is not already in use.
*
* @param $source A string specifying the file location of the original file.
* This parameter will contain the resulting destination filename in case of
* success.
* @param $dest A string containing the directory $source should be copied to.
* @param $replace A boolean that when true will overwrite any existing files,
* but when false append a _X to the filename.
* @return True for success, false for failure.
*/
function file_copy(&$source, $dest = 0, $replace = 0) {
$dest = file_create_path($dest);
$directory = $dest;
$basename = file_check_path($directory);
// Make sure we at least have a valid directory.
if ($basename === false) {
drupal_set_message(t('file copy failed: no directory configured, or it could not be accessed.'), 'error');
return 0;
}
// Process a file upload object.
if (is_object($source)) {
$file = $source;
$source = $file->path;
if (!$basename) {
$basename = $file->name;
}
}
$source = realpath($source);
if (!file_exists($source)) {
drupal_set_message(t('file copy failed: source file does not exist.'), 'error');
return 0;
}
// If destination file is not specified then use filename of source file.
$basename = $basename ? $basename : basename($source);
$dest = $directory . FILE_SEPARATOR . $basename;
if (file_exists($dest) && !$replace) {
// Destination file already exists and we can't replace is so we try and
// and find a new filename.
list($name, $ext) = explode('.', $basename, 2);
$ext = $ext ? ".$ext" : '';
$counter = 0;
do {
$dest = $directory . FILE_SEPARATOR . $name .'_'. $counter++ . $ext;
$counter++;
} while (file_exists($dest));
}
if (!copy($source, $dest)) {
drupal_set_message(t('file copy failed.'), 'error');
return 0;
}
if (is_object($file)) {
$file->name = $basename;
$file->path = $dest;
$source = $file;
}
else {
$source = $dest;
}
return 1; // Everything went ok.
}
function file_move(&$source, $dest = 0, $replace = 0) {
$path = is_object($source) ? $source->path : $source;
if (file_copy($source, $dest, $replace)) {
if (unlink($path)) {
return 1;
}
drupal_set_message(t('removing original file failed.'), 'error');
}
return 0;
}
function file_delete($source) {
unlink(file_create_path($source));
}
/**
* Saves a file upload to a new location. The source file is validated as a
* proper upload and handled as such.
*
* @param $source A string specifying the name of the upload field to save.
* This parameter will contain the resulting destination filename in case of
* success.
* @param $dest A string containing the directory $source should be copied to,
* will use the temporary directory in case no other value is set.
* @param $dest A boolean, set to true if the destination should be replaced
* when in use, but when false append a _X to the filename.
* @return An object containing file info or 0 in case of error.
*/
function file_save_upload($source, $dest = 0, $replace = 0) {
// Make sure $source exists in $_FILES.
if ($file = file_check_upload($source)) {
if ($dest === 0) {
$dest = variable_get('file_directory_temp', ini_get('upload_tmp_dir'));
$temporary = 1;
if (file_exists($_SESSION['file_uploads'][$source]->path)) {
// If this file was uploaded by this user before replace the temporary copy.
$replace = 1;
}
}
if (!valid_input_data($file)) {
watchdog('error', t('Possible exploit abuse: invalid data.'));
drupal_set_message(t("file upload failed: invalid data."), 'error');
return 0;
}
// Check for file upload errors.
switch ($file->error) {
case UPLOAD_ERR_PARTIAL:
case UPLOAD_ERR_NO_FILE:
drupal_set_message(t("file upload failed: incomplete upload."), 'error');
return 0;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
drupal_set_message(t("file upload failed: file size too big."), 'error');
return 0;
}
unset($_SESSION['file_uploads'][$source]);
if (file_move($file, $dest, $replace)) {
if ($temporary) {
$_SESSION['file_uploads'][$source] = $file;
}
return $file;
}
return 0;
}
else {
// In case if previews return previous file object.
if (file_exists($_SESSION['file_uploads'][$source]->path)) {
return $_SESSION['file_uploads'][$source];
}
}
return 0;
}
/**
* Transfer file using http to client. Pipes a file through Drupal to the
* client.
*
* @param $source File to transfer.
* @param $headers An array of http headers to send along with file.
*/
function file_transfer($source, $headers) {
ob_end_clean();
foreach ($headers as $header) {
header($header);
}
$source = file_create_path($source);
// Transfer file in 1024 byte chunks to save memory usage.
$fd = fopen($source, 'rb');
while (!feof($fd)) {
print fgets($fd);
}
fclose($fd);
exit();
}
/**
* Call modules to find out if a file is accessible for a given user.
*/
function file_download() {
$file = $_GET['file'];
if (file_exists(file_create_path($file))) {
$list = module_list();
foreach ($list as $module) {
$headers = module_invoke($module, 'file_download', $file);
if ($headers === -1) {
print theme('page', message_access());
}
elseif (is_array($headers)) {
file_transfer($file, $headers);
}
}
}
//drupal_not_found();
}
/**
* Finds all files that match a given mask in a given directory. Searches
* recursively.
*/
function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0) {
$files = array();
if (is_dir($dir) && $handle = opendir($dir)) {
while ($file = readdir($handle)) {
if (!in_array($file, $nomask)) {
if (is_dir("$dir/$file")) {
$files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback));
}
elseif (ereg($mask, $file)) {
$name = basename($file);
$files["$dir/$file"]->filename = "$dir/$file";
$files["$dir/$file"]->name = substr($name, 0, strrpos($name, '.'));
if ($callback) {
$callback("$dir/$file");
}
}
}
}
closedir($handle);
}
return $files;
}
?>
......@@ -57,6 +57,10 @@ function profile_settings() {
_profile_init();
}
if (!file_check_directory(file_create_path(variable_get('profile_avatar_path', 'avatars')))) {
$error['profile_avatar_path'] = theme('error', t('Directory does not exist, or is not writable.'));
}
$profile_public_fields = variable_get("profile_public_fields", array());
$profile_private_fields = variable_get("profile_private_fields", array());
$profile_required_fields = variable_get("profile_required_fields", array());
......@@ -74,7 +78,7 @@ function profile_settings() {
}
$output .= theme("table", $header, $row);
$output .= form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "misc/avatars/"), 30, 255, t("Path for avatar directory; it must be writable and visible from the web."));
$output .= form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "avatars"), 30, 255, t("Subdirectory in the directory '%dir' where avatars will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error['profile_avatar_path']);
$output .= form_textfield(t("Avatar maximum dimensions"), "profile_avatar_dimensions", variable_get("profile_avatar_dimensions", "85x85"), 10, 10, t("Maximum dimensions for avatars."));
$output .= form_textfield(t("Avatar maximum file size"), "profile_avatar_file_size", variable_get("profile_avatar_file_size", "30"), 10, 10, t("Maximum file size for avatars, in kB."));
......@@ -133,11 +137,8 @@ function _profile_form($edit, $mode) {
}
if (in_array("avatar", $reg_fields)) {
if ($edit["profile_avatar"] && $edit["uid"]) {
$file = profile_avatar_path($edit["uid"], $edit["profile_avatar"]);
if ($file) {
$output .= "<img src=\"$file\" alt=\"\" title=\"\" /><br />";
}
if ($edit["profile_avatar"] && file_exists($edit["profile_avatar"])) {
$output .= form_item(t("Avatar"), '<img src="'. file_create_url($edit["profile_avatar"]) .'" alt="" title="" />');
}
$output .= form_file($profile_fields["avatar"][1], "profile_avatar", 64, $profile_fields["avatar"][2]);
}
......@@ -199,9 +200,8 @@ function _profile_user_view(&$user, $mode) {
case "":
// special
if ($t == "profile_avatar") {
$file = profile_avatar_path($user->uid, $user->profile_avatar);
if (file_exists($file)) {
$output .= form_item(t("Avatar"), "<img src=\"$file\" alt=\"\" title=\"\" />");
if (file_exists($user->$t)) {
$output .= form_item(t("Avatar"), '<img src="'. file_create_url($user->$t) .'" alt="" title="" />');
}
}
......@@ -218,51 +218,44 @@ function _profile_user_view(&$user, $mode) {
return $output;
}
function profile_file_download($file) {
if (strpos($file, variable_get("profile_avatar_path", "avatars")) === 0) {
return array("Content-type: $mime");
}
}
function _profile_validate_avatar(&$edit, $user) {
// check that uploaded file is an image, with a maximum file size and maximum height/width
unset($edit["profile_avatar"]);
if ($_FILES["edit"]["name"]["profile_avatar"] == "") {
if (!$file = file_check_upload('profile_avatar')) {
$edit["profile_avatar"] = $user->profile_avatar;
return "";
return;
}
$image_file = $_FILES["edit"]["tmp_name"]["profile_avatar"];
if (is_uploaded_file($image_file)) {
$extension = strtolower(strrchr($_FILES["edit"]["name"]["profile_avatar"], "."));
$size = getimagesize($image_file);
list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85"));
if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) {
$error = t("The uploaded file was not an image.");
}
else if (filesize($image_file) > (variable_get("profile_avatar_file_size", "30") * 1000)) {
$error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30")));
}
else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
$error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85")));
}
else if (!is_dir(variable_get("profile_avatar_path", "misc/avatars/"))) {
$error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else if (!is_writeable(variable_get("profile_avatar_path", "misc/avatars/"))) {
$error = t("Failed to upload the avatar image; the webserver has no write permission to the '%directory' directory.", array("%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else if (!copy($image_file, variable_get("profile_avatar_path", "misc/avatars/").md5($user->uid).$extension)) {
$error = t("Failed to upload the avatar image; could not copy file '%filename' to directory '%directory'.", array("%filename" => $_FILES["edit"]["name"]["profile_avatar"], "%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else {
$edit["profile_avatar"] = $extension;
}
$extension = strtolower(strrchr($file->name, "."));
$size = getimagesize($file->path);
list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85"));
if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) {
$error = t("The uploaded file was not an image.");
}
else if ($file->size > (variable_get("profile_avatar_file_size", "30") * 1000)) {
$error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30")));
}
else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
$error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85")));
}
else if ($file = file_save_upload('profile_avatar', variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR .'avatar-'. $user->uid . $extension, 1)) {
$edit["profile_avatar"] = $file->name;
}
else {
$error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "avatars")));
}
return $error ? "$error<br />" : "";
}
function profile_avatar_path($uid, $extension) {
return $extension ? variable_get("profile_avatar_path", "misc/avatars/") . md5($uid) . $extension : "";
}
function _profile_active_fields($mode) {
return variable_get("profile_". $mode ."_fields", array());
}
......
......@@ -57,6 +57,10 @@ function profile_settings() {
_profile_init();
}
if (!file_check_directory(file_create_path(variable_get('profile_avatar_path', 'avatars')))) {
$error['profile_avatar_path'] = theme('error', t('Directory does not exist, or is not writable.'));
}
$profile_public_fields = variable_get("profile_public_fields", array());
$profile_private_fields = variable_get("profile_private_fields", array());
$profile_required_fields = variable_get("profile_required_fields", array());
......@@ -74,7 +78,7 @@ function profile_settings() {
}
$output .= theme("table", $header, $row);
$output .= form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "misc/avatars/"), 30, 255, t("Path for avatar directory; it must be writable and visible from the web."));
$output .= form_textfield(t("Avatar image path"), "profile_avatar_path", variable_get("profile_avatar_path", "avatars"), 30, 255, t("Subdirectory in the directory '%dir' where avatars will be stored.", array('%dir' => variable_get('file_directory_path', 'files') . FILE_SEPARATOR)) . $error['profile_avatar_path']);
$output .= form_textfield(t("Avatar maximum dimensions"), "profile_avatar_dimensions", variable_get("profile_avatar_dimensions", "85x85"), 10, 10, t("Maximum dimensions for avatars."));
$output .= form_textfield(t("Avatar maximum file size"), "profile_avatar_file_size", variable_get("profile_avatar_file_size", "30"), 10, 10, t("Maximum file size for avatars, in kB."));
......@@ -133,11 +137,8 @@ function _profile_form($edit, $mode) {
}
if (in_array("avatar", $reg_fields)) {
if ($edit["profile_avatar"] && $edit["uid"]) {
$file = profile_avatar_path($edit["uid"], $edit["profile_avatar"]);
if ($file) {
$output .= "<img src=\"$file\" alt=\"\" title=\"\" /><br />";
}
if ($edit["profile_avatar"] && file_exists($edit["profile_avatar"])) {
$output .= form_item(t("Avatar"), '<img src="'. file_create_url($edit["profile_avatar"]) .'" alt="" title="" />');
}
$output .= form_file($profile_fields["avatar"][1], "profile_avatar", 64, $profile_fields["avatar"][2]);
}
......@@ -199,9 +200,8 @@ function _profile_user_view(&$user, $mode) {
case "":
// special
if ($t == "profile_avatar") {
$file = profile_avatar_path($user->uid, $user->profile_avatar);
if (file_exists($file)) {
$output .= form_item(t("Avatar"), "<img src=\"$file\" alt=\"\" title=\"\" />");
if (file_exists($user->$t)) {
$output .= form_item(t("Avatar"), '<img src="'. file_create_url($user->$t) .'" alt="" title="" />');
}
}
......@@ -218,51 +218,44 @@ function _profile_user_view(&$user, $mode) {
return $output;
}
function profile_file_download($file) {
if (strpos($file, variable_get("profile_avatar_path", "avatars")) === 0) {
return array("Content-type: $mime");
}
}
function _profile_validate_avatar(&$edit, $user) {
// check that uploaded file is an image, with a maximum file size and maximum height/width
unset($edit["profile_avatar"]);
if ($_FILES["edit"]["name"]["profile_avatar"] == "") {
if (!$file = file_check_upload('profile_avatar')) {
$edit["profile_avatar"] = $user->profile_avatar;
return "";
return;
}
$image_file = $_FILES["edit"]["tmp_name"]["profile_avatar"];
if (is_uploaded_file($image_file)) {
$extension = strtolower(strrchr($_FILES["edit"]["name"]["profile_avatar"], "."));
$size = getimagesize($image_file);
list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85"));
if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) {
$error = t("The uploaded file was not an image.");
}
else if (filesize($image_file) > (variable_get("profile_avatar_file_size", "30") * 1000)) {
$error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30")));
}
else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
$error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85")));
}
else if (!is_dir(variable_get("profile_avatar_path", "misc/avatars/"))) {
$error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else if (!is_writeable(variable_get("profile_avatar_path", "misc/avatars/"))) {
$error = t("Failed to upload the avatar image; the webserver has no write permission to the '%directory' directory.", array("%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else if (!copy($image_file, variable_get("profile_avatar_path", "misc/avatars/").md5($user->uid).$extension)) {
$error = t("Failed to upload the avatar image; could not copy file '%filename' to directory '%directory'.", array("%filename" => $_FILES["edit"]["name"]["profile_avatar"], "%directory" => variable_get("profile_avatar_path", "misc/avatars/")));
}
else {
$edit["profile_avatar"] = $extension;
}
$extension = strtolower(strrchr($file->name, "."));
$size = getimagesize($file->path);
list($maxwidth, $maxheight) = explode("x", variable_get("profile_avatar_dimensions", "85x85"));
if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array(".gif", ".jpg", ".png", ".jpeg")))) {
$error = t("The uploaded file was not an image.");
}
else if ($file->size > (variable_get("profile_avatar_file_size", "30") * 1000)) {
$error = t("The uploaded image is too large; the maximum file size is %a kB.", array("%a" => variable_get("profile_avatar_file_size", "30")));
}
else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
$error = t("The uploaded image is too large; the maximum dimensions are %a pixels.", array("%a" => variable_get("profile_avatar_dimensions", "85x85")));
}
else if ($file = file_save_upload('profile_avatar', variable_get("profile_avatar_path", "avatars") . FILE_SEPARATOR .'avatar-'. $user->uid . $extension, 1)) {
$edit["profile_avatar"] = $file->name;
}
else {
$error = t("Failed to upload the avatar image; the '%directory' directory doesn't exist.", array("%directory" => variable_get("profile_avatar_path", "avatars")));
}
return $error ? "$error<br />" : "";
}
function profile_avatar_path($uid, $extension) {
return $extension ? variable_get("profile_avatar_path", "misc/avatars/") . md5($uid) . $extension : "";
}
function _profile_active_fields($mode) {
return variable_get("profile_". $mode ."_fields", array());
}
......
......@@ -35,8 +35,7 @@ function system_help($section = "admin/help#system") {
// Start of system_help_cache
$output .= "<p>Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached.</p>";
// End of system_help_cache
$output = t($output, array("%base_url" => $base_url, "%cron-link" => "<a href=\"$base_url/cron.php\
\">$base_url/cron.php</a>", "%lynx" => "<a href=\"http://lynx.browser.org\">lynx</a>", "%wget" => "<a href=\"http://www.gnu.org/software/wget/wget.html\">wget</a>" ));
$output = t($output, array("%base_url" => $base_url, "%cron-link" => "<a href=\"$base_url/cron.php\">$base_url/cron.php</a>", "%lynx" => "<a href=\"http://lynx.browser.org\">lynx</a>", "%wget" => "<a href=\"http://www.gnu.org/software/wget/wget.html\">wget</a>" ));
break;
case 'admin/system/modules#description':
$output = t("Configuration system that lets administrators modify the workings of the site.");
......@@ -56,6 +55,7 @@ function system_perm() {
function system_link($type) {
if ($type == "system") {
menu("system/files", t("file download"), "file_download", 0, MENU_HIDE);
if (user_access("administer site configuration")) {
menu("admin/system", t("configuration"), "system_admin", 3);
......@@ -126,6 +126,17 @@ function system_view_general() {
$output .= form_group(t("Cache settings"), $group);
// file system:
if (!file_check_directory(variable_get