function _file_entity_query_file_entity_access_alter in File Entity (fieldable files) 7.3
Same name and namespace in other branches
- 7.2 file_entity.module \_file_entity_query_file_entity_access_alter()
Helper for file entity access functions.
Parameters
$query: The query to add conditions to.
$type: Either 'file' or 'entity' depending on what sort of query it is. See file_entity_query_file_entity_access_alter() and file_entity_query_entity_field_access_alter() for more.
Related topics
1 call to _file_entity_query_file_entity_access_alter()
- file_entity_query_file_access_alter in ./
file_entity.module - Implements hook_query_TAG_alter().
File
- ./
file_entity.module, line 1915 - Extends Drupal file entities to be fieldable and viewable.
Code
function _file_entity_query_file_entity_access_alter($query, $type) {
global $user;
// Read meta-data from query, if provided.
if (!($account = $query
->getMetaData('account'))) {
$account = $user;
}
// If $account can bypass file access, we don't need to alter the query.
if (user_access('bypass file access', $account)) {
return;
}
// A conflict with og_query_og_membership_alter() causes a fatal error
// if both hooks alter the query.
if (module_exists('og') && $query
->hasTag('og_membership')) {
foreach ($query
->getMetaData('entity_field_query')->fields as $field) {
if (og_is_group_audience_field($field['field_name'])) {
return;
}
}
}
$tables = $query
->getTables();
$base_table = $query
->getMetaData('base_table');
// If no base table is specified explicitly, search for one.
if (!$base_table) {
$fallback = '';
foreach ($tables as $alias => $table_info) {
if (!($table_info instanceof SelectQueryInterface || $table_info['table'] instanceof SelectQueryInterface)) {
$table = $table_info['table'];
// If the file_managed table is in the query, it wins immediately.
if ($table == 'file_managed') {
$base_table = $table;
break;
}
// Check whether the table has a foreign key to file_managed.fid. If it
// does, do not run this check again as we found a base table and only
// file_managed can triumph that.
if (!$base_table) {
// The schema is cached.
$schema = drupal_get_schema($table);
if (isset($schema['fields']['fid'])) {
if (isset($schema['foreign keys'])) {
foreach ($schema['foreign keys'] as $relation) {
if ($relation['table'] === 'file_managed' && $relation['columns'] === array(
'fid' => 'fid',
)) {
$base_table = $table;
}
}
}
else {
// At least it's a fid. A table with a field called fid is very
// very likely to be a file_managed.fid in a file access query.
$fallback = $table;
}
}
}
}
}
// If there is nothing else, use the fallback.
if (!$base_table) {
if ($fallback) {
watchdog('security', 'Your file listing query is using @fallback as a base table in a query tagged for file access. This might not be secure and might not even work. Specify foreign keys in your schema to file_managed.fid ', array(
'@fallback' => $fallback,
), WATCHDOG_WARNING);
$base_table = $fallback;
}
else {
throw new Exception(t('Query tagged for file access but there is no fid. Add foreign keys to file_managed.fid in schema to fix.'));
}
}
}
if ($type == 'entity') {
// The original query looked something like:
// @code
// SELECT fid FROM sometable s
// WHERE ($file_access_conditions)
// @endcode
//
// Our query will look like:
// @code
// SELECT entity_type, entity_id
// FROM field_data_something s
// WHERE (entity_type = 'file' AND $file_access_conditions) OR (entity_type <> 'file')
// @endcode
//
// So instead of directly adding to the query object, we need to collect
// all of the file access conditions in a separate db_and() object and
// then add it to the query at the end.
$file_conditions = db_and();
}
foreach ($tables as $falias => $tableinfo) {
$table = $tableinfo['table'];
if (!$table instanceof SelectQueryInterface && $table == $base_table) {
$subquery = db_select('file_managed', 'fm_access')
->fields('fm_access', array(
'fid',
));
$subquery_conditions = db_or();
$wrappers = file_entity_get_public_and_private_stream_wrapper_names();
if (!empty($wrappers['public'])) {
if (user_access('view files', $account)) {
foreach (array_keys($wrappers['public']) as $wrapper) {
$subquery_conditions
->condition('fm_access.uri', $wrapper . '%', 'LIKE');
}
}
elseif (user_access('view own files', $account)) {
foreach (array_keys($wrappers['public']) as $wrapper) {
$subquery_conditions
->condition(db_and()
->condition('fm_access.uri', $wrapper . '%', 'LIKE')
->condition('fm_access.uid', $account->uid));
}
}
}
if (!empty($wrappers['private'])) {
if (user_access('view private files', $account)) {
foreach (array_keys($wrappers['private']) as $wrapper) {
$subquery_conditions
->condition('fm_access.uri', $wrapper . '%', 'LIKE');
}
}
elseif (user_access('view own private files', $account)) {
foreach (array_keys($wrappers['private']) as $wrapper) {
$subquery_conditions
->condition(db_and()
->condition('fm_access.uri', $wrapper . '%', 'LIKE')
->condition('fm_access.uid', $account->uid));
}
}
}
if ($subquery_conditions
->count()) {
$subquery
->condition($subquery_conditions);
$field = 'fid';
// Now handle entities.
if ($type == 'entity') {
// Set a common alias for entities.
$base_alias = $falias;
$field = 'entity_id';
}
$subquery
->where("{$falias}.{$field} = fm_access.fid");
// For an entity query, attach the subquery to entity conditions.
if ($type == 'entity') {
$file_conditions
->exists($subquery);
}
elseif ($table == 'file_managed') {
// Fix for https://drupal.org/node/2073085
$db_or = db_or();
$db_or
->exists($subquery);
$db_or
->isNull($falias . '.' . $field);
$query
->condition($db_or);
}
else {
$query
->exists($subquery);
}
}
}
}
if ($type == 'entity' && $file_conditions
->count()) {
// All the file access conditions are only for field values belonging to
// files.
$file_conditions
->condition("{$base_alias}.entity_type", 'file');
$or = db_or();
$or
->condition($file_conditions);
// If the field value belongs to a non-file entity type then this function
// does not do anything with it.
$or
->condition("{$base_alias}.entity_type", 'file', '<>');
// Add the compiled set of rules to the query.
$query
->condition($or);
}
}