2004-08-17 21:35:26 +00:00
<?php
/* $Id$ */
2004-08-21 06:42:38 +00:00
/**
* @file
* File-handling and attaching files to nodes.
*/
2004-08-17 21:35:26 +00:00
function upload_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('File-handling and attaching files to nodes.');
case 'admin/upload':
2004-11-23 22:20:41 +00:00
return t('<p>Users with the <a href="%permissions"><em>upload files</em> permission</a> can upload attachments. You can choose which node types can take attachments on the <a href="%workflow">workflow settings</a> page.</p>', array('%permissions' => url('admin/user/configure/permission'), '%workflow' => url('admin/node/configure/defaults')));
2004-08-17 21:35:26 +00:00
case 'admin/node/configure/defaults':
return t('<p>If you want users to be able to attach files to nodes, check the <em>attachments</em> column in the appropriate column.</p>');
2004-09-19 22:56:26 +00:00
case 'admin/help#upload':
return t('
<h3>Background</h3>
<p>The upload module allows users to upload attachments. You can choose which node types can take attachments on the <a href="%workflow">workflow settings</a> page.</p>
<h3>Permissions</h3>
<p>Two permissions are related to uploads: <em>upload files</em> and <em>view uploaded files</em>.</p>
<ol><li><strong>upload files</strong> - Allows users to upload attachments.</li><li><strong>view uploaded files</strong> - Allows users to view and download attachments. Keep in mind that if you are using the <a href="%settings">public download method</a>, anyone will be able to access uploaded files with a direct URL regardless of this permission.</li></ol>
<p>Lastly, users with the <em>administer site configuration</em> permission will be able to configure <a href="%upload">role-specific upload settings</a> such as allowed file types, maximum file size per upload and total file size per user.</p>
', array('%settings' => url('admin/settings'), '%workflow' => url('admin/node/configure/defaults'), '%upload' => url('admin/upload')));
2004-08-17 21:35:26 +00:00
}
}
function upload_perm() {
2004-09-19 22:56:26 +00:00
return array('upload files', 'view uploaded files');
2004-08-17 21:35:26 +00:00
}
2004-09-16 07:17:56 +00:00
function upload_menu($may_cache) {
$items = array();
if ($may_cache) {
2004-09-17 18:08:28 +00:00
$items[] = array(
2005-01-29 08:31:17 +00:00
'path' => 'admin/settings/upload', 'title' => t('uploads'),
2004-09-17 18:08:28 +00:00
'callback' => 'upload_admin',
2004-09-19 22:56:26 +00:00
'access' => user_access('administer site configuration'),
2004-09-17 18:08:28 +00:00
'type' => MENU_NORMAL_ITEM
);
}
else {
2004-09-16 07:17:56 +00:00
// Add handlers for previewing new uploads.
if ($_SESSION['file_uploads']) {
foreach ($_SESSION['file_uploads'] as $key => $file) {
$filename = file_create_filename($file->filename, file_create_path());
$items[] = array(
'path' => $filename, 'title' => t('file download'),
'callback' => 'upload_download',
2004-09-19 22:56:26 +00:00
'access' => user_access('view uploaded files'),
2004-09-17 18:08:28 +00:00
'type' => MENU_CALLBACK
2004-09-16 07:17:56 +00:00
);
$_SESSION['file_uploads'][$key]->_filename = $filename;
}
2004-08-17 21:35:26 +00:00
}
}
2004-09-16 07:17:56 +00:00
2004-08-17 21:35:26 +00:00
return $items;
}
function upload_admin() {
system_settings_save();
2004-08-18 19:45:50 +00:00
$group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 5, 5, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
2004-08-17 21:35:26 +00:00
$output = form_group(t('General settings'), $group);
$roles = user_roles(0, 'upload files');
foreach ($roles as $rid => $role) {
2004-08-18 19:45:50 +00:00
$group = form_textfield(t('Permitted file extensions'), "upload_extensions_$rid", variable_get("upload_extensions_$rid", "jpg jpeg gif png txt html doc xls pdf ppt pps"), 60, 255, t('Extensions that users in this role can upload. Separate extensions with a space and do not include the leading dot.'));
$group .= form_textfield(t('Maximum file size per upload'), "upload_uploadsize_$rid", variable_get("upload_uploadsize_$rid", 1), 5, 5, t('The maximum size of a file a user can upload (in megabytes).'));
$group .= form_textfield(t('Total file size per user'), "upload_usersize_$rid", variable_get("upload_usersize_$rid", 10), 5, 5, t('The maximum size of all files a user can have on the site (in megabytes).'));
$output .= form_group(t('Settings for %role', array('%role' => "<em>$role</em>")), $group);
2004-08-17 21:35:26 +00:00
}
print theme('page', system_settings_form($output));
}
function upload_download() {
foreach ($_SESSION['file_uploads'] as $file) {
if ($file->_filename == $_GET['q']) {
file_transfer($file->filepath, array('Content-Type: '. $file->filemime, 'Content-Length: '. $file->filesize));
}
}
}
function upload_file_download($file) {
2004-09-19 22:56:26 +00:00
if (user_access('view uploaded files')) {
$file = file_create_path($file);
2005-01-29 22:02:37 +00:00
$result = db_query(db_rewrite_sql("SELECT f.nid, * from {files} f WHERE filepath = '%s", 'f'), $file);
2004-09-19 22:56:26 +00:00
if ($file = db_fetch_object($result)) {
$name = mime_header_encode($file->filename);
// Serve images and text inline for the browser to display rather than download.
$disposition = ereg('^(text/|image/)', $file->filemime) ? 'inline' : 'attachment';
return array('Content-Type: '. $file->filemime .'; name='. $name,
'Content-Length: '. $file->filesize,
'Content-Disposition: '. $disposition .'; filename='. $name);
}
2004-08-17 21:35:26 +00:00
}
}
function upload_nodeapi(&$node, $op, $arg) {
switch ($op) {
case 'settings':
2005-01-24 21:20:16 +00:00
return form_radios(t('Attachments'), 'upload_'. $node->type, variable_get('upload_'. $node->type, 1), array(t('Disabled'), t('Enabled')));
2004-08-17 21:35:26 +00:00
case 'form param':
2004-08-18 21:55:39 +00:00
if (variable_get("upload_$node->type", 1) && user_access('upload files')) {
2004-08-17 21:35:26 +00:00
$output['options'] = array('enctype' => 'multipart/form-data');
}
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'validate':
$node->files = upload_load($node);
// Double check existing files:
if (is_array($node->list)) {
foreach ($node->list as $key => $value) {
if ($file = file_check_upload($key)) {
$node->files[$file->source] = $file;
$node->files[$key]->list = $node->list[$key];
$node->files[$key]->remove = $node->remove[$key];
if ($file->source) {
$filesize += $file->filesize;
}
}
}
}
else {
foreach ($node->files as $key => $file) {
$node->list[$key] = $file->list;
}
}
2004-08-19 15:41:57 +00:00
2004-08-18 21:55:39 +00:00
if (($file = file_check_upload('upload')) && user_access('upload files')) {
2004-08-17 21:35:26 +00:00
global $user;
$max_size = variable_get("upload_maxsize_total", 0);
$total_size = upload_count_size() + $filesize;
$total_usersize = upload_count_size($user->uid) + $filesize;
if ($maxsize && $total_size > $maxsize) {
2004-08-18 19:45:50 +00:00
form_set_error('upload', t('Error attaching file %name: total file size exceeded', array('%name' => "<em>$file->filename</em>")));
2004-08-17 21:35:26 +00:00
break;
}
2004-09-13 19:14:32 +00:00
// Don't do any checks for uid #1.
if ($user->uid != 1) {
// Validate file against all users roles. Only denies an upload when
// all roles prevent it.
foreach ($user->roles as $rid => $name) {
$extensions = variable_get("upload_extensions_$rid", 'jpg jpeg gif png txt html doc xls pdf ppt pps');
$uploadsize = variable_get("upload_uploadsize_$rid", 1);
$usersize = variable_get("upload_usersize_$rid", 1);
$regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i';
if (!preg_match($regex, $file->filename)) {
$error['extension']++;
}
2004-08-17 21:35:26 +00:00
2004-09-13 19:14:32 +00:00
if ($file->filesize > $uploadsize * 1024 * 1024) {
$error['uploadsize']++;
}
2004-08-17 21:35:26 +00:00
2004-09-13 19:14:32 +00:00
if ($total_usersize + $file->filesize > $usersize * 1024 * 1024) {
$error['usersize']++;
}
2004-08-17 21:35:26 +00:00
}
2004-09-13 19:14:32 +00:00
}
2004-08-17 21:35:26 +00:00
2004-09-13 19:14:32 +00:00
// Rename possibly executable scripts to prevent accidental execution.
// Uploaded files are attachments and should be shown in their original
// form, rather than run.
if (preg_match('/\.(php|pl|py|cgi|asp)$/i', $file->filename)) {
$file->filename .= '.txt';
$file->filemime = 'text/plain';
2004-08-17 21:35:26 +00:00
}
2004-08-19 15:41:57 +00:00
2004-08-18 21:55:39 +00:00
if ($error['extension'] == count($user->roles) && $user->uid != 1) {
2004-08-18 19:45:50 +00:00
form_set_error('upload', t('Error attaching file %name: invalid extension', array('%name' => "<em>$file->filename</em>")));
2004-08-17 21:35:26 +00:00
}
2004-08-18 21:55:39 +00:00
elseif ($error['uploadsize'] == count($user->roles) && $user->uid != 1) {
2004-08-18 19:45:50 +00:00
form_set_error('upload', t('Error attaching file %name: exceeds maximum file size', array('%name' => "<em>$file->filename</em>")));
2004-08-17 21:35:26 +00:00
}
2004-08-18 21:55:39 +00:00
elseif ($error['usersize'] == count($user->roles) && $user->uid != 1) {
2004-08-18 19:45:50 +00:00
form_set_error('upload', t('Error attaching file %name: exceeds maximum file size', array('%name' => "<em>$file->filename</em>")));
2004-08-17 21:35:26 +00:00
}
else {
$key = 'upload_'. count($_SESSION['file_uploads']);
$file->source = $key;
$file->list = 1;
$file = file_save_upload($file);
$node->files[$key] = $file;
}
}
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'form post':
2004-08-18 21:55:39 +00:00
if (variable_get("upload_$node->type", 1) == 1 && user_access('upload files')) {
2004-08-17 21:35:26 +00:00
$output = upload_form($node);
}
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'load':
2004-09-19 22:56:26 +00:00
if (variable_get("upload_$node->type", 1) == 1) {
2004-08-24 19:21:30 +00:00
$output['files'] = upload_load($node);
2004-08-17 21:35:26 +00:00
}
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'view':
2004-09-19 22:56:26 +00:00
if ($node->files && user_access('view uploaded files')) {
2004-08-19 15:41:57 +00:00
$header = array(t('Attachment'), t('Size'));
2004-08-17 21:35:26 +00:00
$rows = array();
$previews = array();
// Build list of attached files
foreach ($node->files as $file) {
if ($file->list) {
$rows[] = array(
'<a href="'. ($file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()))) . '">'. $file->filename .'</a>',
format_size($file->filesize)
);
// We save the list of files still in preview for later
if (!$file->fid) {
$previews[] = $file;
}
}
}
// URLs to files being previewed are actually Drupal paths. When Clean
// URLs are disabled, the two do not match. We perform an automatic
// replacement from temporary to permanent URLs. That way, the author
// can use the final URL in the body before having actually saved (to
// place inline images for example).
if (!variable_get('clean_url', 0)) {
foreach ($previews as $file) {
$old = file_create_filename($file->filename, file_create_path());
$new = url($old);
$node->body = str_replace($old, $new, $node->body);
$node->teaser = str_replace($old, $new, $node->teaser);
}
}
$teaser = $arg;
// Add the attachments list
if (count($rows) && !$teaser) {
$node->body .= theme('table', $header, $rows);
}
}
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'insert':
case 'update':
2004-08-18 21:55:39 +00:00
if (user_access('upload files')) {
upload_save($node);
}
2004-08-17 21:35:26 +00:00
break;
2005-01-24 21:20:16 +00:00
2004-08-17 21:35:26 +00:00
case 'delete':
upload_delete($node);
break;
2004-12-31 09:30:12 +00:00
case 'search result':
return $node->files ? format_plural(count($node->files), '1 attachment', '%count attachments') : null;
2004-08-17 21:35:26 +00:00
}
return $output;
}
function upload_count_size($uid = 0) {
if ($uid) {
$result = db_query("SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE uid = %d", $uid);
}
else {
$result = db_query("SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node} n ON f.nid = n.nid");
}
return db_result($result);
}
function upload_save($node) {
2004-09-05 09:15:18 +00:00
foreach ((array)$node->files as $key => $file) {
2004-08-17 21:35:26 +00:00
if ($file->source && !$file->remove) {
// Clean up the session:
unset($_SESSION['file_uploads'][$file->source]);
2004-10-20 16:57:35 +00:00
// Insert new files:
if ($file = file_save_upload($file, $file->filename)) {
$fid = db_next_id('{files}_fid');
db_query("INSERT INTO {files} (fid, nid, filename, filepath, filemime, filesize, list) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)",
$fid, $node->nid, $file->filename, $file->filepath, $file->filemime, $file->filesize, $node->list[$key]);
}
2004-08-17 21:35:26 +00:00
}
else {
// Remove or update existing files:
if ($node->remove[$key]) {
file_delete($file->filepath);
db_query("DELETE FROM {files} WHERE fid = %d", $key);
}
if ($file->list != $node->list[$key]) {
db_query("UPDATE {files} SET list = %d WHERE fid = %d", $node->list[$key], $key);
}
}
}
return;
}
function upload_delete($node) {
$node->files = upload_load($node);
foreach ($node->files as $file) {
file_delete($file->filepath);
}
db_query("DELETE FROM {files} WHERE nid = %d", $node->nid);
}
function upload_form($node) {
2004-08-19 15:41:57 +00:00
$header = array(t('Delete'), t('List'), t('Url'), t('Size'));
2004-08-17 21:35:26 +00:00
$rows = array();
if (is_array($node->files)) {
foreach ($node->files as $key => $file) {
$rows[] = array(
form_checkbox('', "remove][$key", 1, $file->remove),
form_checkbox('', "list][$key", 1, $file->list),
$file->filename ."<br /><small>". file_create_url(($file->fid ? $file->filepath : file_create_filename($file->filename, file_create_path()))) ."</small>",
format_size($file->filesize)
);
}
}
if (count($node->files)) {
2004-08-18 06:08:04 +00:00
$output = form_item('', theme('table', $header, $rows), t('Note: changes made to the attachments are not permanent until you save this post.'));
2004-08-17 21:35:26 +00:00
}
2004-08-18 21:55:39 +00:00
if (user_access('upload files')) {
$output .= form_file(t('Attach new file'), "upload", 40);
$output .= form_button(t('Attach'), 'fileop');
}
2004-08-17 21:35:26 +00:00
return '<div class="attachments">'. form_group(t('Attachments'), $output) . '</div>';
}
function upload_load($node) {
$files = array();
if ($node->nid) {
$result = db_query("SELECT * FROM {files} WHERE nid = %d", $node->nid);
while ($file = db_fetch_object($result)) {
$files[$file->fid] = $file;
}
}
return $files;
}
?>