filehash.module in File Hash 8
Same filename and directory in other branches
Generate hashes for each uploaded file.
File
filehash.moduleView source
<?php
/**
* @file
* Generate hashes for each uploaded file.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function filehash_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.filehash':
return [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t('File Hash module generates and stores MD5, SHA-1 and/or SHA-256 hashes for each file uploaded to the site. Hashes allow files to be uniquely identified, duplicate files to be detected, and copies to be verified against the original source.'),
];
}
}
/**
* Returns array of enabled hash algorithms.
*/
function filehash_algos() {
return array_diff(\Drupal::config('filehash.settings')
->get('algos'), [
0,
]);
}
/**
* Implements hook_ENTITY_TYPE_create().
*/
function filehash_file_create(EntityInterface $file) {
filehash_hash($file);
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function filehash_file_delete(EntityInterface $file) {
\Drupal::database()
->delete('filehash')
->condition('fid', $file
->id())
->execute();
}
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function filehash_file_insert(EntityInterface $file) {
filehash_save($file);
}
/**
* Implements hook_ENTITY_TYPE_load().
*/
function filehash_file_load($files) {
$algos = filehash_algos();
if (!$algos) {
return;
}
$result = \Drupal::database()
->select('filehash')
->fields('filehash')
->condition('fid', array_keys($files), 'IN')
->execute();
foreach ($result as $record) {
foreach ($algos as $algo) {
$files[$record->fid]->filehash[$algo] = $record->{$algo};
}
}
// Generate hash if it does not already exist for the file.
foreach ($files as $fid => $file) {
foreach ($algos as $algo) {
if (empty($file->filehash[$algo])) {
filehash_hash($files[$fid]);
filehash_save($files[$fid]);
break;
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function filehash_file_presave(EntityInterface $file) {
filehash_hash($file);
}
/**
* Implements hook_ENTITY_TYPE_update().
*/
function filehash_file_update(EntityInterface $file) {
filehash_save($file);
}
/**
* Implements hook_file_validate().
*/
function filehash_file_validate(FileInterface $file) {
return \Drupal::config('filehash.settings')
->get('dedupe') ? filehash_validate_dedupe($file) : [];
}
/**
* Checks that file is not a duplicate.
*/
function filehash_validate_dedupe(FileInterface $file) {
$errors = [];
// We only run the dedupe check on initial file creation.
if (!$file
->id()) {
foreach (filehash_algos() as $algo) {
$query = \Drupal::database()
->select('filehash');
$query
->addField('filehash', 'fid');
$query
->condition($algo, $file->filehash[$algo]);
$query
->range(0, 1);
if ($fid = $query
->execute()
->fetchField()) {
$error = t('Sorry, duplicate files are not permitted.');
if (\Drupal::currentUser()
->hasPermission('access files overview')) {
try {
$url = Url::fromRoute('view.files.page_2', [
'arg_0' => $fid,
], [
'attributes' => [
'target' => '_blank',
],
]);
$error = t('This file has already been uploaded as %filename.', [
'%filename' => Link::fromTextAndUrl(File::load($fid)
->label(), $url)
->toString(),
]);
} catch (Exception $e) {
// Maybe the view was disabled?
}
}
$errors[] = $error;
break;
}
}
}
return $errors;
}
/**
* Calculates the file hashes.
*/
function filehash_hash($file) {
$file->filehash = array_fill_keys([
'md5',
'sha1',
'sha256',
], NULL);
// Unreadable files will have NULL hash values.
if (!is_readable($file
->getFileUri())) {
return;
}
foreach (filehash_algos() as $algo) {
$file->filehash[$algo] = hash_file($algo, $file
->getFileUri());
}
}
/**
* Returns array of human-readable hash algorithm names.
*/
function filehash_names() {
return [
'md5' => t('MD5'),
'sha1' => t('SHA-1'),
'sha256' => t('SHA-256'),
];
}
/**
* Implements hook_ENTITY_TYPE_build_defaults_alter().
*/
function filehash_node_build_defaults_alter(array &$build, EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
if ($view_mode != 'rss') {
return;
}
// The <media:hash> element only supports MD5 and SHA-1.
$algos = filehash_algos();
if (!isset($algos['md5']) && !isset($algos['sha1'])) {
return;
}
// The following field types are currently supported.
$fields = \Drupal::entityTypeManager()
->getStorage('field_config')
->loadByProperties([
'entity_type' => 'node',
'bundle' => $node
->bundle(),
'field_type' => 'file',
]);
$fields += \Drupal::entityTypeManager()
->getStorage('field_config')
->loadByProperties([
'entity_type' => 'node',
'bundle' => $node
->bundle(),
'field_type' => 'image',
]);
foreach ($fields as $field) {
if (method_exists($field, 'getName')) {
foreach ($node->{$field
->getName()} as $item) {
if ($item
->isDisplayed()) {
// Add <media:hash> elements for at most one file per RSS item.
$file = File::load($item->target_id);
filehash_rss_elements($file, $node);
return;
}
}
}
}
}
/**
* Adds <media:hash> RSS elements to $node object.
*/
function filehash_rss_elements($file, $node) {
$names = [
'md5' => 'md5',
'sha1' => 'sha-1',
];
foreach ($names as $algo => $name) {
if (!empty($file->filehash[$algo])) {
$node->rss_elements[] = [
'key' => 'media:hash',
'attributes' => [
'algo' => $name,
],
'value' => $file->filehash[$algo],
];
}
}
$node->rss_namespaces['xmlns:media'] = 'http://search.yahoo.com/mrss/';
}
/**
* Saves the file hashes.
*/
function filehash_save(FileInterface $file) {
\Drupal::database()
->merge('filehash')
->key([
'fid' => $file
->id(),
])
->fields($file->filehash)
->execute();
}
Functions
Name | Description |
---|---|
filehash_algos | Returns array of enabled hash algorithms. |
filehash_file_create | Implements hook_ENTITY_TYPE_create(). |
filehash_file_delete | Implements hook_ENTITY_TYPE_delete(). |
filehash_file_insert | Implements hook_ENTITY_TYPE_insert(). |
filehash_file_load | Implements hook_ENTITY_TYPE_load(). |
filehash_file_presave | Implements hook_ENTITY_TYPE_presave(). |
filehash_file_update | Implements hook_ENTITY_TYPE_update(). |
filehash_file_validate | Implements hook_file_validate(). |
filehash_hash | Calculates the file hashes. |
filehash_help | Implements hook_help(). |
filehash_names | Returns array of human-readable hash algorithm names. |
filehash_node_build_defaults_alter | Implements hook_ENTITY_TYPE_build_defaults_alter(). |
filehash_rss_elements | Adds <media:hash> RSS elements to $node object. |
filehash_save | Saves the file hashes. |
filehash_validate_dedupe | Checks that file is not a duplicate. |