function filefield_file_download in FileField 6.3
Same name and namespace in other branches
- 5.2 filefield.module \filefield_file_download()
- 6.2 filefield.module \filefield_file_download()
Implementation of hook_file_download().
File
- ./
filefield.module, line 120 - FileField: Defines a CCK file field type.
Code
function filefield_file_download($filepath) {
$filepath = file_create_path($filepath);
$result = db_query("SELECT * FROM {files} WHERE filepath = '%s'", $filepath);
// Ensure case-sensitivity of uploaded file names.
while ($file = db_fetch_object($result)) {
if (strcmp($file->filepath, $filepath) == 0) {
break;
}
}
// If the file is not found in the database, we're not responsible for it.
if (empty($file)) {
return;
}
// See if this is a file on a newly created node, on which the user who
// uploaded it will immediately have access.
$new_node_file = $file->status == 0 && isset($_SESSION['filefield_access']) && in_array($file->fid, $_SESSION['filefield_access']);
if ($new_node_file) {
$denied = FALSE;
}
else {
// Find out if any file field contains this file, and if so, which field
// and node it belongs to. Required for later access checking.
$cck_files = array();
foreach (content_fields() as $field) {
if ($field['type'] == 'filefield' || $field['type'] == 'image') {
$db_info = content_database_info($field);
$table = $db_info['table'];
$fid_column = $db_info['columns']['fid']['column'];
$columns = array(
'vid',
'nid',
);
foreach ($db_info['columns'] as $property_name => $column_info) {
$columns[] = $column_info['column'] . ' AS ' . $property_name;
}
$result = db_query("SELECT " . implode(', ', $columns) . "\n FROM {" . $table . "}\n WHERE " . $fid_column . " = %d", $file->fid);
while ($content = db_fetch_array($result)) {
$content['field'] = $field;
$cck_files[$field['field_name']][$content['vid']] = $content;
}
}
}
// If no file field item is involved with this file, we don't care about it.
if (empty($cck_files)) {
return;
}
// So the overall field view permissions are not denied, but if access is
// denied for ALL nodes containing the file, deny the download as well.
// Node access checks also include checking for 'access content'.
$nodes = array();
$denied = TRUE;
$revision_access = FALSE;
foreach ($cck_files as $field_name => $field_files) {
foreach ($field_files as $revision_id => $content) {
// Checking separately for each revision is probably not the best idea -
// what if 'view revisions' is disabled? So, let's just check for the
// current revision of that node.
if (isset($nodes[$content['nid']])) {
continue;
// Don't check the same node twice.
}
if (($node = node_load($content['nid'])) && (node_access('view', $node) && filefield_view_access($field_name, $node))) {
// They have access to the node.
$denied = FALSE;
}
if (!$denied && $node->vid == $revision_id) {
// If revision is the current revision, grant access.
$revision_access = TRUE;
}
elseif (!$denied) {
$revision_node = node_load($content['nid'], $revision_id);
// You have access to the node as well as that particular revision.
$revision_access = $revision_node && _node_revision_access($revision_node, 'view');
}
// If node access denied, skip other revisions; or if we have node
// access and access to at least one revision the file is present on,
// skip other revision checks.
if ($denied || $revision_access) {
$nodes[$content['nid']] = $node;
break 2;
}
}
}
}
// If they don't have access to the node or file, or if the file is only
// attached to revisions that they don't have access to, deny access.
if ($denied || !$revision_access) {
return -1;
}
// Access is granted.
$name = mime_header_encode($file->filename);
$type = mime_header_encode($file->filemime);
// By default, serve images, text, and flash content for display rather than
// download. Or if variable 'filefield_inline_types' is set, use its patterns.
$inline_types = variable_get('filefield_inline_types', array(
'^text/',
'^image/',
'flash$',
));
$disposition = 'attachment';
foreach ($inline_types as $inline_type) {
// Exclamation marks are used as delimiters to avoid escaping slashes.
if (preg_match('!' . $inline_type . '!', $file->filemime)) {
$disposition = 'inline';
}
}
return array(
'Content-Type: ' . $type . '; name="' . $name . '"',
'Content-Length: ' . $file->filesize,
'Content-Disposition: ' . $disposition . '; filename="' . $name . '"',
'Cache-Control: private',
);
}