You are here

filefield_paths.module in File (Field) Paths 7

Contains core functions for the File (Field) Paths module.

File

filefield_paths.module
View source
<?php

/**
 * @file
 * Contains core functions for the File (Field) Paths module.
 */

/**
 * Include additional files.
 */
$dirname = dirname(__FILE__) . "/modules";
$includes = file_scan_directory($dirname, '/.inc$/');
foreach (module_list() as $module) {
  if (isset($includes[$file = "{$dirname}/{$module}.inc"])) {
    require_once $file;
  }
}

/**
 * Implements hook_menu().
 */
function filefield_paths_menu() {
  $items['admin/config/media/file-system/filefield-paths'] = array(
    'title' => t('File (Field) Paths settings'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'filefield_paths_settings_form',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'filefield_paths.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_form_alter().
 *
 * @param $form
 */
function filefield_paths_form_alter(&$form) {

  // Force all File (Field) Paths uploads to go to the temporary file system
  // prior to being processed.
  if (isset($form['#entity']) && isset($form['#entity_type']) && isset($form['#bundle']) && $form['#type'] == 'form') {
    filefield_paths_temporary_upload_location($form);
  }
  $field_types = _filefield_paths_get_field_types();
  if (isset($form['#field']) && in_array($form['#field']['type'], array_keys($field_types))) {
    $entity_info = entity_get_info($form['#instance']['entity_type']);
    $settings = isset($form['#instance']['settings']['filefield_paths']) ? $form['#instance']['settings']['filefield_paths'] : array();
    $form['instance']['settings']['filefield_paths_enabled'] = array(
      '#type' => 'checkbox',
      '#title' => t('Enable File (Field) Paths?'),
      '#default_value' => isset($form['#instance']['settings']['filefield_paths_enabled']) ? $form['#instance']['settings']['filefield_paths_enabled'] : TRUE,
      '#weight' => 2,
    );

    // Hide standard File directory field.
    $form['instance']['settings']['file_directory']['#states'] = array(
      'visible' => array(
        ':input[name="instance[settings][filefield_paths_enabled]"]' => array(
          'checked' => FALSE,
        ),
      ),
    );

    // File (Field) Paths fieldset element.
    $form['instance']['settings']['filefield_paths'] = array(
      '#type' => 'fieldset',
      '#title' => t('File (Field) Path settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#weight' => 3,
      '#tree' => TRUE,
      '#states' => array(
        'visible' => array(
          ':input[name="instance[settings][filefield_paths_enabled]"]' => array(
            'checked' => TRUE,
          ),
        ),
      ),
    );

    // Additional File (Field) Paths widget fields.
    $fields = module_invoke_all('filefield_paths_field_settings', $form['#field'], $form['#instance']);
    foreach ($fields as $name => $field) {

      // Attach widget fields.
      $form['instance']['settings']['filefield_paths'][$name] = array(
        '#type' => 'container',
      );

      // Attach widget field form elements.
      if (isset($field['form']) && is_array($field['form'])) {
        foreach (array_keys($field['form']) as $delta => $key) {
          $form['instance']['settings']['filefield_paths'][$name][$key] = $field['form'][$key];
          if (module_exists('token')) {
            $form['instance']['settings']['filefield_paths'][$name][$key]['#element_validate'][] = 'token_element_validate';
            $form['instance']['settings']['filefield_paths'][$name][$key]['#token_types'] = array(
              'file',
              $entity_info['token type'],
            );
          }

          // Fetch stored value from instance.
          if (isset($settings[$name][$key])) {
            $form['instance']['settings']['filefield_paths'][$name][$key]['#default_value'] = $settings[$name][$key];
          }
        }

        // Field options.
        $form['instance']['settings']['filefield_paths'][$name]['options'] = array(
          '#type' => 'fieldset',
          '#title' => t('@title options', array(
            '@title' => t($field['title']),
          )),
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
          '#weight' => 1,
          '#attributes' => array(
            'class' => array(
              "{$name} cleanup",
            ),
          ),
        );

        // Cleanup slashes (/).
        $form['instance']['settings']['filefield_paths'][$name]['options']['slashes'] = array(
          '#type' => 'checkbox',
          '#title' => t('Remove slashes (/) from tokens'),
          '#default_value' => isset($settings[$name]['options']['slashes']) ? $settings[$name]['options']['slashes'] : FALSE,
          '#description' => t('If checked, any slashes (/) in tokens will be removed from %title.', array(
            '%title' => t($field['title']),
          )),
        );

        // Cleanup field with Pathauto module.
        $form['instance']['settings']['filefield_paths'][$name]['options']['pathauto'] = array(
          '#type' => 'checkbox',
          '#title' => t('Cleanup using Pathauto'),
          '#default_value' => isset($settings[$name]['options']['pathauto']) && module_exists('pathauto') ? $settings[$name]['options']['pathauto'] : FALSE,
          '#description' => t('Cleanup %title using <a href="@pathauto">Pathauto settings</a>.', array(
            '%title' => t($field['title']),
            '@pathauto' => url('admin/config/search/path/settings'),
          )),
          '#disabled' => !module_exists('pathauto'),
        );

        // Transliterate field with Transliteration module.
        $form['instance']['settings']['filefield_paths'][$name]['options']['transliterate'] = array(
          '#type' => 'checkbox',
          '#title' => t('Transliterate'),
          '#default_value' => isset($settings[$name]['options']['transliterate']) && module_exists('transliteration') ? $settings[$name]['options']['transliterate'] : 0,
          '#description' => t('Provides one-way string transliteration (romanization) and cleans the %title during upload by replacing unwanted characters.', array(
            '%title' => t($field['title']),
          )),
          '#disabled' => !module_exists('transliteration'),
        );

        // Replacement patterns for field.
        if (module_exists('token')) {
          $form['instance']['settings']['filefield_paths']['token_tree'] = array(
            '#theme' => 'token_tree',
            '#token_types' => array(
              'file',
              $entity_info['token type'],
            ),
            '#dialog' => TRUE,
            '#weight' => 10,
          );
        }

        // Redirect
        $form['instance']['settings']['filefield_paths']['redirect'] = array(
          '#type' => 'checkbox',
          '#title' => t('Create Redirect'),
          '#description' => t('Create a redirect to the new location when a previously uploaded file is moved.'),
          '#default_value' => isset($settings['redirect']) ? $settings['redirect'] : FALSE,
          '#weight' => 11,
        );
        if (!module_exists('redirect')) {
          $form['instance']['settings']['filefield_paths']['redirect']['#disabled'] = TRUE;
          $form['instance']['settings']['filefield_paths']['redirect']['#description'] .= '<br />' . t('Requires the <a href="https://drupal.org/project/redirect" target="_blank">Redirect</a> module.');
        }

        // Retroactive updates.
        $form['instance']['settings']['filefield_paths']['retroactive_update'] = array(
          '#type' => 'checkbox',
          '#title' => t('Retroactive update'),
          '#description' => t('Move and rename previously uploaded files.') . '<div>' . t('<strong class="warning">Warning:</strong> This feature should only be used on developmental servers or with extreme caution.') . '</div>',
          '#weight' => 12,
        );

        // Active updating.
        $form['instance']['settings']['filefield_paths']['active_updating'] = array(
          '#type' => 'checkbox',
          '#title' => t('Active updating'),
          '#default_value' => isset($settings['active_updating']) ? $settings['active_updating'] : FALSE,
          '#description' => t('Actively move and rename previously uploaded files as required.') . '<div>' . t('<strong class="warning">Warning:</strong> This feature should only be used on developmental servers or with extreme caution.') . '</div>',
          '#weight' => 13,
        );
      }
    }
    $form['#submit'][] = 'filefield_paths_form_submit';
  }
}

/**
 * Recursively set temporary upload location of all File (Field) Paths enabled
 * managed file fields.
 *
 * @param $element
 */
function filefield_paths_temporary_upload_location(&$element) {
  if (isset($element['#type']) && $element['#type'] == 'managed_file' && isset($element['#entity_type']) && isset($element['#field_name']) && isset($element['#bundle'])) {
    $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
    if (isset($instance['settings']['filefield_paths_enabled']) && $instance['settings']['filefield_paths_enabled']) {
      $element['#upload_location'] = variable_get('filefield_paths_temp_location', 'public://filefield_paths');
    }
    return;
  }
  foreach (element_children($element) as $child) {
    filefield_paths_temporary_upload_location($element[$child]);
  }
}

/**
 * Submit callback for File (Field) Paths settings form.
 *
 * @param $form
 * @param $form_state
 */
function filefield_paths_form_submit($form, &$form_state) {

  // Retroactive updates.
  if ($form_state['values']['instance']['settings']['filefield_paths_enabled'] && $form_state['values']['instance']['settings']['filefield_paths']['retroactive_update']) {
    if (filefield_paths_batch_update($form_state['values']['instance'])) {
      batch_process($form_state['redirect']);
    }
  }
}

/**
 * Set batch process to update File (Field) Paths.
 *
 * @param $instance
 *
 * @return bool
 */
function filefield_paths_batch_update($instance) {
  $query = new EntityFieldQuery();
  $result = $query
    ->entityCondition('entity_type', $instance['entity_type'])
    ->entityCondition('bundle', array(
    $instance['bundle'],
  ))
    ->fieldCondition($instance['field_name'])
    ->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT')
    ->execute();

  // If there are no results, do not set a batch as there is nothing to process.
  if (empty($result[$instance['entity_type']])) {
    return FALSE;
  }
  $objects = array_keys($result[$instance['entity_type']]);
  $instance = field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);

  // Create batch.
  $batch = array(
    'title' => t('Updating File (Field) Paths'),
    'operations' => array(
      array(
        '_filefield_paths_batch_update_process',
        array(
          $objects,
          $instance,
        ),
      ),
    ),
  );
  batch_set($batch);
  return TRUE;
}

/**
 * Batch callback for File (Field) Paths retroactive updates.
 *
 * @param $objects
 * @param $instance
 * @param $context
 *
 * @throws FieldException
 */
function _filefield_paths_batch_update_process($objects, $instance, &$context) {
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = count($objects);
    $context['sandbox']['objects'] = $objects;
  }

  // Process nodes by groups of 5.
  $count = min(5, count($context['sandbox']['objects']));
  for ($i = 1; $i <= $count; $i++) {

    // For each oid, load the object, update the files and save it.
    $oid = array_shift($context['sandbox']['objects']);
    $entity = current(entity_load($instance['entity_type'], array(
      $oid,
    )));

    // Enable active updating if it isn't already enabled.
    $active_updating = $instance['settings']['filefield_paths']['active_updating'];
    if (!$active_updating) {
      $instance['settings']['filefield_paths']['active_updating'] = TRUE;
      field_update_instance($instance);
    }

    // Invoke field_attach_update().
    field_attach_update($instance['entity_type'], $entity);

    // Restore active updating to it's previous state if necessary.
    if (!$active_updating) {
      $instance['settings']['filefield_paths']['active_updating'] = $active_updating;
      field_update_instance($instance);
    }

    // Update our progress information.
    $context['sandbox']['progress']++;
  }

  // Inform the batch engine that we are not finished,
  // and provide an estimation of the completion level we reached.
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}

/**
 * Implements hook_field_storage_pre_insert().
 *
 * @param $entity_type
 * @param $entity
 */
function filefield_paths_field_storage_pre_insert($entity_type, $entity) {
  filefield_paths_field_storage_pre_update($entity_type, $entity);
}

/**
 * Implements hook_field_storage_pre_update().
 *
 * @param $entity_type
 * @param $entity
 */
function filefield_paths_field_storage_pre_update($entity_type, $entity) {
  $field_types = _filefield_paths_get_field_types();
  $entity_info = entity_get_info($entity_type);
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  if ($entity_info['fieldable']) {
    foreach (field_info_fields() as $field) {
      if (in_array($field['type'], array_keys($field_types))) {
        $files = array();
        $instance = field_info_instance($entity_type, $field['field_name'], $bundle);
        $enabled = isset($instance['settings']['filefield_paths_enabled']) && $instance['settings']['filefield_paths_enabled'] || !isset($instance['settings']['filefield_paths_enabled']);
        if ($enabled && isset($entity->{$field['field_name']}) && is_array($entity->{$field['field_name']})) {
          foreach ($entity->{$field['field_name']} as $langcode => &$deltas) {
            foreach ($deltas as $delta => &$file) {

              // Prepare file.
              if (function_exists($function = "{$field['module']}_field_load")) {
                $items = array(
                  array(
                    &$file,
                  ),
                );
                $function($entity_type, array(
                  $entity,
                ), $field, array(
                  $instance,
                ), $langcode, $items, FIELD_LOAD_CURRENT);
              }
              $files[] =& $file;
            }

            // Invoke hook_filefield_paths_process_file().
            foreach (module_implements('filefield_paths_process_file') as $module) {
              if (function_exists($function = "{$module}_filefield_paths_process_file")) {
                $function($entity_type, $entity, $field, $instance, $langcode, $files);
              }
            }
          }
        }
      }
    }
  }
}

/**
 * Implements hook_file_presave().
 *
 * @param $file
 */
function filefield_paths_file_presave($file) {

  // Store original filename in the database.
  if (empty($file->origname) && isset($file->filename)) {
    $file->origname = $file->filename;
  }
}

/**
 * Creates a redirect for a moved File field.
 *
 * @param $source
 * @param $path
 *
 * @throws Exception
 */
function _filefield_paths_create_redirect($source, $path) {
  global $base_path;
  watchdog('filefield_paths', 'Creating redirect from @source to @path', array(
    '@source' => $source,
    '@path' => $path,
  ), WATCHDOG_DEBUG);
  $redirect = new stdClass();
  redirect_object_prepare($redirect);
  $parsed_source = parse_url(file_create_url($source), PHP_URL_PATH);
  $parsed_path = parse_url(file_create_url($path), PHP_URL_PATH);
  $redirect->source = drupal_substr(urldecode($parsed_source), drupal_strlen($base_path));
  $redirect->redirect = drupal_substr(urldecode($parsed_path), drupal_strlen($base_path));

  // Check if the redirect exists before saving.
  $hash = redirect_hash($redirect);
  if (!redirect_load_by_hash($hash)) {
    redirect_save($redirect);
  }
}

/**
 * Run regular expression over all available text-based fields.
 *
 * @param $old
 * @param $new
 * @param $entity
 */
function _filefield_paths_replace_path($old, $new, $entity) {
  $info = parse_url($old);
  if (isset($info['path'])) {
    $info['host'] .= $info['path'];
  }

  // Generate all path prefix variations.
  $prefixes = _filefield_paths_replace_path_get_prefixes($info['scheme'], TRUE);
  $prefixes = implode('|', $prefixes);

  // Generate all image style path variations.
  $styles['raw'] = "styles/REGEX/{$info['scheme']}/";
  $styles['urlencode'] = urlencode($styles['raw']);
  foreach ($styles as &$style) {
    $style = str_replace(array(
      '/',
      'REGEX',
    ), array(
      '\\/',
      '(.*?)',
    ), $style);
  }
  $styles = implode('|', $styles);

  // General all path variations.
  $paths['raw'] = preg_quote($info['host'], '/');
  $paths['urlencode'] = preg_quote(urlencode($info['host']), '/');
  $paths['drupal_encode_path'] = preg_quote(drupal_encode_path($info['host']), '/');
  $paths = implode('|', $paths);

  // Newer versions of the Image module add an 8 character token which is
  // required if the image style hasn't been generated yet.
  $itok = '';
  if (defined('IMAGE_DERIVATIVE_TOKEN')) {
    $itok = '((?:[\\?|&](?:\\S+?&)*|(?:%3F|%26)(?:\\S+?%26)*)' . IMAGE_DERIVATIVE_TOKEN . '(?:=|%3D)(\\S{8}))*';
  }

  // Build regular expression pattern.
  $pattern = "/({$prefixes})({$styles})*({$paths}){$itok}/";

  // Create an anonymous function for the replacement via preg_replace_callback.
  $callback = function ($matches) use ($new, $old) {
    return filefield_paths_replace_path_callback($matches, $new, $old);
  };
  if (!$callback) {
    watchdog('filefield_paths', 'Unable to create an anonymous function to find references of %old and replace with %new.', array(
      '%old' => $old,
      '%new' => $new,
    ));
    return;
  }
  $fields = field_info_fields();
  foreach ($fields as $name => $field) {
    if ($field['module'] == 'text' && isset($entity->{$field['field_name']}) && is_array($entity->{$field['field_name']})) {
      foreach ($entity->{$field['field_name']} as &$language) {
        foreach ($language as &$item) {
          foreach (array(
            'value',
            'summary',
          ) as $column) {
            if (isset($item[$column])) {
              $item[$column] = preg_replace_callback($pattern, $callback, $item[$column]);
            }
          }
        }
      }
    }
  }
}

/**
 * Helper function; Returns all variations of the file path prefix.
 *
 * @param            $scheme
 * @param bool|FALSE $preg_quote
 * @param bool|FALSE $reset
 *
 * @return mixed
 */
function _filefield_paths_replace_path_get_prefixes($scheme, $preg_quote = FALSE, $reset = FALSE) {
  $prefixes =& drupal_static(__FUNCTION__, array());

  // Force clean urls on.
  $clean_url = $GLOBALS['conf']['clean_url'];
  $GLOBALS['conf']['clean_url'] = TRUE;
  $id = $scheme . '::' . (string) $preg_quote;
  if (!isset($prefixes[$id]) || $reset) {
    $prefixes[$id]['uri'] = "{$scheme}://";
    $prefixes[$id]['absolute'] = file_create_url($prefixes[$id]['uri']);
    $prefixes[$id]['relative'] = parse_url($prefixes[$id]['absolute'], PHP_URL_PATH);
    $prefixes[$id]['unclean'] = '?q=' . drupal_substr($prefixes[$id]['relative'], drupal_strlen(base_path()));
    foreach ($prefixes[$id] as $key => $prefix) {
      $prefixes[$id]["{$key}-urlencode"] = urlencode($prefix);
      $prefixes[$id]["{$key}-drupal_encode_path"] = drupal_encode_path($prefix);
    }
    if ($preg_quote) {
      foreach ($prefixes[$id] as $key => $prefix) {
        $prefixes[$id][$key] = preg_quote($prefixes[$id][$key], '/');
      }
    }
  }

  // Restore clean url settings.
  $GLOBALS['conf']['clean_url'] = $clean_url;
  return $prefixes[$id];
}

/**
 * Callback for regex string replacement functionality.
 *
 * @param $matches
 * @param $new
 * @param $old
 *
 * @return string
 */
function filefield_paths_replace_path_callback($matches, $new, $old) {
  $prefix = $matches[1];
  $styles = $matches[2];
  $query = isset($matches[6]) ? $matches[6] : '';

  // Get file path info for old file.
  $old_info = parse_url($old);
  if (isset($old_info['path'])) {
    $old_info['host'] .= $old_info['path'];
  }

  // Determine the file path variation type/modifier.
  $old_prefixes = _filefield_paths_replace_path_get_prefixes($old_info['scheme']);
  $modifier = NULL;
  foreach ($old_prefixes as $key => $old_prefix) {
    if ($prefix == $old_prefix) {
      $parts = explode('-', $key);
      $modifier = isset($parts[1]) ? $parts[1] : NULL;
      break;
    }
  }

  // Get file path info for new file.
  $new_info = parse_url($new);
  if (isset($new_info['path'])) {
    $new_info['host'] .= $new_info['path'];
  }

  // Replace prefix.
  $prefixes = _filefield_paths_replace_path_get_prefixes($new_info['scheme']);
  if (isset($key) && isset($prefixes[$key])) {
    $prefix = $prefixes[$key];
  }

  // Replace styles directory.
  if (!empty($styles)) {
    $styles = str_replace($old_info['scheme'], $new_info['scheme'], $styles);

    // Newer versions of the Image module add an 8 character token which is
    // required if the image style hasn't been generated yet.
    if (defined('IMAGE_DERIVATIVE_TOKEN') && isset($matches[7])) {
      $image_style = !empty($matches[3]) ? $matches[3] : $matches[4];

      // Only replace the token if the old one was valid.
      if ($matches[7] == image_style_path_token($image_style, $old)) {
        $query = substr_replace($query, image_style_path_token($image_style, $new), -strlen($matches[7]));
      }
    }
  }

  // Replace path.
  $path = $new_info['host'];
  if (!is_null($modifier) && function_exists($modifier)) {
    $path = call_user_func($modifier, $path);
  }
  return $prefix . $styles . $path . $query;
}

/**
 * Process and cleanup strings.
 *
 * @param       $value
 * @param       $data
 * @param array $settings
 *
 * @return mixed|string
 */
function filefield_paths_process_string($value, $data, $settings = array()) {
  $transliterate = module_exists('transliteration') && isset($settings['transliterate']) && $settings['transliterate'];
  $pathauto = module_exists('pathauto') && isset($settings['pathauto']) && $settings['pathauto'] == TRUE;
  $remove_slashes = !empty($settings['slashes']);
  if ($pathauto == TRUE) {
    module_load_include('inc', 'pathauto');
  }

  // If '/' is to be removed from tokens, token replacement need to happen after
  // splitting the paths to subdirs, otherwise tokens containing '/' will be
  // part of the final path.
  if (!$remove_slashes) {
    $value = token_replace($value, $data, array(
      'clear' => TRUE,
    ));
  }
  $paths = explode('/', $value);
  foreach ($paths as $i => &$path) {
    if ($remove_slashes) {
      $path = token_replace($path, $data, array(
        'clear' => TRUE,
      ));
    }
    if ($pathauto == TRUE) {
      if ('file_name' == $settings['context'] && count($paths) == $i + 1) {
        $pathinfo = pathinfo($path);
        $basename = drupal_basename($path);
        $extension = preg_match('/\\.[^.]+$/', $basename, $matches) ? $matches[0] : NULL;
        $pathinfo['filename'] = !is_null($extension) ? drupal_substr($basename, 0, drupal_strlen($basename) - drupal_strlen($extension)) : $basename;
        if ($remove_slashes) {
          $path = '';
          if (!empty($pathinfo['dirname']) && $pathinfo['dirname'] !== '.') {
            $path .= $pathinfo['dirname'] . '/';
          }
          $path .= $pathinfo['filename'];
          $path = pathauto_cleanstring($path);
          if (!empty($pathinfo['extension'])) {
            $path .= '.' . pathauto_cleanstring($pathinfo['extension']);
          }
          $path = str_replace('/', '', $path);
        }
        else {
          $path = str_replace($pathinfo['filename'], pathauto_cleanstring($pathinfo['filename']), $path);
        }
      }
      else {
        $path = pathauto_cleanstring($path);
      }
    }
    elseif ($remove_slashes) {
      $path = str_replace('/', '', $path);
    }

    // Transliterate string.
    if ($transliterate == TRUE) {
      $path = transliteration_clean_filename($path);
    }
  }
  $value = implode('/', $paths);

  // Ensure that there are no double-slash sequences due to empty token values.
  $value = preg_replace('/\\/+/', '/', $value);
  return $value;
}

/**
 * Provides a list of all available field types for use with File (Field) Paths.
 *
 * @param bool|FALSE $reset
 *
 * @return array
 */
function _filefield_paths_get_field_types($reset = FALSE) {
  $field_types =& drupal_static(__FUNCTION__);
  if (empty($field_types) || $reset) {
    $field_types = module_invoke_all('filefield_paths_field_type_info');
    $field_types = array_flip($field_types);
    foreach (array_keys($field_types) as $type) {
      $info = field_info_field_types($type);
      $field_types[$type] = array(
        'label' => $info['label'],
      );
    }
  }
  return $field_types;
}

Functions

Namesort descending Description
filefield_paths_batch_update Set batch process to update File (Field) Paths.
filefield_paths_field_storage_pre_insert Implements hook_field_storage_pre_insert().
filefield_paths_field_storage_pre_update Implements hook_field_storage_pre_update().
filefield_paths_file_presave Implements hook_file_presave().
filefield_paths_form_alter Implements hook_form_alter().
filefield_paths_form_submit Submit callback for File (Field) Paths settings form.
filefield_paths_menu Implements hook_menu().
filefield_paths_process_string Process and cleanup strings.
filefield_paths_replace_path_callback Callback for regex string replacement functionality.
filefield_paths_temporary_upload_location Recursively set temporary upload location of all File (Field) Paths enabled managed file fields.
_filefield_paths_batch_update_process Batch callback for File (Field) Paths retroactive updates.
_filefield_paths_create_redirect Creates a redirect for a moved File field.
_filefield_paths_get_field_types Provides a list of all available field types for use with File (Field) Paths.
_filefield_paths_replace_path Run regular expression over all available text-based fields.
_filefield_paths_replace_path_get_prefixes Helper function; Returns all variations of the file path prefix.