From b644a78db052358d732889a77516cf466bd0bc01 Mon Sep 17 00:00:00 2001 From: Dave Reid Date: Sat, 30 Jul 2011 09:56:05 -0500 Subject: [PATCH] Issue #1227706: Added a file entity access API. --- file_entity.module | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 133 insertions(+), 0 deletions(-) diff --git a/file_entity.module b/file_entity.module index 871f83a..1f3bbcb 100644 --- a/file_entity.module +++ b/file_entity.module @@ -6,6 +6,21 @@ */ /** + * Modules should return this value from hook_file_access() to allow access to a file. + */ +define('FILE_ACCESS_ALLOW', 'allow'); + +/** + * Modules should return this value from hook_file_access() to deny access to a file. + */ +define('FILE_ACCESS_DENY', 'deny'); + +/** + * Modules should return this value from hook_file_access() to not affect file access. + */ +define('FILE_ACCESS_IGNORE', NULL); + +/** * As part of extending Drupal core's file entity API, this module adds some * functions to the 'file' namespace. For organization, those are kept in the * 'file_entity.file_api.inc' file. @@ -492,3 +507,121 @@ function template_preprocess_file_entity(&$variables) { $variables['theme_hook_suggestions'][] = 'file__' . str_replace(array('/', '-'), array('__', '_'), $file->filemime); $variables['theme_hook_suggestions'][] = 'file__' . $file->fid; } + +/** + * Determine if a user may perform the given operation on the specified file. + * + * @param $op + * The operation to be performed on the file. Possible values are: + * - "view" + * - "update" + * - "delete" + * - "create" + * @param $file + * The file object on which the operation is to be performed, or file type + * (e.g. 'image') for "create" operation. + * @param $account + * Optional, a user object representing the user for whom the operation is to + * be performed. Determines access for a user other than the current user. + * + * @return + * TRUE if the operation may be performed, FALSE otherwise. + */ +function file_access($op, $file, $account = NULL) { + global $user; + + $rights = &drupal_static(__FUNCTION__, array()); + + if (!$file || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) { + // If there was no file to check against, or the $op was not one of the + // supported ones, we return access denied. + return FALSE; + } + // If no user object is supplied, the access check is for the current user. + if (empty($account)) { + $account = $user; + } + + // $file may be either an object or a file type. Since file types cannot be + // an integer, use either fid or type as the static cache id. + + $cid = is_object($file) ? $file->nid : $file; + + // If we've already checked access for this file, user and op, return from + // cache. + if (isset($rights[$account->uid][$cid][$op])) { + return $rights[$account->uid][$cid][$op]; + } + + //if (user_access('bypass file access', $account)) { + // return $rights[$account->uid][$cid][$op] = TRUE; + //} + //if (!user_access('access files', $account)) { + // return $rights[$account->uid][$cid][$op] = FALSE; + //} + + // We grant access to the file if both of the following conditions are met: + // - No modules say to deny access. + // - At least one module says to grant access. + $access = module_invoke_all('file_access', $file, $op, $account); + if (in_array(FILE_ACCESS_DENY, $access, TRUE)) { + return $rights[$account->uid][$cid][$op] = FALSE; + } + elseif (in_array(FILE_ACCESS_ALLOW, $access, TRUE)) { + return $rights[$account->uid][$cid][$op] = TRUE; + } + + // Check if authors can view their own temporary files. + //if ($op == 'view' && $file->status != FILE_STATUS_PERMANENT && user_access('view own unpublished content', $account) && $account->uid == $file->uid && $account->uid != 0) { + // return $rights[$account->uid][$cid][$op] = TRUE; + //} + + // Default behavior is to allow all users to view permanent files. + if (is_object($file) && $op == 'view' && $file->status == FILE_STATUS_PERMANENT) { + return $rights[$account->uid][$cid][$op] = TRUE; + } + + return FALSE; +} + +/** + * Implements hook_stream_wrappers_alter(). + */ +function file_entity_stream_wrappers_alter(&$wrappers) { + $wrappers['private']['uses file_download'] = TRUE; + $wrappers['temporary']['uses file_download'] = TRUE; +} + +/** + * Return a specific stream wrapper's registry information. + * + * @param $scheme + * A URI scheme, a stream is referenced as "scheme://target". + * + * @see file_get_stream_wrappers() + */ +function file_get_stream_wrapper($scheme) { + $wrappers = file_get_stream_wrappers(); + return isset($wrappers[$scheme]) ? $wrappers[$scheme] : FALSE; +} + +/** + * Implements hook_file_access(). + */ +function file_entity_file_access($op, $file, $account) { + if ($op == 'view' && file_valid_uri($file->uri)) { + $wrapper = file_get_stream_wrapper(file_uri_scheme($file->uri)); + + // Restrict access to private files. + // @see file_download() + if (!empty($wrapper['uses file_download'])) { + foreach (module_implements('file_download') as $module) { + if (module_invoke($module, 'file_download', $file->uri) === -1) { + return FILE_ACCESS_DENY; + } + } + } + } + + return FILE_ACCESS_IGNORE; +} -- 1.7.1