First commit
60
modules/file/file.api.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks for file module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Control download access to files.
|
||||
*
|
||||
* The hook is typically implemented to limit access based on the entity the
|
||||
* file is referenced, e.g., only users with access to a node should be allowed
|
||||
* to download files attached to that node.
|
||||
*
|
||||
* @param array $file_item
|
||||
* The array of information about the file to check access for.
|
||||
* @param $entity_type
|
||||
* The type of $entity; for example, 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The $entity to which $file is referenced.
|
||||
*
|
||||
* @return
|
||||
* TRUE is access should be allowed by this entity or FALSE if denied. Note
|
||||
* that denial may be overridden by another entity controller, making this
|
||||
* grant permissive rather than restrictive.
|
||||
*
|
||||
* @see hook_field_access().
|
||||
*/
|
||||
function hook_file_download_access($file_item, $entity_type, $entity) {
|
||||
if ($entity_type == 'node') {
|
||||
return node_access('view', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the access rules applied to a file download.
|
||||
*
|
||||
* Entities that implement file management set the access rules for their
|
||||
* individual files. Module may use this hook to create custom access rules
|
||||
* for file downloads.
|
||||
*
|
||||
* @see hook_file_download_access().
|
||||
*
|
||||
* @param $grants
|
||||
* An array of grants gathered by hook_file_download_access(). The array is
|
||||
* keyed by the module that defines the entity type's access control; the
|
||||
* values are Boolean grant responses for each module.
|
||||
* @param array $file_item
|
||||
* The array of information about the file to alter access for.
|
||||
* @param $entity_type
|
||||
* The type of $entity; for example, 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The $entity to which $file is referenced.
|
||||
*/
|
||||
function hook_file_download_access_alter(&$grants, $file_item, $entity_type, $entity) {
|
||||
// For our example module, we always enforce the rules set by node module.
|
||||
if (isset($grants['node'])) {
|
||||
$grants = array('node' => $grants['node']);
|
||||
}
|
||||
}
|
35
modules/file/file.css
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @file
|
||||
* Admin stylesheet for file module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Managed file element styles.
|
||||
*/
|
||||
.form-managed-file .form-file,
|
||||
.form-managed-file .form-submit {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form-managed-file input.progress-disabled {
|
||||
float: none;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.form-managed-file div.ajax-progress,
|
||||
.form-managed-file div.throbber {
|
||||
display: inline;
|
||||
float: none;
|
||||
padding: 1px 5px 2px 5px;
|
||||
}
|
||||
|
||||
.form-managed-file div.ajax-progress-bar {
|
||||
display: none;
|
||||
margin-top: 4px;
|
||||
width: 28em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form-managed-file div.ajax-progress-bar div.bar {
|
||||
margin: 0;
|
||||
}
|
1031
modules/file/file.field.inc
Normal file
13
modules/file/file.info
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = File
|
||||
description = Defines a file field type.
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
dependencies[] = field
|
||||
files[] = tests/file.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
98
modules/file/file.install
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for File module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema().
|
||||
*/
|
||||
function file_field_schema($field) {
|
||||
return array(
|
||||
'columns' => array(
|
||||
'fid' => array(
|
||||
'description' => 'The {file_managed}.fid being referenced in this field.',
|
||||
'type' => 'int',
|
||||
'not null' => FALSE,
|
||||
'unsigned' => TRUE,
|
||||
),
|
||||
'display' => array(
|
||||
'description' => 'Flag to control whether this file should be displayed when viewing content.',
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 1,
|
||||
),
|
||||
'description' => array(
|
||||
'description' => 'A description of the file.',
|
||||
'type' => 'text',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'fid' => array('fid'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'fid' => array(
|
||||
'table' => 'file_managed',
|
||||
'columns' => array('fid' => 'fid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*
|
||||
* Display information about getting upload progress bars working.
|
||||
*/
|
||||
function file_requirements($phase) {
|
||||
$requirements = array();
|
||||
|
||||
// Check the server's ability to indicate upload progress.
|
||||
if ($phase == 'runtime') {
|
||||
$implementation = file_progress_implementation();
|
||||
$apache = strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== FALSE;
|
||||
$fastcgi = strpos($_SERVER['SERVER_SOFTWARE'], 'mod_fastcgi') !== FALSE || strpos($_SERVER["SERVER_SOFTWARE"], 'mod_fcgi') !== FALSE;
|
||||
$description = NULL;
|
||||
if (!$apache) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php.');
|
||||
$severity = REQUIREMENT_INFO;
|
||||
}
|
||||
elseif ($fastcgi) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php and not as FastCGI.');
|
||||
$severity = REQUIREMENT_INFO;
|
||||
}
|
||||
elseif (!$implementation && extension_loaded('apc')) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is capable of displaying file upload progress through APC, but it is not enabled. Add <code>apc.rfc1867 = 1</code> to your php.ini configuration. Alternatively, it is recommended to use <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>, which supports more than one simultaneous upload.');
|
||||
$severity = REQUIREMENT_INFO;
|
||||
}
|
||||
elseif (!$implementation) {
|
||||
$value = t('Not enabled');
|
||||
$description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a> (preferred) or to install <a href="http://us2.php.net/apc">APC</a>.');
|
||||
$severity = REQUIREMENT_INFO;
|
||||
}
|
||||
elseif ($implementation == 'apc') {
|
||||
$value = t('Enabled (<a href="http://php.net/manual/en/apc.configuration.php#ini.apc.rfc1867">APC RFC1867</a>)');
|
||||
$description = t('Your server is capable of displaying file upload progress using APC RFC1867. Note that only one upload at a time is supported. It is recommended to use the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a> if possible.');
|
||||
$severity = REQUIREMENT_OK;
|
||||
}
|
||||
elseif ($implementation == 'uploadprogress') {
|
||||
$value = t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
|
||||
$severity = REQUIREMENT_OK;
|
||||
}
|
||||
$requirements['file_progress'] = array(
|
||||
'title' => t('Upload progress'),
|
||||
'value' => $value,
|
||||
'severity' => $severity,
|
||||
'description' => $description,
|
||||
);
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
155
modules/file/file.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* @file
|
||||
* Provides JavaScript additions to the managed file field type.
|
||||
*
|
||||
* This file provides progress bar support (if available), popup windows for
|
||||
* file previews, and disabling of other file fields during Ajax uploads (which
|
||||
* prevents separate file fields from accidentally uploading files).
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
/**
|
||||
* Attach behaviors to managed file element upload fields.
|
||||
*/
|
||||
Drupal.behaviors.fileValidateAutoAttach = {
|
||||
attach: function (context, settings) {
|
||||
if (settings.file && settings.file.elements) {
|
||||
$.each(settings.file.elements, function(selector) {
|
||||
var extensions = settings.file.elements[selector];
|
||||
$(selector, context).bind('change', {extensions: extensions}, Drupal.file.validateExtension);
|
||||
});
|
||||
}
|
||||
},
|
||||
detach: function (context, settings) {
|
||||
if (settings.file && settings.file.elements) {
|
||||
$.each(settings.file.elements, function(selector) {
|
||||
$(selector, context).unbind('change', Drupal.file.validateExtension);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach behaviors to the file upload and remove buttons.
|
||||
*/
|
||||
Drupal.behaviors.fileButtons = {
|
||||
attach: function (context) {
|
||||
$('input.form-submit', context).bind('mousedown', Drupal.file.disableFields);
|
||||
$('div.form-managed-file input.form-submit', context).bind('mousedown', Drupal.file.progressBar);
|
||||
},
|
||||
detach: function (context) {
|
||||
$('input.form-submit', context).unbind('mousedown', Drupal.file.disableFields);
|
||||
$('div.form-managed-file input.form-submit', context).unbind('mousedown', Drupal.file.progressBar);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach behaviors to links within managed file elements.
|
||||
*/
|
||||
Drupal.behaviors.filePreviewLinks = {
|
||||
attach: function (context) {
|
||||
$('div.form-managed-file .file a, .file-widget .file a', context).bind('click',Drupal.file.openInNewWindow);
|
||||
},
|
||||
detach: function (context){
|
||||
$('div.form-managed-file .file a, .file-widget .file a', context).unbind('click', Drupal.file.openInNewWindow);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* File upload utility functions.
|
||||
*/
|
||||
Drupal.file = Drupal.file || {
|
||||
/**
|
||||
* Client-side file input validation of file extensions.
|
||||
*/
|
||||
validateExtension: function (event) {
|
||||
// Remove any previous errors.
|
||||
$('.file-upload-js-error').remove();
|
||||
|
||||
// Add client side validation for the input[type=file].
|
||||
var extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
|
||||
if (extensionPattern.length > 1 && this.value.length > 0) {
|
||||
var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi');
|
||||
if (!acceptableMatch.test(this.value)) {
|
||||
var error = Drupal.t("The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.", {
|
||||
// According to the specifications of HTML5, a file upload control
|
||||
// should not reveal the real local path to the file that a user
|
||||
// has selected. Some web browsers implement this restriction by
|
||||
// replacing the local path with "C:\fakepath\", which can cause
|
||||
// confusion by leaving the user thinking perhaps Drupal could not
|
||||
// find the file because it messed up the file path. To avoid this
|
||||
// confusion, therefore, we strip out the bogus fakepath string.
|
||||
'%filename': this.value.replace('C:\\fakepath\\', ''),
|
||||
'%extensions': extensionPattern.replace(/\|/g, ', ')
|
||||
});
|
||||
$(this).closest('div.form-managed-file').prepend('<div class="messages error file-upload-js-error" aria-live="polite">' + error + '</div>');
|
||||
this.value = '';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Prevent file uploads when using buttons not intended to upload.
|
||||
*/
|
||||
disableFields: function (event){
|
||||
var clickedButton = this;
|
||||
|
||||
// Only disable upload fields for Ajax buttons.
|
||||
if (!$(clickedButton).hasClass('ajax-processed')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're working with an "Upload" button.
|
||||
var $enabledFields = [];
|
||||
if ($(this).closest('div.form-managed-file').length > 0) {
|
||||
$enabledFields = $(this).closest('div.form-managed-file').find('input.form-file');
|
||||
}
|
||||
|
||||
// Temporarily disable upload fields other than the one we're currently
|
||||
// working with. Filter out fields that are already disabled so that they
|
||||
// do not get enabled when we re-enable these fields at the end of behavior
|
||||
// processing. Re-enable in a setTimeout set to a relatively short amount
|
||||
// of time (1 second). All the other mousedown handlers (like Drupal's Ajax
|
||||
// behaviors) are excuted before any timeout functions are called, so we
|
||||
// don't have to worry about the fields being re-enabled too soon.
|
||||
// @todo If the previous sentence is true, why not set the timeout to 0?
|
||||
var $fieldsToTemporarilyDisable = $('div.form-managed-file input.form-file').not($enabledFields).not(':disabled');
|
||||
$fieldsToTemporarilyDisable.attr('disabled', 'disabled');
|
||||
setTimeout(function (){
|
||||
$fieldsToTemporarilyDisable.attr('disabled', false);
|
||||
}, 1000);
|
||||
},
|
||||
/**
|
||||
* Add progress bar support if possible.
|
||||
*/
|
||||
progressBar: function (event) {
|
||||
var clickedButton = this;
|
||||
var $progressId = $(clickedButton).closest('div.form-managed-file').find('input.file-progress');
|
||||
if ($progressId.length) {
|
||||
var originalName = $progressId.attr('name');
|
||||
|
||||
// Replace the name with the required identifier.
|
||||
$progressId.attr('name', originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0]);
|
||||
|
||||
// Restore the original name after the upload begins.
|
||||
setTimeout(function () {
|
||||
$progressId.attr('name', originalName);
|
||||
}, 1000);
|
||||
}
|
||||
// Show the progress bar if the upload takes longer than half a second.
|
||||
setTimeout(function () {
|
||||
$(clickedButton).closest('div.form-managed-file').find('div.ajax-progress-bar').slideDown();
|
||||
}, 500);
|
||||
},
|
||||
/**
|
||||
* Open links to files within forms in a new window.
|
||||
*/
|
||||
openInNewWindow: function (event) {
|
||||
$(this).attr('target', '_blank');
|
||||
window.open(this.href, 'filePreview', 'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
1094
modules/file/file.module
Normal file
BIN
modules/file/icons/application-octet-stream.png
Normal file
After Width: | Height: | Size: 189 B |
BIN
modules/file/icons/application-pdf.png
Normal file
After Width: | Height: | Size: 346 B |
BIN
modules/file/icons/application-x-executable.png
Normal file
After Width: | Height: | Size: 189 B |
BIN
modules/file/icons/audio-x-generic.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
modules/file/icons/image-x-generic.png
Normal file
After Width: | Height: | Size: 385 B |
BIN
modules/file/icons/package-x-generic.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
modules/file/icons/text-html.png
Normal file
After Width: | Height: | Size: 265 B |
BIN
modules/file/icons/text-plain.png
Normal file
After Width: | Height: | Size: 220 B |
BIN
modules/file/icons/text-x-generic.png
Normal file
After Width: | Height: | Size: 220 B |
BIN
modules/file/icons/text-x-script.png
Normal file
After Width: | Height: | Size: 276 B |
BIN
modules/file/icons/video-x-generic.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
modules/file/icons/x-office-document.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
modules/file/icons/x-office-presentation.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
modules/file/icons/x-office-spreadsheet.png
Normal file
After Width: | Height: | Size: 183 B |
1804
modules/file/tests/file.test
Normal file
12
modules/file/tests/file_module_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = File test
|
||||
description = Provides hooks for testing File module functionality.
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
69
modules/file/tests/file_module_test.module
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides File module pages for testing purposes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function file_module_test_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['file/test'] = array(
|
||||
'title' => 'Managed file test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('file_module_test_form'),
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor for testing a 'managed_file' element.
|
||||
*
|
||||
* @see file_module_test_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function file_module_test_form($form, &$form_state, $tree = TRUE, $extended = FALSE, $default_fid = NULL) {
|
||||
$form['#tree'] = (bool) $tree;
|
||||
|
||||
$form['nested']['file'] = array(
|
||||
'#type' => 'managed_file',
|
||||
'#title' => t('Managed file'),
|
||||
'#upload_location' => 'public://test',
|
||||
'#progress_message' => t('Please wait...'),
|
||||
'#extended' => (bool) $extended,
|
||||
'#size' => 13,
|
||||
);
|
||||
if ($default_fid) {
|
||||
$form['nested']['file']['#default_value'] = $extended ? array('fid' => $default_fid) : $default_fid;
|
||||
}
|
||||
|
||||
$form['textfield'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Type a value and ensure it stays'),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for file_module_test_form().
|
||||
*/
|
||||
function file_module_test_form_submit($form, &$form_state) {
|
||||
if ($form['#tree']) {
|
||||
$fid = $form['nested']['file']['#extended'] ? $form_state['values']['nested']['file']['fid'] : $form_state['values']['nested']['file'];
|
||||
}
|
||||
else {
|
||||
$fid = $form['nested']['file']['#extended'] ? $form_state['values']['file']['fid'] : $form_state['values']['file'];
|
||||
}
|
||||
drupal_set_message(t('The file id is %fid.', array('%fid' => $fid)));
|
||||
}
|