summaryrefslogtreecommitdiff
path: root/sites/all/modules/file_entity/file_entity.pages.inc
diff options
context:
space:
mode:
Diffstat (limited to 'sites/all/modules/file_entity/file_entity.pages.inc')
-rw-r--r--sites/all/modules/file_entity/file_entity.pages.inc1167
1 files changed, 1167 insertions, 0 deletions
diff --git a/sites/all/modules/file_entity/file_entity.pages.inc b/sites/all/modules/file_entity/file_entity.pages.inc
new file mode 100644
index 000000000..17688fee7
--- /dev/null
+++ b/sites/all/modules/file_entity/file_entity.pages.inc
@@ -0,0 +1,1167 @@
+<?php
+
+/**
+ * @file
+ * Supports file operations including View, Edit, and Delete.
+ */
+
+/**
+ * Menu callback; view a single file entity.
+ */
+function file_entity_view_page($file) {
+ drupal_set_title($file->filename);
+
+ $uri = entity_uri('file', $file);
+ // Set the file path as the canonical URL to prevent duplicate content.
+ drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
+ // Set the non-aliased path as a default shortlink.
+ drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
+
+ return file_view($file, 'full');
+}
+
+/**
+ * Menu callback; download a single file entity.
+ */
+function file_entity_download_page($file) {
+ // Ensure there is a valid token to download this file.
+ if (!variable_get('file_entity_allow_insecure_download', FALSE)) {
+ if (!isset($_GET['token']) || $_GET['token'] !== file_entity_get_download_token($file)) {
+ return MENU_ACCESS_DENIED;
+ }
+ }
+
+ // If the file does not exist it can cause problems with file_transfer().
+ if (!is_file($file->uri)) {
+ return MENU_NOT_FOUND;
+ }
+
+ $headers = array(
+ 'Content-Type' => mime_header_encode($file->filemime),
+ 'Content-Disposition' => 'attachment; filename="' . mime_header_encode(drupal_basename($file->uri)) . '"',
+ 'Content-Length' => $file->filesize,
+ 'Content-Transfer-Encoding' => 'binary',
+ 'Pragma' => 'no-cache',
+ 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
+ 'Expires' => '0',
+ );
+
+ // Let other modules alter the download headers.
+ drupal_alter('file_download_headers', $headers, $file);
+
+ // Let other modules know the file is being downloaded.
+ module_invoke_all('file_transfer', $file->uri, $headers);
+
+ if (file_entity_file_is_local($file)) {
+ // For local files, transfer the file and do not reveal the actual URL.
+ file_transfer($file->uri, $headers);
+ }
+ else {
+ // For remote files, just redirect the user to that file's actual URL.
+ $headers['Location'] = file_create_url($file->uri);
+ foreach ($headers as $name => $value) {
+ drupal_add_http_header($name, $value);
+ }
+ drupal_send_headers();
+ drupal_exit();
+ }
+}
+
+/**
+ * Form callback for adding a file via an upload form.
+ *
+ * This is a multi step form which has 1-3 pages:
+ * - Upload file
+ * - Choose filetype
+ * If there is only one candidate (based on mimetype) we will skip this step.
+ * - Edit fields
+ * Skip this step if there are no fields on this entity type.
+ */
+function file_entity_add_upload($form, &$form_state, array $options = array()) {
+ $step = (isset($form_state['step']) && in_array($form_state['step'], array(1, 2, 3, 4))) ? $form_state['step'] : 1;
+ $form['#step'] = $step;
+ $form['#options'] = $options;
+ switch ($step) {
+ case 1:
+ return file_entity_add_upload_step_upload($form, $form_state, $options);
+
+ case 2:
+ return file_entity_add_upload_step_filetype($form, $form_state, $options);
+
+ case 3:
+ return file_entity_add_upload_step_scheme($form, $form_state, $options);
+
+ case 4:
+ return file_entity_add_upload_step_fields($form, $form_state, $options);
+
+ }
+}
+
+/**
+ * Generate form fields for the first step in the add file wizard.
+ */
+function file_entity_add_upload_step_upload($form, &$form_state, array $options = array()) {
+ $form['upload'] = array(
+ '#type' => 'managed_file',
+ '#title' => t('Upload a new file'),
+ '#upload_location' => file_entity_upload_destination_uri($options),
+ '#upload_validators' => file_entity_get_upload_validators($options),
+ '#progress_indicator' => 'bar',
+ '#required' => TRUE,
+ '#pre_render' => array('file_managed_file_pre_render', 'file_entity_upload_validators_pre_render'),
+ '#default_value' => isset($form_state['storage']['upload']) ? $form_state['storage']['upload'] : NULL,
+ );
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['next'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ );
+
+ form_load_include($form_state, 'inc', 'file_entity', 'file_entity.pages');
+
+ return $form;
+}
+
+/**
+ * Generate form fields for the second step in the add file wizard.
+ */
+function file_entity_add_upload_step_filetype($form, &$form_state, array $options = array()) {
+ $file = file_load($form_state['storage']['upload']);
+
+ $form['type'] = array(
+ '#type' => 'radios',
+ '#title' => t('File type'),
+ '#options' => file_entity_get_filetype_candidates($file),
+ '#default_value' => isset($form_state['storage']['type']) ? $form_state['storage']['type'] : NULL,
+ '#required' => TRUE,
+ );
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['previous'] = array(
+ '#type' => 'submit',
+ '#value' => t('Previous'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('file_entity_add_upload_submit'),
+ );
+ $form['actions']['next'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ );
+
+ return $form;
+}
+
+/**
+ * Generate form fields for the third step in the add file wizard.
+ */
+function file_entity_add_upload_step_scheme($form, &$form_state, array $options = array()) {
+ $file = file_load($form_state['storage']['upload']);
+
+ $schemes = array();
+ foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $info) {
+ $schemes[$scheme] = check_plain($info['description']);
+ }
+
+ // Remove any schemes not found in the instance settings.
+ if (!empty($options['schemes'])) {
+ $schemes = array_intersect_key($schemes, array_flip($options['schemes']));
+ }
+
+ // Determine which scheme to use as the default value.
+ if (isset($form_state['storage']['scheme'])) {
+ $fallback_scheme = $form_state['storage']['scheme'];
+ }
+ elseif (!empty($options['uri_scheme'])) {
+ $fallback_scheme = $options['uri_scheme'];
+ }
+ else {
+ $fallback_scheme = file_default_scheme();
+ }
+
+ $form['scheme'] = array(
+ '#type' => 'radios',
+ '#title' => t('Destination'),
+ '#options' => $schemes,
+ '#default_value' => $fallback_scheme,
+ '#required' => TRUE,
+ );
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['previous'] = array(
+ '#type' => 'submit',
+ '#value' => t('Previous'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('file_entity_add_upload_submit'),
+ );
+ $form['actions']['next'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ );
+
+ return $form;
+}
+
+/**
+ * Generate form fields for the fourth step in the add file wizard.
+ */
+function file_entity_add_upload_step_fields($form, &$form_state, array $options = array()) {
+ // Load the file and overwrite the filetype set on the previous screen.
+ $file = file_load($form_state['storage']['upload']);
+ $file->type = $form_state['storage']['type'];
+
+ // Let users modify the filename here.
+ $form['filename'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Name'),
+ '#default_value' => $file->filename,
+ '#required' => TRUE,
+ '#maxlength' => 255,
+ '#weight' => -10,
+ );
+
+ // Add fields.
+ field_attach_form('file', $file, $form, $form_state);
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['previous'] = array(
+ '#type' => 'submit',
+ '#value' => t('Previous'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('file_entity_add_upload_submit'),
+ );
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ );
+
+ return $form;
+}
+
+/**
+ * Page callback to show file usage information.
+ */
+function file_entity_usage_page($file) {
+ $rows = array();
+ $occured_entities = array();
+
+ // Determine all of the locations where a file is used, then loop through the
+ // occurrences and filter out any duplicates.
+ foreach (file_usage_list($file) as $module => $type) {
+ foreach ($type as $entity_type => $entity_ids) {
+ // There are cases where the actual entity doesn't exist.
+ // We have to handle this.
+ $entity_info = entity_get_info($entity_type);
+ $entities = empty($entity_info) ? NULL : entity_load($entity_type, array_keys($entity_ids));
+
+ foreach ($entity_ids as $entity_id => $count) {
+ // If this entity has already been listed in the table, just add any
+ // additional usage to the total count column in the table row and
+ // continue on to the next iteration of the loop.
+ if (isset($occured_entities[$entity_type][$entity_id])) {
+ $rows[$occured_entities[$entity_type][$entity_id]][2] += $count;
+ continue;
+ }
+
+ // Retrieve the label and the URI of the entity.
+ $label = empty($entities[$entity_id]) ? $module : entity_label($entity_type, $entities[$entity_id]);
+ $entity_uri = empty($entities[$entity_id]) ? NULL : entity_uri($entity_type, $entities[$entity_id]);
+
+ // Link the label to the URI when possible.
+ if (empty($entity_uri)) {
+ $entity = check_plain($label);
+ }
+ else {
+ $entity = l($label, $entity_uri['path']);
+ }
+
+ $rows[] = array($entity, $entity_type, $count);
+
+ // Record the occurrence of the entity to ensure that it isn't listed in
+ // the table again.
+ $occured_entities[$entity_type][$entity_id] = count($rows) - 1;
+ }
+ }
+ }
+
+ $header = array(t('Entity'), t('Entity type'), t('Use count'));
+ $build['usage_table'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ '#caption' => t('This table lists all of the places where @filename is used.', array('@filename' => $file->filename)),
+ '#empty' => t('This file is not currently used.'),
+ );
+
+ return $build;
+}
+
+/**
+ * Get the candidate filetypes for a given file.
+ *
+ * Only filetypes for which the user has access to create entities are returned.
+ *
+ * @param array $file
+ * An upload file array from form_state.
+ *
+ * @return array
+ * An array of file type bundles that support the file's mime type.
+ */
+function file_entity_get_filetype_candidates($file) {
+ $types = module_invoke_all('file_type', $file);
+ drupal_alter('file_type', $types, $file);
+ $candidates = array();
+ foreach ($types as $type) {
+ $file->type = $type;
+ if (file_entity_access('create', $file)) {
+ $candidates[$type] = file_entity_type_get_name($file);
+ }
+ }
+ return $candidates;
+}
+
+/**
+ * Submit handler for the add file form.
+ */
+function file_entity_add_upload_submit($form, &$form_state) {
+ $form_state['storage'] = isset($form_state['storage']) ? $form_state['storage'] : array();
+ $form_state['storage'] = array_merge($form_state['storage'], $form_state['values']);
+
+ // This var is set to TRUE when we are ready to save the file.
+ $save = FALSE;
+ $trigger = $form_state['triggering_element']['#id'];
+
+ $steps_to_check = array(2, 3);
+ if ($trigger == 'edit-previous') {
+ // If the previous button was hit,
+ // the step checking order should be reversed 3, 2.
+ $steps_to_check = array_reverse($steps_to_check);
+ }
+
+ foreach ($steps_to_check as $step) {
+ // Check if we can skip step 2 and 3.
+ if (($form['#step'] == $step - 1 && $trigger == 'edit-next') || ($form['#step'] == $step + 1 && $trigger == 'edit-previous')) {
+ $file = file_load($form_state['storage']['upload']);
+ if ($step == 2) {
+ // Check if we can skip step 2.
+ $candidates = file_entity_get_filetype_candidates($file);
+ if (count($candidates) == 1) {
+ $candidates_keys = array_keys($candidates);
+ // There is only one possible filetype for this file.
+ // Skip the second page.
+ $form['#step'] += ($trigger == 'edit-previous') ? -1 : 1;
+ $form_state['storage']['type'] = reset($candidates_keys);
+ }
+ elseif (!$candidates || variable_get('file_entity_file_upload_wizard_skip_file_type', FALSE)) {
+ // Do not assign the file a file type.
+ $form['#step'] += ($trigger == 'edit-previous') ? -1 : 1;
+ $form_state['storage']['type'] = FILE_TYPE_NONE;
+ }
+ }
+ else {
+ // Check if we can skip step 3.
+ $options = $form['#options'];
+ $schemes = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
+
+ // Remove any schemes not found in the instance settings.
+ if (!empty($options['schemes'])) {
+ $schemes = array_intersect_key($schemes, $options['schemes']);
+ }
+
+ if (!file_entity_file_is_writeable($file)) {
+ // The file is read-only (remote) and must use its provided scheme.
+ $form['#step'] += ($trigger == 'edit-previous') ? -1 : 1;
+ $form_state['storage']['scheme'] = file_uri_scheme($file->uri);
+ }
+ elseif (count($schemes) == 1) {
+ // There is only one possible stream wrapper for this file.
+ // Skip the third page.
+ $form['#step'] += ($trigger == 'edit-previous') ? -1 : 1;
+ $form_state['storage']['scheme'] = key($schemes);
+ }
+ elseif (variable_get('file_entity_file_upload_wizard_skip_scheme', FALSE)) {
+ $form['#step'] += ($trigger == 'edit-previous') ? -1 : 1;
+
+ // Fallback to the URI scheme specified in the field settings
+ // otherwise use the default file scheme.
+ if (!empty($options['uri_scheme'])) {
+ $form_state['storage']['scheme'] = $options['uri_scheme'];
+ }
+ else {
+ $form_state['storage']['scheme'] = file_default_scheme();
+ }
+ }
+ }
+ }
+ }
+
+ // We have the filetype, check if we can skip step 4.
+ if (($form['#step'] == 3 && $trigger == 'edit-next')) {
+ $file = file_load($form_state['storage']['upload']);
+ if (!field_info_instances('file', $form_state['storage']['type'])) {
+ // This filetype doesn't have fields, save the file.
+ $save = TRUE;
+ }
+ elseif (variable_get('file_entity_file_upload_wizard_skip_fields', FALSE)) {
+ // Save the file with blanks fields.
+ $save = TRUE;
+ }
+ }
+
+ // Form id's can vary depending on how many other forms are displayed, so we
+ // need to do string comparissons. e.g edit-submit--2.
+ if (strpos($trigger, 'edit-next') !== FALSE) {
+ $form_state['step'] = $form['#step'] + 1;
+ }
+ elseif (strpos($trigger, 'edit-previous') !== FALSE) {
+ $form_state['step'] = $form['#step'] - 1;
+ }
+ elseif (strpos($trigger, 'edit-submit') !== FALSE) {
+ $save = TRUE;
+ }
+
+ if ($save) {
+ $file = file_load($form_state['storage']['upload']);
+ if ($file) {
+ if (file_uri_scheme($file->uri) != $form_state['storage']['scheme']) {
+ $file_destination = $form_state['storage']['scheme'] . '://' . file_uri_target($file->uri);
+ $file_destination = file_stream_wrapper_uri_normalize($file_destination);
+ if ($moved_file = file_move($file, $file_destination, FILE_EXISTS_RENAME)) {
+ // Only re-assign the file object if file_move() did not fail.
+ $file = $moved_file;
+ }
+ }
+ $file->type = $form_state['storage']['type'];
+ $file->display = TRUE;
+
+ // Change the file from temporary to permanent.
+ $file->status = FILE_STATUS_PERMANENT;
+
+ // Save the form fields.
+ // Keep in mind that the values for the Field API fields must be in
+ // $form_state['values'] and not in ['storage']. This is true as long as
+ // the fields are on the last page of the multi step form.
+ entity_form_submit_build_entity('file', $file, $form, $form_state);
+
+ file_save($file);
+ $form_state['file'] = $file;
+ drupal_set_message(t('@type %name was uploaded.', array('@type' => file_entity_type_get_name($file), '%name' => $file->filename)));
+ }
+ else {
+ drupal_set_message(t('An error occurred and no file was uploaded.'), 'error');
+ return;
+ }
+
+ // Figure out destination.
+ if (user_access('administer files')) {
+ $path = 'admin/content/file';
+ }
+ else {
+ $path = 'file/' . $file->fid;
+ }
+ $form_state['redirect'] = $path;
+ }
+ else {
+ $form_state['rebuild'] = TRUE;
+ }
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Determines the upload location for the file add upload form.
+ *
+ * @param array $params
+ * An array of parameters from the media browser.
+ * @param array $data
+ * (optional) An array of token objects to pass to token_replace().
+ *
+ * @return string
+ * A file directory URI with tokens replaced.
+ *
+ * @see token_replace()
+ */
+function file_entity_upload_destination_uri(array $params, array $data = array()) {
+ $params += array(
+ 'uri_scheme' => file_default_scheme(),
+ 'file_directory' => '',
+ );
+
+ $destination = trim($params['file_directory'], '/');
+
+ // Replace tokens.
+ $destination = token_replace($destination, $data);
+
+ return $params['uri_scheme'] . '://' . $destination;
+}
+
+/**
+ * Form for uploading multiple files.
+ */
+function file_entity_add_upload_multiple($form, &$form_state, $params = array()) {
+ $form = file_entity_add_upload($form, $form_state, $params);
+ unset($form['upload']['#title']);
+ // The validators will be set from plupload anyway. This isn't pretty,
+ // but don't allow it to show up twice.
+ unset($form['upload']['#description']);
+
+ $form['upload']['#type'] = 'plupload';
+
+ // Ensure that we call the plupload_element_pre_render function.
+ // If it isn't called, it doesn't set the JS settings that transfers the
+ // list of allowed file extentions to the PLUpload widget.
+ // We override the 'file_entity_upload_validators_pre_render' setting if it
+ // exists, because both pre-render hooks adds the upload-help with list of
+ // allowed file extensions.
+ $index = array_search('file_entity_upload_validators_pre_render', $form['upload']['#pre_render']);
+ if ($index !== FALSE) {
+ $form['upload']['#pre_render'][$index] = 'plupload_element_pre_render';
+ }
+ else {
+ $form['upload']['#pre_render'][] = 'plupload_element_pre_render';
+ }
+
+ $form['submit']['#value'] = t('Start upload');
+ return $form;
+}
+
+/**
+ * Submit handler for the multiple upload form.
+ */
+function file_entity_add_upload_multiple_submit($form, &$form_state) {
+ $upload_location = !empty($form['upload']['#upload_location']) ?
+ $form['upload']['#upload_location'] . '/' :
+ variable_get('file_default_scheme', 'public') . '://';
+
+ // Ensure writable destination directory for the files.
+ file_prepare_directory($upload_location, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+ // We can't use file_save_upload() because of
+ // http://www.jacobsingh.name/content/tight-coupling-no-not.
+ foreach ($form_state['values']['upload'] as $uploaded_file) {
+ if ($uploaded_file['status'] == 'done') {
+ $source = $uploaded_file['tmppath'];
+ $destination = file_stream_wrapper_uri_normalize($upload_location . $uploaded_file['name']);
+ // Rename it to its original name, and put it in its final home.
+ // Note - not using file_move here because if we call file_get_mime
+ // (in file_uri_to_object) while it has a .tmp extension, it horks.
+ $destination = file_unmanaged_move($source, $destination, FILE_EXISTS_RENAME);
+
+ $file = file_uri_to_object($destination);
+ $file->status = FILE_STATUS_PERMANENT;
+ file_save($file);
+
+ $form_state['files'][$file->fid] = $file;
+ }
+ else {
+ // @todo: move this to element validate or something.
+ form_set_error('pud', t('The specified file %name could not be uploaded.', array('%name' => $uploaded_file['name'])));
+ }
+ }
+
+ // Redirect to the file edit page.
+ if (file_entity_access('update', $file) && module_exists('media_bulk_upload')) {
+ $destination = array();
+ if (isset($_GET['destination'])) {
+ $destination = drupal_get_destination();
+ unset($_GET['destination']);
+ }
+ elseif (user_access('administer files')) {
+ $destination = array('destination' => 'admin/content/file');
+ }
+ $form_state['redirect'] = array('admin/content/file/edit-multiple/' . implode(' ', array_keys($form_state['files'])), array('query' => $destination));
+ }
+ else {
+ $form_state['redirect'] = user_access('administer files') ? 'admin/content/file' : '<front>';
+ }
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Page callback: Form constructor for the file edit form.
+ *
+ * Path: file/%file/edit
+ *
+ * @param object $file
+ * A file object from file_load().
+ *
+ * @see file_entity_menu()
+ *
+ * @todo Rename this form to file_edit_form to ease into core.
+ */
+function file_entity_edit($form, &$form_state, $file) {
+ drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $file->type, '@title' => $file->filename)), PASS_THROUGH);
+
+ $form_state['file'] = $file;
+
+ $form['#attributes']['class'][] = 'file-form';
+ if (!empty($file->type)) {
+ $form['#attributes']['class'][] = 'file-' . $file->type . '-form';
+ }
+
+ // Basic file information.
+ // These elements are just values so they are not even sent to the client.
+ foreach (array('fid', 'type', 'uid', 'timestamp') as $key) {
+ $form[$key] = array(
+ '#type' => 'value',
+ '#value' => isset($file->$key) ? $file->$key : NULL,
+ );
+ }
+
+ $form['filename'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Name'),
+ '#default_value' => $file->filename,
+ '#required' => TRUE,
+ '#maxlength' => 255,
+ '#weight' => -10,
+ );
+
+ // Add a 'replace this file' upload field if the file is writeable.
+ if (file_entity_file_is_writeable($file)) {
+ // Set up replacement file validation.
+ $replacement_options = array();
+
+ // The replacement file must have an extension valid for the original type.
+ $file_extensions = array();
+ $file_type_name = isset($file->type) ? $file->type : file_get_type($file);
+ if ($file_type_name && ($file_type = file_type_load($file_type_name))) {
+ $file_extensions = file_type_get_valid_extensions($file_type);
+ }
+
+ // Set allowed file extensions.
+ if (!empty($file_extensions)) {
+ // Set to type based file extensions.
+ $replacement_options['file_extensions'] = implode(' ', $file_extensions);
+ }
+ else {
+ // Fallback to the extension of the current file.
+ $replacement_options['file_extensions'] = pathinfo($file->uri, PATHINFO_EXTENSION);
+ }
+
+ $form['replace_upload'] = array(
+ '#type' => 'file',
+ '#title' => t('Replace file'),
+ '#description' => t('This file will replace the existing file. This action cannot be undone.'),
+ '#upload_validators' => file_entity_get_upload_validators($replacement_options),
+ '#pre_render' => array('file_entity_upload_validators_pre_render'),
+ );
+ }
+
+ $form['preview'] = file_view_file($file, 'preview');
+
+ $form['additional_settings'] = array(
+ '#type' => 'vertical_tabs',
+ '#weight' => 99,
+ );
+
+ // File destination information for administrators.
+ $form['destination'] = array(
+ '#type' => 'fieldset',
+ '#access' => user_access('administer files') && file_entity_file_is_writeable($file),
+ '#title' => t('Destination'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#group' => 'additional_settings',
+ '#attributes' => array(
+ 'class' => array('file-form-destination'),
+ ),
+ '#attached' => array(
+ 'js' => array(
+ drupal_get_path('module', 'file_entity') . '/file_entity.js',
+ ),
+ ),
+ );
+
+ $options = array();
+ foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $info) {
+ $options[$scheme] = check_plain($info['name']);
+ }
+
+ $form['destination']['scheme'] = array(
+ '#type' => 'radios',
+ '#title' => t('Destination'),
+ '#options' => $options,
+ '#default_value' => file_uri_scheme($file->uri),
+ );
+
+ // File user information for administrators.
+ $form['user'] = array(
+ '#type' => 'fieldset',
+ '#access' => user_access('administer files'),
+ '#title' => t('User information'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#group' => 'additional_settings',
+ '#attributes' => array(
+ 'class' => array('file-form-user'),
+ ),
+ '#attached' => array(
+ 'js' => array(
+ drupal_get_path('module', 'file_entity') . '/file_entity.js',
+ array(
+ 'type' => 'setting',
+ 'data' => array('anonymous' => variable_get('anonymous', t('Anonymous'))),
+ ),
+ ),
+ ),
+ '#weight' => 90,
+ );
+ $form['user']['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Associated with'),
+ '#maxlength' => 60,
+ '#autocomplete_path' => 'user/autocomplete',
+ '#default_value' => !empty($file->uid) ? user_load($file->uid)->name : '',
+ '#weight' => -1,
+ '#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
+ );
+
+ // Add the buttons.
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ '#weight' => 5,
+ '#submit' => array('file_entity_edit_submit'),
+ '#validate' => array('file_entity_edit_validate'),
+ );
+ $form['actions']['delete'] = array(
+ '#type' => 'submit',
+ '#value' => t('Delete'),
+ '#weight' => 10,
+ '#submit' => array('file_entity_edit_delete_submit'),
+ '#access' => file_entity_access('delete', $file),
+ );
+
+ // Build the URL for the cancel button taking into account that there might be
+ // a "destination" that includes query string variables.
+ $parameters = drupal_get_query_parameters();
+ $destination = isset($parameters['destination']) ? $parameters['destination'] : 'file/' . $file->fid;
+ $url = drupal_parse_url($destination);
+
+ $form['actions']['cancel'] = array(
+ '#type' => 'link',
+ '#title' => t('Cancel'),
+ '#href' => $url['path'],
+ '#options' => array('query' => $url['query']),
+ '#weight' => 15,
+ );
+
+ $langcode = function_exists('entity_language') ? entity_language('file', $file) : NULL;
+ field_attach_form('file', $file, $form, $form_state, $langcode);
+
+ return $form;
+}
+
+/**
+ * Form validation handler for file_entity_edit().
+ */
+function file_entity_edit_validate($form, &$form_state) {
+ $file = (object) $form_state['values'];
+
+ // Validate the "associated user" field.
+ if (!empty($file->name) && !($account = user_load_by_name($file->name))) {
+ // The use of empty() is mandatory in the context of usernames
+ // as the empty string denotes the anonymous user. In case we
+ // are dealing with an anonymous user we set the user ID to 0.
+ form_set_error('name', t('The username %name does not exist.', array('%name' => $file->name)));
+ }
+
+ // Handle the replacement file if uploaded.
+ if (isset($form_state['values']['replace_upload'])) {
+ // Save the file as a temporary file.
+ $file = file_save_upload('replace_upload', $form['replace_upload']['#upload_validators']);
+ if (!empty($file)) {
+ // Put the temporary file in form_values so we can save it on submit.
+ $form_state['values']['replace_upload'] = $file;
+ }
+ elseif ($file === FALSE) {
+ // File uploaded failed.
+ form_set_error('replace_upload', t('The replacement file could not be uploaded.'));
+ }
+ }
+
+ // Run entity form validation.
+ entity_form_field_validate('file', $form, $form_state);
+}
+
+/**
+ * Form submission handler for the 'Save' button for file_entity_edit().
+ */
+function file_entity_edit_submit($form, &$form_state) {
+ $file = $form_state['file'];
+ $orphaned_uri = '';
+
+ // Check if a replacement file has been uploaded.
+ if (!empty($form_state['values']['replace_upload'])) {
+ $replacement = $form_state['values']['replace_upload'];
+ // Move file from temp to permanent home.
+ $destination_uri = rtrim($file->uri, drupal_basename($file->uri)) . drupal_basename($replacement->uri);
+ $replace_mode = $destination_uri == $file->uri ? FILE_EXISTS_REPLACE : FILE_EXISTS_RENAME;
+ if ($new_file_uri = file_unmanaged_copy($replacement->uri, $destination_uri, $replace_mode)) {
+ // @todo Add watchdog() about replaced file here?
+
+ // Remove temporary file.
+ file_delete($replacement);
+
+ // Update if the uri target has changed.
+ if ($new_file_uri != $file->uri) {
+ // Store the original file uri to delete if save is sucessful.
+ $orphaned_uri = $file->uri;
+
+ // Update file entity uri.
+ $file->uri = $new_file_uri;
+ }
+ }
+ }
+
+ // Run entity form submit handling and save the file.
+ entity_form_submit_build_entity('file', $file, $form, $form_state);
+
+ // A user might assign the associated user by entering a user name in the file
+ // edit form, which we then need to translate to a user ID.
+ if (isset($file->name)) {
+ // The use of isset() is mandatory in the context of user IDs, because
+ // user ID 0 denotes the anonymous user.
+ if ($user = user_load_by_name($file->name)) {
+ $file->uid = $user->uid;
+ }
+ else {
+ // Anonymous user.
+ $file->uid = 0;
+ }
+ }
+ elseif ($file->uid) {
+ $user = user_load($file->uid);
+ $file->name = $user->name;
+ }
+
+ if (file_uri_scheme($file->uri) != $form_state['values']['scheme']) {
+ $file_destination = $form_state['storage']['scheme'] . '://' . file_uri_target($file->uri);
+ $file_destination = file_stream_wrapper_uri_normalize($file_destination);
+ if ($moved_file = file_move($file, $file_destination, FILE_EXISTS_RENAME)) {
+ // Only re-assign the file object if file_move() did not fail.
+ $file = $moved_file;
+ }
+ }
+
+ file_save($file);
+
+ $args = array(
+ '@type' => file_entity_type_get_name($file),
+ '%title' => entity_label('file', $file),
+ );
+ watchdog('file', '@type: updated %title.', $args);
+ drupal_set_message(t('@type %title has been updated.', $args));
+
+ // Clean up orphaned file.
+ if (!empty($orphaned_uri)) {
+ file_unmanaged_delete($orphaned_uri);
+
+ $args['@orphaned'] = file_uri_target($orphaned_uri);
+ watchdog('file', '@type: deleted orphaned file @orphaned for %title.', $args);
+ drupal_set_message(t('The replaced @type @orphaned has been deleted.', $args));
+ }
+
+ $form_state['redirect'] = 'file/' . $file->fid;
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Form submission handler for the 'Delete' button for file_entity_edit().
+ */
+function file_entity_edit_delete_submit($form, &$form_state) {
+ $fid = $form_state['values']['fid'];
+ $destination = array();
+ if (isset($_GET['destination'])) {
+ $destination = drupal_get_destination();
+ unset($_GET['destination']);
+ }
+ $form_state['redirect'] = array('file/' . $fid . '/delete', array('query' => $destination));
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Page callback: Form constructor for the file deletion confirmation form.
+ *
+ * Path: file/%file/delete
+ *
+ * @param object $file
+ * A file object from file_load().
+ *
+ * @see file_entity_menu()
+ */
+function file_entity_delete_form($form, &$form_state, $file) {
+ $form_state['file'] = $file;
+
+ $form['fid'] = array(
+ '#type' => 'value',
+ '#value' => $file->fid,
+ );
+
+ $description = t('This action cannot be undone.');
+ if ($references = file_usage_list($file)) {
+ $description .= ' ' . t('This file is currently in use and may cause problems if deleted.');
+ }
+
+ return confirm_form($form,
+ t('Are you sure you want to delete the file %title?', array(
+ '%title' => entity_label('file', $file),
+ )),
+ 'file/' . $file->fid,
+ $description,
+ t('Delete')
+ );
+}
+
+/**
+ * Form submission handler for file_entity_delete_form().
+ */
+function file_entity_delete_form_submit($form, &$form_state) {
+ if ($form_state['values']['confirm'] && $file = file_load($form_state['values']['fid'])) {
+ // Use file_delete_multiple() rather than file_delete() since we want to
+ // avoid unwanted validation and usage checking.
+ file_delete_multiple(array($file->fid));
+
+ $args = array(
+ '@type' => file_entity_type_get_name($file),
+ '%title' => entity_label('file', $file),
+ );
+ watchdog('file', '@type: deleted %title.', $args);
+ drupal_set_message(t('@type %title has been deleted.', $args));
+ }
+
+ $form_state['redirect'] = '<front>';
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Form constructor for file deletion confirmation form.
+ *
+ * @param array $files
+ * An array of file objects.
+ */
+function file_entity_multiple_delete_form($form, &$form_state, array $files) {
+ $form['files'] = array(
+ '#prefix' => '<ul>',
+ '#suffix' => '</ul>',
+ '#tree' => TRUE,
+ );
+
+ $files_have_usage = FALSE;
+ foreach ($files as $fid => $file) {
+ $title = entity_label('file', $file);
+ $usage = file_usage_list($file);
+ if (!empty($usage)) {
+ $files_have_usage = TRUE;
+ $title = t('@title (in use)', array('@title' => $title));
+ }
+ else {
+ $title = check_plain($title);
+ }
+ $form['files'][$fid] = array(
+ '#type' => 'hidden',
+ '#value' => $fid,
+ '#prefix' => '<li>',
+ '#suffix' => $title . "</li>\n",
+ );
+ }
+
+ $form['operation'] = array(
+ '#type' => 'hidden',
+ '#value' => 'delete',
+ );
+
+ $description = t('This action cannot be undone.');
+ if ($files_have_usage) {
+ $description .= ' ' . t('Some of the files are currently in use and may cause problems if deleted.');
+ }
+
+ return confirm_form(
+ $form,
+ format_plural(count($files), 'Are you sure you want to delete this file?', 'Are you sure you want to delete these files?'),
+ 'admin/content/file',
+ $description,
+ t('Delete')
+ );
+}
+
+/**
+ * Form submission handler for file_entity_multiple_delete_form().
+ */
+function file_entity_multiple_delete_form_submit($form, &$form_state) {
+ if ($form_state['values']['confirm'] && $fids = array_keys($form_state['values']['files'])) {
+ file_delete_multiple($fids);
+ $count = count($fids);
+ watchdog('file', 'Deleted @count files.', array('@count' => $count));
+ drupal_set_message(format_plural($count, 'Deleted one file.', 'Deleted @count files.'));
+ }
+ $form_state['redirect'] = 'admin/content/file';
+
+ // Clear the page and block caches.
+ cache_clear_all();
+}
+
+/**
+ * Page callback for the file edit form.
+ *
+ * @deprecated
+ * Use drupal_get_form('file_entity_edit')
+ */
+function file_entity_page_edit($file) {
+ return drupal_get_form('file_entity_edit', $file);
+}
+
+/**
+ * Page callback for the file deletion confirmation form.
+ *
+ * @deprecated
+ * Use drupal_get_form('file_entity_delete_form')
+ */
+function file_entity_page_delete($file) {
+ return drupal_get_form('file_entity_delete_form');
+}
+
+/**
+ * Retrieves the upload validators for a file.
+ *
+ * @param array $options
+ * (optional) An array of options for file validation.
+ *
+ * @return array
+ * An array suitable for passing to file_save_upload() or for a managed_file
+ * or upload element's '#upload_validators' property.
+ */
+function file_entity_get_upload_validators(array $options = array()) {
+ // Set up file upload validators.
+ $validators = array();
+
+ // Validate file extensions. If there are no file extensions in $params and
+ // there are no Media defaults, there is no file extension validation.
+ if (!empty($options['file_extensions'])) {
+ $validators['file_validate_extensions'] = array($options['file_extensions']);
+ }
+ else {
+ $validators['file_validate_extensions'] = array(variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp mp3 mov mp4 m4a m4v mpeg avi ogg oga ogv weba webp webm'));
+ }
+
+ // Cap the upload size according to the system or user defined limit.
+ $max_filesize = parse_size(file_upload_max_size());
+ $file_entity_max_filesize = parse_size(variable_get('file_entity_max_filesize', ''));
+
+ // If the user defined a size limit, use the smaller of the two.
+ if (!empty($file_entity_max_filesize)) {
+ $max_filesize = min($max_filesize, $file_entity_max_filesize);
+ }
+
+ if (!empty($options['max_filesize']) && $options['max_filesize'] < $max_filesize) {
+ $max_filesize = parse_size($options['max_filesize']);
+ }
+
+ // There is always a file size limit due to the PHP server limit.
+ $validators['file_validate_size'] = array($max_filesize);
+
+ // Add image validators.
+ $options += array('min_resolution' => 0, 'max_resolution' => 0);
+ if ($options['min_resolution'] || $options['max_resolution']) {
+ $validators['file_validate_image_resolution'] = array($options['max_resolution'], $options['min_resolution']);
+ }
+
+ // Add other custom upload validators from options.
+ if (!empty($options['upload_validators'])) {
+ $validators += $options['upload_validators'];
+ }
+
+ return $validators;
+}
+
+function file_entity_upload_archive_form($form, &$form_state) {
+ $options = array(
+ 'file_extensions' => archiver_get_extensions(),
+ );
+
+ $form['upload'] = array(
+ '#type' => 'managed_file',
+ '#title' => t('Upload an archive file'),
+ '#upload_location' => NULL, // Upload to the temporary directory.
+ '#upload_validators' => file_entity_get_upload_validators($options),
+ '#progress_indicator' => 'bar',
+ '#required' => TRUE,
+ '#pre_render' => array('file_managed_file_pre_render', 'file_entity_upload_validators_pre_render'),
+ );
+
+ $form['pattern'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Pattern'),
+ '#description' => t('Only files matching this pattern will be imported. For example, to import all jpg and gif files, the pattern would be <em>*.jpg|*.gif</em>. Use <em>.*</em> to extract all files in the archive.'),
+ '#default_value' => '.*',
+ '#required' => TRUE,
+ );
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+
+ form_load_include($form_state, 'inc', 'file_entity', 'file_entity.pages');
+
+ return $form;
+}
+
+/**
+ * Upload a file.
+ */
+function file_entity_upload_archive_form_submit($form, &$form_state) {
+ $form_state['files'] = array();
+
+ if ($archive = file_load($form_state['values']['upload'])) {
+ if ($archiver = archiver_get_archiver($archive->uri)) {
+ $files = $archiver->listContents();
+
+ $extract_dir = file_default_scheme() . '://' . pathinfo($archive->filename, PATHINFO_FILENAME);
+ $extract_dir = file_destination($extract_dir, FILE_EXISTS_RENAME);
+ if (!file_prepare_directory($extract_dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY)) {
+ throw new Exception(t('Unable to prepar, e directory %dir for extraction.', array('%dir' => $extract_dir)));
+ }
+
+ $archiver->extract($extract_dir);
+ $pattern = '/' . $form_state['values']['pattern'] . '/';
+ if ($files = file_scan_directory($extract_dir, $pattern)) {
+ foreach ($files as $file) {
+ $file->status = FILE_STATUS_PERMANENT;
+ $file->uid = $archive->uid;
+ file_save($file);
+ $form_state['files'][$file->fid] = $file;
+ }
+ }
+ drupal_set_message(t('Extracted %file and added @count new files.', array('%file' => $archive->filename, '@count' => count($files))));
+ }
+ else {
+ throw new Exception(t('Cannot extract %file, not a valid archive.', array('%file' => $archive->uri)));
+ }
+ }
+
+ // Redirect to the file edit page.
+ if (file_entity_access('edit') && module_exists('multiform')) {
+ $destination = array('destination' => 'admin/content/file');
+ if (isset($_GET['destination'])) {
+ $destination = drupal_get_destination();
+ unset($_GET['destination']);
+ }
+ $form_state['redirect'] = array('admin/content/file/edit-multiple/' . implode(' ', array_keys($form_state['files'])), array('query' => $destination));
+ }
+ else {
+ $form_state['redirect'] = 'admin/content/file';
+ }
+}