You are here

swftools.module in SWF Tools 6.2

Same filename and directory in other branches
  1. 5 swftools.module
  2. 6.3 swftools.module
  3. 6 swftools.module

File

swftools.module
View source
<?php

// Include the generic player module for basic mp3 and flv support
include_once drupal_get_path('module', 'swftools') . '/genericplayers.module';

// This is the Flash embed method, other constants are usually defined in other Flash replace providers.
define('SWFTOOLS_EMBED_METHOD', 'swftools_embed_method');

// Using JavaScript to replace HTML with Flash embedding code.
// The following are actions, what to do with the passed file.
define('SWFTOOLS_IMAGE_DISPLAY_LIST', 'swftools_image_display_list');

// Display list of images
define('SWFTOOLS_FLV_DISPLAY', 'swftools_flv_display');

// Display .flv format file
define('SWFTOOLS_FLV_DISPLAY_LIST', 'swftools_flv_display_list');

// Display list of .flv format files
define('SWFTOOLS_MP3_DISPLAY', 'swftools_mp3_display');

// Display .mp3 format file
define('SWFTOOLS_MP3_DISPLAY_LIST', 'swftools_mp3_display_list');

// Display list of .mp3 format files
define('SWFTOOLS_MEDIA_DISPLAY', 'swftools_media_display');

// Display an unspecified file format
define('SWFTOOLS_MEDIA_DISPLAY_LIST', 'swftools_media_display_list');

// Display list of mixed files
define('SWFTOOLS_SWF_DISPLAY_DIRECT', 'swftools_swf_display_direct');

// Display .swf format file, not inside any player
define('SWFTOOLS_SWF_DISPLAY', 'swftools_swf_display');

// Display .swf format inside a player
// These are for user convenience, most common parameters for casual users using the api.
define('SWFDEFAULT', FALSE);
define('SWFTOOLS_SWF', 'swftools_swf');

// This is a 'player' method implemented by swftools.module itself.
define('SWFTOOLS_CUSTOM', 'swftools_custom');

// An unknown media/file player.
define('SWFTOOLS_NOJAVASCRIPT', 'swftools_nojavascript');

// This is an 'embed' method implemented by swftools.module itself.
define('SWFTOOLS_DEFAULT_BG', 'shared/swftools-default.jpg');

// A generic image for use in certain contexts.
// Let other modules know SWF Tools is available
define('SWFTOOLS_INSTALLED', TRUE);

// Configure some other defaults
define('SWFTOOLS_DEFAULT_HTML_ALT', '<p>' . t('You are missing some Flash content that should appear here! Perhaps your browser cannot display it, or maybe it did not initialize correctly.') . '</p>');
define('SWFTOOLS_PLAYLIST_PATH', 'playlists');
define('SWFTOOLS_PLAYER_PATH', '');
define('SWFTOOLS_GRANT_ACCESS_TO_PRIVATE_FILES', FALSE);
define('SWFTOOLS_GRANT_ACCESS_EXTENSIONS', 'swf flv xml mp3 jpg jpeg png');
define('SWFTOOLS_ALWAYS_ADD_JS', TRUE);

/**
 * Implementation of hook_init()
 * swftools_init() is used to force embedding JavaScript on to all pages
 */
function swftools_init() {
  if (variable_get('swftools_always_add_js', SWFTOOLS_ALWAYS_ADD_JS)) {
    swftools_push_js();
  }
}

/**
 * Implementation of hook_menu().
 */
function swftools_menu() {

  // Reset methods cache
  $methods = swftools_methods_available('', TRUE);

  // Initialise array
  $items = array();

  // Should this be administer swf tools?
  $swf_admin = array(
    'administer flash',
  );
  $items['admin/settings/swftools'] = array(
    'title' => 'SWF Tools',
    'description' => 'Settings to control how SWF Tools integrates with Adobe Flash related methods and tools like video players, MP3 players and image viewers.',
    'access arguments' => $swf_admin,
    'page callback' => 'system_admin_menu_block_page',
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
  );
  $items['admin/settings/swftools/handling'] = array(
    'title' => 'File handling',
    'description' => 'Configure how SWF Tools should handle different types of file.',
    'access arguments' => $swf_admin,
    'weight' => -1,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'swftools_admin_handling_form',
    ),
    'file' => 'swftools.admin.inc',
  );
  $items['admin/settings/swftools/embed'] = array(
    'title' => 'Embedding settings',
    'description' => 'Set the embedding method that SWF Tools should use, and configure embedding defaults.',
    'access arguments' => $swf_admin,
    'weight' => -2,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'swftools_admin_embed_form',
    ),
    'file' => 'swftools.admin.inc',
  );

  // If CCK is active then add a link to the CCK formatters
  if (module_exists('content')) {
    $items['admin/settings/swftools/cck'] = array(
      'title' => 'CCK formatters',
      'description' => 'Additional settings to control how SWF Tools should interact with CCK.',
      'access arguments' => $swf_admin,
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'swftools_admin_cck_form',
      ),
      'file' => 'swftools.admin.inc',
    );
  }
  $items['admin/reports/swftools'] = array(
    'title' => 'SWF Tools status',
    'description' => 'Get an overview of the status of the SWF Tools module and its supporting files.',
    'page callback' => 'swftools_status',
    'access arguments' => $swf_admin,
    'file' => 'swftools.admin.status.inc',
    'weight' => 9,
  );
  $items = array_merge($items, genericplayers_menu());
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function swftools_perm() {
  return array(
    'administer flash',
  );
}

/**
 * Take an array of play list data and options, and return a markup string.
 * 
 * @param $playlist_data
 *   A formatted array of data to be used to create the playlist. An appropriate
 *   array can be created from an array of filenames by calling swftools_prepare_playlist_data.
 * @param $options
 *   An array of options to pass to the call to swf().
 * @return
 *   A string of markup to produce the playlist in a flash media player.
 */
function swf_list($playlist_data, $options = array()) {

  // Populate methods and othervars with playlist data
  if (is_array($playlist_data)) {

    // If action isn't set then set it
    if (empty($options['methods']['action']) && isset($playlist_data['action'])) {
      $options['methods']['action'] = $playlist_data['action'];
    }

    // If playlist_data isn't set then set it
    if (empty($options['othervars']['playlist_data'])) {
      $options['othervars']['playlist_data'] = $playlist_data;
    }

    // If playlist filename is set
    if (isset($playlist_data['filename'])) {
      $playlist = $playlist_data['filename'];
    }
    else {
      $playlist = '';
    }

    // Produce markup
    return swf($playlist, $options);
  }
}

/**
 * Return output, which might be embed markup, or pre-flash markup
 * that includes the appropriate jQuery added to the <head>
 *
 * @param $file
 *   The file to be played. If it is a SWF file it will usually be embedded directly.
 *   Use a full URL, a path relative to webroot, or a path relative to the configured files directory.
 *   If an array is passed then the array will be converted to a playlist automatically.
 *   If the file string is a complete url then SWF Tools will pass it along unaltered. If the string
 *   is a partial path then it will either be resolved to the local file system, or to a remote host,
 *   depending whether the swftools_media_url variable is set.
 * @param $options=>$params
 *   An associative array of <param> variables to set.eg. array('bgcolor'=>'FF00FF')
 *   To set height and width: array('width'=>'200', 'height'=>'120'). However,
 *   as a convenient alternative for the common requirement of just height and width
 *   you can also pass a text string like '200x100'.
 *   If you pass nothing, and the file to play is a .swf, swftools will try and
 *   establish a natural width and height from the actual .swf file that you've
 *   passed into $file.
 * @param $options=>$flashvars
 *   An associative array of flashvar variables to set. eg. array('playlist'=>'files/my_playlist.xml')
 * @param $options=>$othervars
 *   An associative array of variables that might be required by the $player or $embed technique.
 *   These values are not output as params or flashvars.
 * @param $options=>$methods
 *   Explicitly declare an action, player or action by passing an array of
 *   the form: array('action'=>'dosomething','player'=>'withsomething','embed'=>'withthisjavascript').
 *   These usually default to the administration settings and also you will
 *   usually use a CONSTANT which will be documented further at a later stage.
 */
function swf($file, $options = array()) {

  // Initialise any $options array elements that weren't passed by the caller
  $options += array(
    'params' => array(),
    'flashvars' => array(),
    'othervars' => array(),
    'methods' => array(),
  );

  // If swf() was called with an array of files, make a playlist and call swf_list() for processing
  if (is_array($file)) {

    // Turn the array in to a playlist
    $playlist_data = swftools_prepare_playlist_data($file, '', isset($options['methods']['action']) ? FALSE : TRUE);

    // Call swf_list to process the playlist and create the markup
    return swf_list($playlist_data, $options);
  }

  // Get all the actions, tools and embedding options available to us
  $all_methods = swftools_methods_available();

  // ACTION
  // Work out what SWF Tools should do with this file
  // Was an explicit action set in $options['methods']['action']
  $action = isset($options['methods']['action']) ? $options['methods']['action'] : FALSE;

  // If an explicit action wasn't set then try to determine an appropriate one using the filename
  if (!$action) {
    $action = swftools_get_action($file);
  }

  // HTML ALTERNATIVE
  // If an explicit value wasn't set in $options['othervars']['html_alt'] use a default
  $html_alt = isset($options['othervars']['html_alt']) ? $options['othervars']['html_alt'] : variable_get('swftools_html_alt', SWFTOOLS_DEFAULT_HTML_ALT);

  // RESOLVE PLAYER AND EMBEDDING
  // 'resolved' refers to the fact that these are the methods we now intend to use, not /all/ methods available.
  $resolved_methods = new stdClass();

  // PLAYER
  // Work out what player SWF Tools will need to use for this action
  // Was an explicit player set in $options['methods']['player']
  $player = isset($options['methods']['player']) ? $options['methods']['player'] : FALSE;

  // If an explicit player wasn't set then find out what player is configured for the current action
  if (!$player) {

    // Find out what player is assigned to handle the current action
    $player = swftools_get_player($action);

    // If still no player assignment then we don't know what to do with this action
    if (!$player) {

      // Build an array of descriptions for each possible action
      $descriptions = array(
        SWFTOOLS_IMAGE_DISPLAY_LIST => 'a series of images',
        SWFTOOLS_FLV_DISPLAY => 'a single flv file',
        SWFTOOLS_FLV_DISPLAY_LIST => 'a series of flv files',
        SWFTOOLS_MP3_DISPLAY => 'a single mp3 file',
        SWFTOOLS_MP3_DISPLAY_LIST => 'a series of mp3 files',
        SWFTOOLS_MEDIA_DISPLAY_LIST => 'a series mixed media files',
      );

      // If we have a matching description for the specified action, create a meaningful message
      if (isset($descriptions[$action])) {
        drupal_set_message(t('No player is configured to play ' . $descriptions[$action] . '. Check the SWF Tools file handling settings on the configuration page.'), 'error');
      }
      else {
        drupal_set_message(t('No player is configured for the action %action. Check the SWF Tools file handling settings on the configuration page.', array(
          '%action' => $action,
        )), 'error');
      }

      // We couldn't find a player for this content, so fallback to the alternate markup and return
      return $html_alt;
    }
  }

  // Check that the action / player combination is valid (it should appear in the array of all methods)
  if (isset($all_methods[$action][$player])) {

    // If the combination was found, place player information in to $resolved_methods
    $resolved_methods->player = $all_methods[$action][$player];
  }
  else {

    // If the action is display an swf directly then assume we have a custom player
    if ($action == SWFTOOLS_SWF_DISPLAY_DIRECT) {

      // Assign SWFTOOLS_CUSTOM data in to $resolved_methods
      $resolved_methods->player = $all_methods[$action][SWFTOOLS_CUSTOM];
      $resolved_methods->player['shared_file'] = $player;
    }
    else {
      drupal_set_message(t('Could not find the %player file for embedding.', array(
        '%player' => $player,
      )), 'error', FALSE);
      return $html_alt;
    }
  }

  // EMBED
  // Work out what embedding method SWF Tools should use for this content
  // Was an explicit embedding method set in $options['methods']['embed']
  $embed = isset($options['methods']['embed']) ? $options['methods']['embed'] : FALSE;

  // If an explicit embedding method wasn't set then find get the current default
  if (!$embed) {
    $embed = variable_get(SWFTOOLS_EMBED_METHOD, SWFTOOLS_NOJAVASCRIPT);
  }

  // Place the embedding method information in to $resolved_methods
  $resolved_methods->embed = $all_methods[SWFTOOLS_EMBED_METHOD][$embed];

  // VARIABLES AND PARAMETERS
  // Put all the variables on a simple object to make internal function calls simpler
  $vars = new stdClass();

  // OTHERVARS
  // If $options['othervars'] were supplied, add to $vars->othervars
  $vars->othervars = is_array($options['othervars']) ? $options['othervars'] : array();

  // PARAMS
  // $options['params'] could be an associative array, or in 'WIDTHxHEIGHT' format.
  // If $options were passed to the swf() function then process them
  if ($options['params']) {

    // If $options['params'] is an array then just add it to $vars
    if (is_array($options['params'])) {
      $vars->params = $options['params'];
    }
    else {
      $dimensions = explode('x', $options['params']);
      if (count($dimensions) == 2) {
        $vars->params = array(
          'width' => $dimensions[0],
          'height' => $dimensions[1],
        );
      }
    }
  }

  // FLASHVARS
  // Flashvars could be passed as an associative array, or as a string in 'a=1&b=2' format
  // If the flashvars have been passed as an array simply add to $varsa
  if (is_array($options['flashvars'])) {
    $vars->flashvars = $options['flashvars'];
  }
  else {

    // Parse the string as if in 'a=1&b=2' format.
    parse_str($options['flashvars'], $vars->flashvars);
  }

  // BASE
  // Determine a reasonable 'base' directory, if a remote url is set, use that
  // If file is local, set to the file directory
  // Was an explicit base path set in $options['params']['base']
  $base = !empty($vars->params['base']) ? $vars->params['base'] : '';

  // If the base path isn't set, or the path is not valid try to find a reasonable alternative
  if (!$base || !valid_url($base)) {

    // Use swftools_get_media_url() to obtain either the local path, or the remote media path
    $base = swftools_get_media_url('', FALSE);
  }

  // Strip $base_root if this is a local base path
  $base = swftools_strip_base_root($base);

  // Assign the resulting base path in to  $vars->params['base']
  $vars->params['base'] = $base;

  // PLAYLIST
  // Determine if we trying to generate a playlist
  // If $options['othervars']['playlist_data'] is set then we are processing a playlist
  if (isset($options['othervars']['playlist_data'])) {

    // Flag that a playlist is being generated
    $playlist = TRUE;

    // Generate a playlist in the files directory
    $file = swftools_generate_playlist($options['othervars']['playlist_data'], '', $resolved_methods, $vars);

    // If a file wasn't generated by swftools_generate_playlist then set an error and return alternate markup
    if (!$file) {
      drupal_set_message(t('Unable to create playlist.'), 'error');
      return $html_alt;
    }
  }

  // CACHING
  // To try and prevent the xml files from being cached append the time to the filename to try and force it to reload
  if (variable_get('swftools_playlist_caching', 'here') == 'always') {
    $nocache = '?nc=' . time();
  }
  else {
    $nocache = '';
  }

  // FILE
  // Make sure that the file path is $file is valid - we skip this section if $file is already a full url
  // Otherwise we try to expand it to a full url to the local file system or the remote media directory
  // If $file isn't already a valid url...
  //  if (!valid_url($file, TRUE)) {
  // If $file isn't a valid url, and if the file isn't going to be streamed, then try to work out where it is
  if (!valid_url($file, TRUE) && !isset($vars->othervars['stream'])) {

    // If we don't have a playlist...
    if (empty($playlist)) {

      // TODO : Is it necessary to have swftools_get_media_path() AND swftools_get_media_url()
      // Then check if files are being sourced locally, and if they are build a file path
      if (swftools_get_media_path()) {
        $file = file_create_path($file);
      }
    }

    // Try to turn $file in to a complete url, either local or remote
    $file_url = swftools_get_media_url($file);

    // If $file_url was not generated then file doesn't exist so return $html_alt
    if (!$file_url) {
      return $html_alt;
    }

    // Append $nocache string to complete the url

    //$file_url = $file_url . $nocache;
  }
  else {
    $file_url = $file;
  }

  //  // Try to strip $base_root if this is a local path
  //  $file_url = swftools_strip_base_root($file_url);
  // Attach file_url to othervars so player modules have access if required
  $vars->othervars['file_url'] = $file_url;

  // SRC
  // Determine the "src" attribute of the embed (also applies to the 'movie' attribute).
  // Usually this is the Flash Player, but it can also be a swf file, or a custom file
  // passed on othervars['shared_file'].
  switch ($player) {
    case SWFTOOLS_SWF:
      $vars->params['src_path'] = $file;
      $vars->params['src'] = $file_url;
      break;
    case SWFTOOLS_CUSTOM:
      $vars->params['src_path'] = $resolved_methods->player['shared_file'];

      // May need the local path for dimensions.
      $vars->params['src'] = swftools_get_media_url($vars->params['src_path']);
      break;
    default:
      $vars->params['src_path'] = swftools_get_player_path() . '/' . $resolved_methods->player['shared_file'];
      $vars->params['src'] = $GLOBALS['base_url'] . '/' . $vars->params['src_path'];
  }

  // Try to strip $base_root if this is a local path
  $vars->params['src'] = swftools_strip_base_root($vars->params['src']);

  // Merge default and user defined "params".
  $vars->params = array_merge(_swftools_params(), $vars->params);

  // Ask the module implementing the player what flashvars are required, pass
  // all existing values by reference to allow optional override at the player.module level.
  if (module_hook($resolved_methods->player['module'], 'swftools_flashvars')) {

    // Get player flashvars - use a custom invoke to allow pass by reference
    $player_flashvars = swftools_flashvars_invoke($action, $resolved_methods, $vars);

    // Merge player flashvars with existing flashvars
    if (is_array($player_flashvars)) {
      $vars->flashvars = array_merge($vars->flashvars, $player_flashvars);
    }
  }

  // If the player made a flashvar assignment for the playlist, add it to the flashvars
  if (!empty($resolved_methods->player['file'])) {
    $vars->flashvars[$resolved_methods->player['file']] = $vars->othervars['file_url'];
  }

  // If the player requires a specific minimum flash version then assign it to the params
  if (isset($resolved_methods->player['version'])) {
    $vars->params['version'] = $resolved_methods->player['version'];
  }

  // Call function to set the size of the content
  swftools_set_size($vars, $resolved_methods->player);

  // Build a string out of the flashvars array.
  $vars->params['flashvars'] = _swftools_get_flashvars_string($vars->flashvars);

  // Call the embedding code to get the HTML and set the JavaScript if necessary.
  $embed_markup = module_invoke($resolved_methods->embed['module'], 'swftools_embed', $action, $resolved_methods, $vars, $html_alt);

  // Call theme function to return completed markup, e.g. add containing div
  return theme('swftools_embed', $embed_markup, $action, $resolved_methods, $vars, $html_alt);
}

/**
 * Produce finished markup ready for inserting on the page
 *
 * @param $embed_markup
 *   The markup needed to add the swf content to the page
 * @param $action
 *   The action that is being used, in case the themer wants it
 * @param $methods
 *   The player and embedding methods being used, in case the themer wants it
 * @param $vars
 *   The array of othervars, params and flashvars in case the themer wants it
 * @param $html_alt
 *   The alternate HTML content, in case the themer wants it
 * @return
 *   An HTML string that generates the output
 */
function theme_swftools_embed($embed_markup, $action, $methods, $vars, $html_alt) {

  // Generate a css id if an id was supplied in $vars->othervars
  $id = !empty($vars->othervars['id']) ? ' id="swf-' . $vars->othervars['id'] . '"' : '';

  // Prepare an array of classes to include in the wrapper div
  $classes[] = 'swftools-wrapper';
  $classes[] = str_replace('_', '-', $methods->player['name']);

  // If the user provided class data already then don't over-rule it
  if (!empty($vars->othervars['class'])) {
    $classes[] = $vars->othervars['class'];
  }

  // Return completed markup
  return '<div' . $id . ' class="' . implode(' ', $classes) . '">' . $embed_markup . '</div>';
}

/**
 * Collect information from all modules about the players and embedding methods available.
 * 
 * @param $action
 *   Optional parameter to retrieve data only about a specific method.
 * @param $reset
 *   Optional parameter which if TRUE will reset the method cache and rebuild it.
 * @return
 *   An array of data describing the available methods.
 */
function swftools_methods_available($action = NULL, $reset = FALSE) {

  // Cache methods array as it may be called several times
  static $methods;

  // If user has requested the cache to be reset then reset it
  if (!isset($methods) || $reset) {
    if (!$reset && ($cache = cache_get('swftools:methods')) && !empty($cache->data)) {
      $methods = $cache->data;
    }
    else {
      $methods = module_invoke_all('swftools_methods');
      cache_set('swftools:methods', $methods, 'cache', CACHE_PERMANENT);
    }
  }

  // In case no module is presenting a method for the required action the
  // following line avoids a notice error
  if ($action) {
    $methods += array(
      $action => NULL,
    );
  }

  // Return results - either for the specific action, or the whole array
  return $action ? $methods[$action] : $methods;
}
function swftools_json_params(&$params, $attr = 'swftools') {
  return $attr . "='" . drupal_to_js($params) . "'";
}

/**
 * Returns 'true' or 'false' for JavaScript based the supplied value $bool.
 * 
 * @param $bool
 *   The value that should be cast to true or false.
 * @return
 *   The string 'true' or 'false' depending on the supplied value.
 */
function _swftools_tf($bool) {

  // String 'false' is treated as TRUE in PHP logic, so force to FALSE
  if (strtolower($bool) == 'false') {
    $bool = FALSE;
  }

  // Return 'true' or 'false' now we are sure of result
  return $bool ? 'true' : 'false';
}

/**
 * Identify the most likely SWF Tools action for a file, based on its extension.
 * 
 * @param $file
 *   The name of the file to be processed.
 * @return
 *   A string describing an SWF Tools action.
 */
function swftools_get_action($file) {

  // Get the path information for this file
  $path_parts = pathinfo($file);

  // Select an action based on the file extension
  switch (strtolower($path_parts['extension'])) {
    case 'flv':
      return SWFTOOLS_FLV_DISPLAY;
    case 'swf':
      return SWFTOOLS_SWF_DISPLAY_DIRECT;
    case 'mp3':
      return SWFTOOLS_MP3_DISPLAY;
    case 'jpg':
    case 'gif':
    case 'png':
    case 'jpeg':
    case 'img':
      return SWFTOOLS_IMAGE_DISPLAY_LIST;
    default:

      // Assume that the configured mediaplayer will handle this file or playlist
      return SWFTOOLS_MEDIA_DISPLAY_LIST;
  }
}

/**
 * Identify the currently configured player for the specified action.
 *
 * @param $action
 *   The SWF Tools action to be performed.
 * @return
 *   The name of the currently configured player for this action.
 */
function swftools_get_player($action) {
  switch ($action) {
    case SWFTOOLS_FLV_DISPLAY:
      return variable_get(SWFTOOLS_FLV_DISPLAY, GENERIC_FLV);
    case SWFTOOLS_MP3_DISPLAY:
      return variable_get(SWFTOOLS_MP3_DISPLAY, GENERIC_MP3);
    case SWFTOOLS_SWF_DISPLAY_DIRECT:
      return variable_get(SWFTOOLS_SWF_DISPLAY_DIRECT, SWFTOOLS_SWF);

    // For all other media types the default is FALSE - no player configured
    default:
      return variable_get($action, FALSE);
  }
}

/**
 * Returns the playlist path relative to webroot.
 * This path needs to be writeable, so it is fitting to limit valid
 * locations to the files directory.
 *
 */
function swftools_get_playlist_path($dir = FALSE) {

  // If no directory specified, get the default
  if (!$dir) {
    $dir = variable_get('swftools_playlist_path', SWFTOOLS_PLAYLIST_PATH);
  }

  // Ensure we have a path in the file system
  $dir = file_create_path($dir);

  // Create playlist directory if necessary
  if (!file_check_directory($dir, FILE_CREATE_DIRECTORY)) {
    drupal_set_message(t('%dir does not exist, or is not writeable.', array(
      '%dir' => $dir,
    )), 'error', FALSE);
  }

  // Return path to the playlist directory
  return $dir;
}

/**
 * Returns a flash player path relative to webroot.
 * The default path is in the modules/swftools/shared directory.
 * It may suit some sites to store flash players in an alternative location, but
 * the assumption is the location will be on the same server.
 * If the path starts with '/', then we can assume is relative to the webroot.
 * Otherwise we assume it's in the files directory.
 * 
 * @param $dir
 *   Optional parameter that gives the location of flash media players.
 * @return
 *   String with the path to the media players.
 */
function swftools_get_player_path($dir = FALSE) {

  // If a directory parameter wasn't set then return the configured value
  if (!$dir) {
    $dir = variable_get('swftools_player_path', SWFTOOLS_PLAYER_PATH);

    // If the swftools_player_path variable isn't set return the default path
    if (!$dir) {
      $dir = drupal_get_path('module', 'swftools') . '/shared';
    }
  }
  elseif (substr($dir, 0, 1) == '/') {
    $dir = ltrim($dir, '/');
  }
  else {
    $dir = file_create_path($dir);
  }

  // Return the resulting directory
  return $dir;
}

/**
 * Returns the media path relative to webroot.
 * There is a setting called 'swftools_media_url'. If this is set, we assume the
 * media is on a different server.
 * 
 * @return
 *   A string containing the path to the local files, or empty if the files are remote.
 */
function swftools_get_media_path() {

  // Retrieve the media url setting
  $media_url = trim(variable_get('swftools_media_url', ''));

  // If no media url is set then return the path to local files
  if (!$media_url || $media_url == '') {
    return file_create_path('') . '/';
  }

  // If a media url is set then assume this is a remote path and so we don't know anything
  // about the path between the base url and the file. Return an empty string.
  return '';
}

/**
 * Resolve a path to a full url, either on the local file system, or at a remote address
 * if the swftools_media_url variable has been set. If the path describes a file, is local
 * and the swftools_check_media variable is set then check if the file exists.
 * The path must be relative to the webroot.
 * 
 * @param $path
 *   The file path to check.
 * @param $is_file
 *   Optional flag to indicate that the path points to a file in which case local files can be tested to see if
 *   they exist (defaults to TRUE). If set to FALSE then it indicates the path doesn't refer to a file and it won't be tested.
 * @return
 *   A string with the complete url to the file, either locally or using the remote path, or FALSE if the local file doesn't exist
 */
function swftools_get_media_url($path, $is_file = TRUE) {

  // Retrieve swftools_media_url to see if a remote path has been set
  $media_url = trim(variable_get('swftools_media_url', ''));

  // If a remote path is set simply build the appropriate path and return
  if ($media_url) {
    return $media_url . '/' . $path;
  }

  // If media checking is active, and the path is a file, check to see if it actually exists
  if (variable_get('swftools_check_media', TRUE) && $is_file) {

    // If the file doesn't exist, set an error message and return FALSE to indicate failure
    if (!file_exists($path)) {
      drupal_set_message(t('Could not display the flash because %path does not appear to exist.', array(
        '%path' => $path,
      )), 'error');
      return FALSE;
    }
  }

  // Return the path
  return file_create_url($path);
}

/**
 * "flashvars" is a parameter like height and width, which are
 * passed into the flash player as a=1&b=2&...
 *
 */
function _swftools_get_flashvars_string(&$flashvars) {
  foreach ($flashvars as $var => $value) {
    $flashvars[$var] = str_replace(array(
      '&',
      '=',
      '?',
    ), array(
      '%26',
      '%3D',
      '%3F',
    ), $value);
  }
  $encoded = drupal_query_string_encode($flashvars);

  // '#' seems to encode as %2523, reverse this, using a more robust hex prefix..
  $encoded = str_replace('%2523', '0x', $encoded);

  // Fix encoding per #181998#comment-882293
  $encoded = str_replace('%3A', ':', $encoded);
  $encoded = str_replace('%252F', '/', $encoded);
  return $encoded;
}

/**
 * Return an array of default values to use as the swf parameters.
 * Parameters are described in the Adobe knowledge base TechNote 12701
 * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
 * 
 * @return
 *   An array of key/value pairs
 */
function _swftools_params() {
  $defaults = array(
    'swliveconnect' => variable_get('swftools_params_swliveconnect', 'default'),
    'play' => variable_get('swftools_params_play', TRUE),
    'loop' => variable_get('swftools_params_loop', TRUE),
    'menu' => variable_get('swftools_params_menu', FALSE),
    'quality' => variable_get('swftools_params_quality', 'autohigh'),
    'scale' => variable_get('swftools_params_scale', 'showall'),
    'align' => variable_get('swftools_params_align', 'l'),
    'salign' => variable_get('swftools_params_salign', 'tl'),
    'wmode' => variable_get('swftools_params_wmode', 'opaque'),
    'bgcolor' => variable_get('swftools_params_bgcolor', '#FFFFFF'),
    'version' => variable_get('swftools_params_version', '7'),
    'allowfullscreen' => variable_get('swftools_params_allowfullscreen', TRUE),
    'allowscriptaccess' => variable_get('swftools_params_allowscriptaccess', 'sameDomain'),
  );

  // Ensure that boolean parameters are set to strings 'true' or 'false'
  $defaults['menu'] = _swftools_tf($defaults['menu']);
  $defaults['play'] = _swftools_tf($defaults['play']);
  $defaults['loop'] = _swftools_tf($defaults['loop']);
  $defaults['allowfullscreen'] = _swftools_tf($defaults['allowfullscreen']);

  // Return the defaults
  return $defaults;
}

/**
 * Attempt to return information for the specified file
 * Supply the path to the file to be processed, and it return FALSE if no data
 * was obtained. The return variable, if successful, is an array that may
 * include width, height, extension, file_size, mime_type.
 *
 */
function swftools_get_info($file) {

  // Only check the file if it is local, or it is a media player

  //if (trim(variable_get('swftools_media_url', '')) == '') {
  if (trim(variable_get('swftools_media_url', '')) == '' or strpos($file, swftools_get_player_path()) === 0) {
    $info = image_get_info($file);
    return $info;
  }
  return FALSE;
}

/**
 * Saves a playlist (xml file) to the playlist directory ready for the swf player to use.
 * 
 * @param &$playlist_data
 *   A formatted array of playlist data that will be converted to an xml file. NEED TO DOCUMENT THE STRUCTURE.
 * @param $playlist_name
 *   An optional name for the playlist. If not specified a filename will be created.
 * @param $method
 *   An array describing the selected player method.
 * @param &$vars
 *   Array of variables. Not used by this function, but will be passed to the playlist generator functions.
 * @return
 *   A string containing the path to the playlist, or FALSE if the playlist generation failed.
 *   Note that $playlist_data and $vars can be manipulated by this function.
 */
function swftools_generate_playlist(&$playlist_data, $playlist_name, &$method, &$vars) {

  // If no filename is supplied
  if (!$playlist_name) {

    // Initialise a string
    $prename = '';

    // Iterate through each element of $playlist_data['playlist']
    foreach ($playlist_data['playlist'] as $data) {

      // Build a string using all the filenames
      $prename .= $data['filename'];
    }

    // Hash the resulting string of names and use as the filename
    $playlist_name = md5($method->player['name'] . $prename) . '.xml';
  }

  // Turn the playlist name in to a full path
  $playlist_name = swftools_get_playlist_path() . '/' . $playlist_name;

  // If caching of xml playlist files has been disabled then delete the current playlist by this name
  if (variable_get('swftools_playlist_caching', 'here') == 'always') {
    file_delete($playlist_name);
  }
  elseif (is_file($playlist_name)) {

    // Return path to the file
    return file_create_url($playlist_name);
  }

  // Determine the name of the relevant hook to output the playlist in the appropriate format
  $hook = $method->player['name'] . '_swftools_playlist';

  // Check that the module implements this hook before trying to call it
  if (module_hook($method->player['module'], $hook)) {
    $playlist = module_invoke($method->player['module'], $hook, $playlist_data, $method, $vars);
  }
  else {
    drupal_set_message(t('@title module does not support xml playlists.', array(
      '@title' => $method->player['title'],
    )), 'error');
  }

  // Try to open the playlist file ready to store the xml playlist
  if (!($handle = fopen($playlist_name, 'a'))) {
    drupal_set_message(t('An error occurred trying to create file %playlist_name.', array(
      '%playlist_name' => $playlist_name,
    )), 'error');
    return FALSE;
  }

  // If the file was opened then try to write the playlist data to it
  if (fwrite($handle, $playlist) === FALSE) {
    drupal_set_message(t('An error occurred trying to create file %playlist_name.', array(
      '%playlist_name' => $playlist_name,
    )), 'error');
    return FALSE;
  }

  // Close the file
  fclose($handle);

  // Return a url to the playlist
  return file_create_url($playlist_name);
}

/**
 * Add to the page any supporting files required by a given embedding method.
 * 
 * @param $embed
 *   Optional parameter - if not supplied the files for the current method will be added.
 *   If supplied then the files for the named method will be added.
 * @return
 *   Nothing
 */
function swftools_push_js($embed = SWFDEFAULT) {

  // Get the the currently available methods
  $all_methods = swftools_methods_available();

  // If no specific embedding method was named then get the current default
  if (!$embed) {
    $embed = variable_get(SWFTOOLS_EMBED_METHOD, SWFTOOLS_NOJAVASCRIPT);
  }

  // Call the module responsible to output the js. Don't pass any additional
  // parameters - as we don't want the module to try and return the in-body
  // html placeholder for the flash content.
  $output = module_invoke($all_methods[SWFTOOLS_EMBED_METHOD][$embed]['module'], 'swftools_embed');
}

/**
 * Take an array of filenames and prepare them to be used as a playlist
 * 
 * @param $files
 *   An array of files that will be added to the playlist.
 * @param $title
 *   Optional playlist title
 * @param $get_action
 *   Optional parameter indicating if the function should determine an appropriate action. Default is TRUE.
 * @param $type_filter
 *   Optional parameter - an array of file extensions that are permitted
 * @param $stream
 *   Option parameter to indicate if this is going to be a streamed playlist, in which case checks for the
 *   existence of files should be skipped
 * @return unknown_type
 */
function swftools_prepare_playlist_data($files, $title = '', $get_action = TRUE, $type_filter = array(), $stream = FALSE) {

  // Initialise an array to return the results in
  $playlist_data = array();
  $playlist_data['header']['title'] = $title;

  // Run through all $files and and make the data look the same.
  $id = 0;
  foreach ($files as $key => $data) {
    while (array_key_exists($id, $files)) {
      $id++;
    }
    if (is_object($data)) {
      $files[$key] = (array) $data;
    }
    elseif (!is_array($data)) {

      // Move this file name to a new key to give it the structure of a file attachment array
      $files[$id]['filepath'] = $data;
      if (!is_numeric($key)) {
        $files[$id]['filename'] = $key;
      }
      else {
        $files[$id]['filename'] = $data;
      }
      unset($files[$key]);
    }
  }

  // Check the fileurl element and add generate it if it's missing.
  $playlist_data['playlist'] = $files;
  foreach ($files as $key => $data) {
    if (!isset($data['fileurl'])) {
      if (valid_url($data['filepath'], TRUE)) {

        // A full http:// file path has been passed.
        $playlist_data['playlist'][$key]['filepath'] = FALSE;

        // Flag that we don't know the server path.
        $playlist_data['playlist'][$key]['fileurl'] = $data['filepath'];
      }
      elseif (isset($data['fid'])) {

        // This is a classes upload module files array.
        $playlist_data['playlist'][$key]['filename'] = $data['filename'];
        $playlist_data['playlist'][$key]['fileurl'] = swftools_get_media_url($playlist_data['playlist'][$key]['filepath'], FALSE);
      }
      else {

        // Otherwise just complete url path.
        $playlist_data['playlist'][$key]['filename'] = $data['filename'];
        if (!$stream) {

          //          This code was building the wrong path when used with CCK filefield, so it may have been
          //          causing problems in other circumstances when partial paths were sent to a playlist
          //          $playlist_data['playlist'][$key]['filepath'] = swftools_get_media_path() . $data['filepath'];
          //          $playlist_data['playlist'][$key]['fileurl'] = swftools_strip_base_root(swftools_get_media_url($playlist_data['playlist'][$key]['filepath']));
          //          The code below is taken from the main swf() function, and uses file_create_path first
          // Then check if files are being sourced locally, and if they are build a file path
          if (swftools_get_media_path()) {
            $file = file_create_path($data['filepath']);
          }
          else {
            $file = $data['filepath'];
          }

          // Build a filepath and url
          $playlist_data['playlist'][$key]['filepath'] = $file;
          $playlist_data['playlist'][$key]['fileurl'] = swftools_strip_base_root(swftools_get_media_url($file));
        }
        else {
          $playlist_data['playlist'][$key]['filepath'] = $data['filepath'];
          $playlist_data['playlist'][$key]['fileurl'] = $data['filepath'];
        }
      }
    }
    if (!isset($data['filename'])) {
      $path_parts = pathinfo($playlist_data['playlist'][$key]['fileurl']);
      $playlist_data['playlist'][$key]['filename'] = $path_parts['basename'];
    }
    if (!isset($data['title'])) {
      $playlist_data['playlist'][$key]['title'] = $playlist_data['playlist'][$key]['filename'];
    }

    // Here is where you might call audio.module or video.module for more.
  }

  // Note, we want to exit quickly if the caller did not want us to
  // dynamically determine the display action by passing $get_action = FALSE.
  if (!$get_action) {

    // The caller knows what swftools action to set, so exit here.
    return $playlist_data;
  }

  // Try to work out the action from the files passed.
  $first_valid_file_type = FALSE;
  $mixed_media = FALSE;

  // Process the files attached to the node to determine the correct action.
  foreach ($playlist_data['playlist'] as $key => $data) {

    // fileurl is always set, irrespective of what we are passing, so use this to determine extension
    $path_parts = pathinfo($data['fileurl']);

    // Get the extension for the file
    $extension = strtolower($path_parts['extension']);

    // Only try to determine actions if there's an extension to work with
    if ($extension) {

      // Determine if this is an image type
      if (strpos('|jpg|jpeg|gif|png|', $extension)) {

        // Treat all types of images as the same file type
        $extension = 'img';
      }

      // Only process the file if $type_filter is empty (ie. no filter)
      // or if the extension is declared in the $type_filter array.
      if (!count($type_filter) || in_array($extension, $type_filter)) {

        // $first_valid_file_type stores the file type of the first valid file.
        // This will be compared to subsequent files and if two files
        // have different types, the action will be defined as SWFTOOLS_MEDIA_DISPLAY_LIST
        // in order to utilize a flexible media player.
        if (!$first_valid_file_type) {
          $first_valid_file_type = $extension;
        }
        else {
          if ($first_valid_file_type != $extension) {
            $mixed_media = TRUE;
          }
        }
      }
      else {

        // This file is not desired so remove it
        unset($playlist_data['playlist'][$key]);
      }
    }
  }

  // Make a decision based on analysing the file array.
  if ($first_valid_file_type == '') {

    // No files passed our test.
    return FALSE;
  }

  // Determine the required action.
  if ($mixed_media) {

    // We have files of multiple types.
    $action = SWFTOOLS_MEDIA_DISPLAY_LIST;
  }
  else {

    // We only had one file type, so discover the action for that type by
    // calling swftools_get_action() with a dummy filename
    $action = swftools_get_action('dummy.' . $first_valid_file_type);
  }

  // Pluralize the action for multiple files if not already pluralized
  if (count($playlist_data['playlist']) > 1 && substr($action, -5, 5) != '_list') {
    $action = $action . '_list';
  }

  // Assign the action to the playlist data ready for return
  $playlist_data['action'] = $action;

  // Return the resulting playlist data
  return $playlist_data;
}

/**
 * Next three filter related code ported from flash_filter.
 *
 */

/*
 * Implementation of hook_filter_tips
 *
 */
function swftools_filter_tips($delta, $format, $long = false) {
  if ($long) {
    return t('
    <h3 id="swftools_filter">SWF Tools Filter</h3>
    <p>The basic syntax for embedding a flash file (.swf), flash movie (.flv) or audio file (.mp3) is:</p>
    <blockquote><code>[swf file="filename.swf"]</code></blockquote>

    <p>If you would like to override SWF Tools and flash player default settings,
       you can specify additional parameters. For example:</p>
    <blockquote><code>[swf file="song.mp3" flashvars="backcolor=#AABBCC&&forecolor=#11AA11"]</code></blockquote>
    <p>If you would like to output a list of files then the format is:</p>
    <blockquote><code>[swf files="image1.jpg&&image2.jpg&&..."]</code></blockquote>
    SWF Tools Filter will accept following:
    <ul>
      <li><b>params</b> : You can specify values for parameters to be passed to Flash
                           to control the appearance of the output. Typical values are
                           bgcolor and wmode. Example: <code>params="wmode=true&&bgcolor="#00FF00"</code>
                           Alternatively you can supply each parameter individually without using
                           <code>params</code>. Example <code>wmode="true" bgcolor="#00FF00"</code></li>
      <li><b>flashvars</b> : You can specify values for output as flashvars, which
                           become available to the Flash movie that is playing. This is often done
                           to control a media player. Refer to the documentation of the flash player
                           you are using to know what flashvar options are available.
                           Example: <code>flashvars="autostart=true&&volume=80"</code></li>
      <li><b>methods</b> : Optional information about how to display the file. The most
                           common usage is to specify a particular media player and
                           thus override the default specified on the settings page.
                           Example: <code>methods="player=onepixelout_mp3"</code></li>
       </ul>
      <p><strong>WARNING</strong>: with params, flashvars and othervars, pass multiple values
                      separated by <strong>&amp;&amp;</strong>.</p>');
  }
  else {
    return t('You may use !swftools_filter_help to display Flash files inline', array(
      "!swftools_filter_help" => l('[swf file="song.mp3"]', "filter/tips/{$format}", array(
        'query' => 'swftools_filter',
      )),
    ));
  }
}

/*
 * Implementation of hook_filter
 *
 */
function swftools_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return array(
        0 => t('SWF Tools filter'),
      );
    case 'no cache':
      return FALSE;
    case 'description':
      return t('Substitutes [swf file="filename.flv"] or [swf files="file1.jpg&&file2.jpg"] with embedding code.');
    case 'prepare':

      // replace <swf > with [swf ] to prevent other filters stripping
      return preg_replace('/\\<(swflist|swf)\\s*(.*)>/sU', '[\\1 \\2]', $text);
    case 'process':
      return _swftools_filter_process_text($text);
  }
}

/*
 * This function processes the filter text that the user has added to the text area.
 * If the filter is wrapped in <p></p> then these are stripped as part of the processing
 * This eliminates a validation error in the resulting mark up if SWF Tools filter is
 * being used in conjunction with other HTML filters that correct line breaks.
 * It won't work in EVERY case, but it will work in MOST cases.
 * Filters that are embedded in-line with text will continue to fail validation.
 */
function _swftools_filter_process_text($text) {
  $endl = chr(13);
  if (preg_match_all('@(?:<p>)?\\[(swflist|swf)\\s*(.*?)\\](?:</p>)?@s', $text, $match)) {

    // $match[0][#] .... fully matched string <swf|swflist parm_0="value_0" parm_1="value_1" parm_2="value_2">
    // $match[1][#] .... matched tag type ( swf | swflist )
    // $match[2][#] .... full params string until the closing '>'
    $swftools_parameters = array(
      'file',
      'params',
      'flashvars',
      'othervars',
      'methods',
      'files',
    );
    $match_vars = array();
    foreach ($match[2] as $key => $passed_parameters) {

      //preg_match_all('/(\w*)=\"(.*?)\"/', $passed_parameters, $match_vars[$key]);
      preg_match_all('/(\\w*)=(?:\\"|&quot;)(.*?)(?:\\"|&quot;)/', $passed_parameters, $match_vars[$key]);

      // $match_vars[0][#] .... fully matched string
      // $match_vars[1][#] .... matched parameter, eg flashvars, params
      // $match_vars[2][#] .... value after the '='
      // Process the parameters onto the $prepared array.
      // Search for standard parameters, parse the values out onto the array.
      foreach ($match_vars[$key][1] as $vars_key => $vars_name) {

        // Switch to swf or swflist, based on file or files
        // Need to tidy up this line, probably use switch/case
        if ($vars_name == 'file') {
          $match[1][$key] = 'swf';
        }
        else {
          if ($vars_name == 'files') {
            $match[1][$key] = 'swflist';
          }
        }
        if ($vars_name == 'file') {
          $prepared[$key][$vars_name] = $match_vars[$key][2][$vars_key];
          unset($match_vars[$key][1][$vars_key]);
        }
        elseif (in_array($vars_name, $swftools_parameters)) {
          $prepared[$key][$vars_name] = swftools_url_parse(str_replace(array(
            '&amp;&amp;',
            '&&',
          ), '&', $match_vars[$key][2][$vars_key]));
          unset($match_vars[$key][1][$vars_key]);
        }
        else {
          $prepared[$key]['othervars'][$vars_name] = $match_vars[$key][2][$vars_key];
        }
      }

      // Search for remaining parameters, map them as elements of the standard parameters.
      if (isset($prepared[$key]['methods']['player'])) {
        $player = strtolower($prepared[$key]['methods']['player']);
      }
      else {
        $player_key = array_search('player', $match_vars[$key][1]);
        if ($player_key !== FALSE) {
          $player = strtolower($match_vars[$key][2][$player_key]);
        }
        else {
          $player = FALSE;
        }
      }
      $prepared[$key]['methods']['player'] = $player;
      if (count($match_vars[$key][1])) {

        // Find out if a player has been set.
        foreach ($match_vars[$key][1] as $vars_key => $vars_name) {
          if ($parent = swftools_get_filter_alias($vars_name, $player)) {
            if ($parent) {
              $prepared[$key][$parent][$vars_name] = $match_vars[$key][2][$vars_key];
            }
          }
        }
      }

      // Just assigning parameters as false if not already set on the $prepared array.
      // Really just to avoid declaration warnings when we call swf and swf_list
      if (count($prepared[$key])) {
        foreach ($swftools_parameters as $swfparameter) {
          if (!isset($prepared[$key][$swfparameter])) {
            $prepared[$key][$swfparameter] = FALSE;
          }
        }
      }

      // Assemble in to an array of options ready to pass
      $options = array();
      $options['params'] = $prepared[$key]['params'];
      $options['flashvars'] = $prepared[$key]['flashvars'];
      $options['othervars'] = $prepared[$key]['othervars'];
      $options['methods'] = $prepared[$key]['methods'];

      // Set a flag to show if we need to determine an action, or if one was provided
      $get_action = TRUE;
      if (isset($options['methods']['action'])) {
        $get_action = FALSE;
      }
      switch ($match[1][$key]) {
        case 'swf':
          $replace = swf($prepared[$key]['file'], $options);
          break;
        case 'swflist':
          if ($prepared[$key]['files']) {
            foreach ($prepared[$key]['files'] as $name => $filename) {
              if (!$filename) {
                $prepared[$key]['files'][$name] = $name;
              }
            }

            // Work out if this is a streamed playlist (in which case we will skip file existence checks)
            $stream = FALSE;
            if (isset($options['othervars']['stream'])) {
              $stream = TRUE;
            }

            // Get playlist data, but don't determine action if the user specified a player

            //$playlist_data = swftools_prepare_playlist_data($prepared[$key]['files'], '', !$player, array(), $stream);
            $playlist_data = swftools_prepare_playlist_data($prepared[$key]['files'], '', $get_action, array(), $stream);
            $replace = swf_list($playlist_data, $options);
          }
          else {
            $replace = '<!-- No files passed to the playlist -->';
          }
          break;
      }
      $matched[] = $match[0][$key];
      $rewrite[] = $replace;
    }
    return str_replace($matched, $rewrite, $text);
  }
  return $text;
}

/*
 * This implements a hook that extends the parameters that can be passed to the filter
 * so that myvar="value" can be mapped to flashvars, etc.
 *
 */
function swftools_get_filter_alias($var, $player = FALSE) {
  static $general_mapping = array();
  static $player_mapping = array();
  if (!count($general_mapping)) {

    // Build up the mapping arrays.
    $general_mapping = array(
      'action' => 'methods',
      'embed' => 'methods',
      'width' => 'params',
      'height' => 'params',
      'swliveconnect' => 'params',
      'play' => 'params',
      'loop' => 'params',
      'menu' => 'params',
      'quality' => 'params',
      'scale' => 'params',
      'align' => 'params',
      'salign' => 'params',
      'wmode' => 'params',
      'bgcolor' => 'params',
      'base' => 'params',
      'version' => 'params',
      'allowfullscreen' => 'params',
      'allowscriptaccess' => 'params',
    );
    if (!count($player_mapping)) {
      $player_mapping = module_invoke_all('swftools_variable_mapping');
    }
    $combined = array();
    if (count($player_mapping)) {
      foreach ($player_mapping as $mapping) {
        $combined = array_merge($combined, $mapping);
      }
      $general_mapping = array_merge($combined, $general_mapping);
    }
  }

  // Return the parent of the variable.
  if ($player && isset($player_mapping[$player][$var])) {
    return $player_mapping[$player][$var];
  }
  else {
    return isset($general_mapping[$var]) ? $general_mapping[$var] : FALSE;
  }
}
function swftools_url_parse($string) {
  $return = array();
  $pairs = split("&", $string);
  foreach ($pairs as $pair) {
    $splitpair = split("=", $pair);

    //if(!$splitpair[1] || array_key_exists($splitpair[0], $return)) {
    if (!isset($splitpair[1]) || array_key_exists($splitpair[0], $return)) {
      $return[] = $splitpair[0];
    }
    else {
      $return[$splitpair[0]] = $splitpair[1];
    }
  }
  return $return;
}

/**
 * Implementation of hook_theme
 */
function swftools_theme() {
  return array(
    'swftools_embed' => array(
      'arguments' => array(
        'embed_code' => NULL,
        'action' => NULL,
        'methods' => NULL,
        'vars' => array(),
        'html_alt' => NULL,
      ),
    ),
    'swftools_formatter_swftools' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_swftools_formatter_swftools',
    ),
    'swftools_formatter_swftools_no_file' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_swftools_formatter_swftools',
    ),
    'swftools_formatter_swftools_playlist' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_swftools_formatter_playlist',
    ),
  );
}

/**
 * Implementation of hook_file_download
 * Allows SWF Tools to work with a private file system that might include files
 * upload outside the control of an upload module, e.g. FTP of large video files
 * If the file is in the playlists directory then return a valid header.
 * If the file is of a supported type, based on extension, then return a valid header.
 * Note: if any other module returns -1 for this file then access will be denied
 * even if SWF Tools tries to allow it. See hook_file_download for details.
 */
function swftools_file_download($file) {

  // See if we have a playlist - SWF Tools can allow access to those since it creates them
  $playlist_path = preg_quote(variable_get('swftools_playlist_path', SWFTOOLS_PLAYLIST_PATH));
  if (preg_match('/^' . $playlist_path . '/', $file)) {
    return array(
      'Content-Type: ' . $mime_types[$extension],
      'Content-Length: ' . filesize(file_create_path($file)),
    );
  }

  // If SWF Tools is allowed to grant access then check to see if access will be allowed
  if (variable_get('swftools_grant_access_to_private_files', SWFTOOLS_GRANT_ACCESS_TO_PRIVATE_FILES)) {

    // Get extension of file in question
    $extension = pathinfo($file, PATHINFO_EXTENSION);

    // Get list of extensions that SWF Tools can grant access to
    $extensions = variable_get('swftools_grant_access_extensions', SWFTOOLS_GRANT_ACCESS_EXTENSIONS);

    // Need access to the user object
    global $user;

    // Check if SWF Tools should grant access - skip the check for user #1
    if ($user->uid != 1) {
      $regex = '/\\.(' . ereg_replace(' +', '|', preg_quote($extensions)) . ')$/i';
      if (!preg_match($regex, $file)) {
        return;
      }
    }

    // Build an array of types that SWF Tools can react to
    $mime_types = array(
      'swf' => 'application/x-shockwave-flash',
      'flv' => 'application/octet-stream',
      'xml' => 'text/xml',
      'mp3' => 'audio/mpeg',
      'jpg' => 'image/jpeg',
      'jpeg' => 'image/jpeg',
      'png' => 'image/gif',
    );

    // If file is one of the above types, based on the extension, return headers
    if ($mime_types[$extension]) {
      return array(
        'Content-Type: ' . $mime_types[$extension],
        'Content-Length: ' . filesize(file_create_path($file)),
      );
    }
  }
}

/**
 * Implementation of swftools_embed hook
 * Returns the markup for the page.
 * This method generates standards compliant HTML
 *
 */
function swftools_swftools_embed($action = 'add_js', $methods = FALSE, $vars = FALSE, $html_alt = '') {

  // If simply adding JavaScript then no further action is necessary
  if ($action == 'add_js') {
    return;
  }

  // An id isn't always set, so populate a blank to avoid a notice error later
  $vars->othervars += array(
    'id' => '',
  );

  // IE6 says the page has error when using Wijering 4 media player and if the object isn't given an id
  // The id must be unique for each player, and must start with letters - it cannot be only numbers
  // So let's generate a unique id in the same way we do with SWF Object, and assign it to our object
  $wijering_fix = '';

  // Initialise a counter to give each div a unique id
  static $unique_id = 0;
  $unique_id++;

  // Construct a unique id for each div by using time() combined with $unique_id
  // This is necessary to prevent clashes between cached content
  $id = time() . $unique_id;
  $wijering_fix = ' id="swf' . $id . '"';
  $P = $vars->params;

  // For legibility.
  $width_attr = $P['width'] ? ' width="' . $P['width'] . '"' : '';
  $height_attr = $P['height'] ? ' height="' . $P['height'] . '"' : '';
  $loop = _swftools_tf($P['loop']);
  $menu = _swftools_tf($P['menu']);
  $play = _swftools_tf($P['play']);
  $fullscreen = _swftools_tf($P['allowfullscreen']);
  $flashvars = str_replace('&', '&amp;', $P['flashvars']);
  $id = $vars->othervars['id'] ? ' id="' . $vars->othervars['id'] . '"' : '';
  $name = $vars->othervars['id'] ? ' name="' . $vars->othervars['id'] . '"' : '';
  $swliveconnect = $P['swliveconnect'] ? ' swliveconnect="' . $P['swliveconnect'] . '"' : '';
  $params = $id;
  $params .= '<param name="allowScriptAccess" value="' . $P['allowscriptaccess'] . '" />' . "\n";
  $params .= '<param name="wmode"             value="' . $P['wmode'] . '" />' . "\n";
  $params .= '<param name="bgcolor"           value="' . $P['bgcolor'] . '" />' . "\n";
  $params .= '<param name="scale"             value="' . $P['scale'] . '" />' . "\n";
  $params .= '<param name="quality"           value="' . $P['quality'] . '" />' . "\n";
  $params .= '<param name="align"             value="' . $P['align'] . '" />' . "\n";
  $params .= '<param name="allowfullscreen"   value="' . $P['allowfullscreen'] . '" />' . "\n";
  $params .= '<param name="base"              value="' . $P['base'] . '" />' . "\n";
  $params .= '<param name="play"              value="' . $play . '" />' . "\n";
  $params .= '<param name="menu"              value="' . $menu . '" />' . "\n";
  $params .= '<param name="loop"              value="' . $loop . '" />' . "\n";
  $params .= $flashvars ? '<param name="flashvars"  value="' . $flashvars . '" />' . "\n" : '';
  $html = '<div class="swftools">' . "\n";
  $html .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' . $width_attr . $height_attr . $wijering_fix . '>' . "\n";
  $html .= '<param name="movie" value="' . $P['src'] . '" />' . "\n";
  $html .= $params;
  $html .= '<!--[if gte IE 7]>-->' . "\n";
  $html .= '<object type="application/x-shockwave-flash" data="' . $P['src'] . '"' . $width_attr . $height_attr . '>' . "\n";
  $html .= $params;
  $html .= '<!--<![endif]-->' . "\n";
  $html .= $html_alt . "\n";
  $html .= '<!--[if gte IE 7]>-->' . "\n";
  $html .= '</object>' . "\n";
  $html .= '<!--<![endif]-->' . "\n";
  $html .= '</object>' . "\n";
  $html .= '</div>' . "\n";
  return $html;
}

/*
 * Called by settings pages for players as a custom handler in place of system_settings_form_submit()
 * It flattens extensive arrays of settings, and resets the filter cache
 */
function swftools_admin_form_submit($form, &$form_state) {

  // Determine what operation is being performed and store in $op
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';

  // Exclude unnecessary elements
  unset($form_state['values']['submit'], $form_state['values']['reset'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token'], $form_state['values']['form_build_id']);

  // Flatten settings for saving
  $saved = array();

  // Process array of parameters that have been passed
  foreach ($form_state['values'] as $player => $settings) {
    if ($op == t('Reset to defaults')) {
      variable_del('swftools_' . $player);
    }
    else {
      $flat[$player] = array();
      if (is_array($settings)) {
        foreach ($settings as $category => $vars) {
          $flat[$player] = array_merge($flat[$player], $vars);
        }
        variable_set('swftools_' . $player, $flat[$player]);
      }
    }
  }

  // Confirmation message
  if ($op == t('Reset to defaults')) {
    drupal_set_message(t('The configuration options have been reset to their default values.'));
  }
  else {
    drupal_set_message(t('The configuration options have been saved.'));
  }

  // Clear caches
  drupal_flush_all_caches();
}

/**
 * Report the methods that are supported by the SWF Tools module.
 * 
 * @return
 *   An array of methods and players provided by the default SWF Tools installation.
 */
function swftools_swftools_methods() {

  // Initialise array
  $methods = array();

  // Module implements a default plain HTML embedding method called 'direct'
  $methods[SWFTOOLS_EMBED_METHOD][SWFTOOLS_NOJAVASCRIPT] = array(
    'name' => SWFTOOLS_NOJAVASCRIPT,
    'module' => 'swftools',
    'shared_file' => '',
    'title' => t('Direct embedding - do not use JavaScript replacement'),
  );

  // Module implements swf embedding
  $methods[SWFTOOLS_SWF_DISPLAY_DIRECT][SWFTOOLS_SWF] = array(
    'name' => SWFTOOLS_SWF,
    'module' => 'swftools',
    'shared_file' => '',
    'title' => t('Use SWF file directly, no streaming through another SWF.'),
  );

  // Module implements custom embedding of an swf
  $methods[SWFTOOLS_SWF_DISPLAY_DIRECT][SWFTOOLS_CUSTOM] = array(
    'name' => SWFTOOLS_CUSTOM,
    'module' => 'swftools',
    'shared_file' => '',
    // Assigned later.
    'title' => t('Use custom SWF file.'),
  );

  // Add in the methods from genericplayers.module
  $methods = array_merge($methods, genericplayers_swftools_methods());

  // Return the methods that are native to SWF Tools
  return $methods;
}

/**
 * Return a customised file download url that doesn't include the $base_root
 * 
 * @param $file
 *   The path of the file for which a download link is return
 * @return
 *   The path to the file including any $base_path but excluding $base_root
 */
function swftools_strip_base_root($file) {

  // Temporarily disable this feature - it may be causing some issues
  return $file;

  // Only produce relative url if using clean urls
  return str_replace($GLOBALS['base_root'], '', $file);
}

/**
 * Helper function to set the size of the swf content in to $vars->params
 * 
 * @param $vars
 *   $vars arrays that is being assembled by SWF Tools.
 * @param $player
 *   The array of player data for the player that will be used.
 * @return
 *   Nothing - function directly sets $vars.
 */
function swftools_set_size(&$vars, $player = array()) {

  // Not a pretty piece of code, but should be ok for the moment. We are
  // purposefully passing the width and height
  // if we have them. Unsure if this will cause problems with some players.
  // It's an ugly piece of code, but will remain in this form until a clearer
  // solution arises.
  //
  // It may be that, in hook_swftools_methods, the flash player indicates that
  // it *want* certain values copied b/t params and flashvars.
  // The code below was patch to fix notice errors, but it broke flash node autodetect
  // Flash node has been patched to fix this by changing zero height / width to null
  // TODO : Is it really necessary to set the height and width in to the flashvars?
  // If flashvars are empty, but params are set, populate flashvars with params
  if (empty($vars->flashvars['width']) && empty($vars->flashvars['height'])) {
    if (!empty($vars->params['width']) && !empty($vars->params['height'])) {
      $vars->flashvars['width'] = $vars->params['width'];
      $vars->flashvars['height'] = $vars->params['height'];
      return;
    }
  }

  // If params are empty, but flashvars are set, populate params with flashvars
  if (empty($vars->params['width']) && empty($vars->params['height'])) {
    if (!empty($vars->flashvars['width']) && !empty($vars->flashvars['height'])) {
      $vars->params['width'] = $vars->flashvars['width'];
      $vars->params['height'] = $vars->flashvars['height'];
      return;
    }
  }

  // If still empty we try and get them from the file to be embedded
  if (empty($vars->params['height']) || empty($vars->params['width'])) {
    $info = swftools_get_info($vars->params['src_path']);
    if ($info) {
      $vars->params['height'] = $info['height'];
      $vars->params['width'] = $info['width'];
      return;
    }
  }

  // If we STILL don't have a width after all this, try to use fallback player defaults
  if (empty($vars->params['width']) && isset($player['width'])) {
    $vars->params['width'] = $player['width'];
  }

  // If we STILL don't have a height after all this, try to use fallback player defaults
  if (empty($vars->params['height']) && isset($player['height'])) {
    $vars->params['height'] = $player['height'];
  }
}

/**
 * Implementation of hook_field_formatter_info().
 */
function swftools_field_formatter_info() {
  return array(
    'swftools_no_file' => array(
      'label' => t('SWF Tools - no download link'),
      'field types' => array(
        'filefield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'swftools_playlist' => array(
      'label' => t('SWF Tools - playlist'),
      'field types' => array(
        'filefield',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
    'swftools' => array(
      'label' => t('SWF Tools - with download link'),
      'field types' => array(
        'filefield',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
  );
}

/**
 * Theme function to turn CCK filefield in to flash content.
 * 
 * @param $element
 *   The element to render.
 * @return
 *   A string of markup to produce the flash content, or nothing if the element was empty.
 */
function theme_swftools_formatter_swftools($element) {

  // If the element is empty return
  if (empty($element['#item']['fid'])) {
    return '';
  }

  // Get the markup for the flash content from swf()
  $return = swf($element['#item']['filepath']);

  // Add the filefield download link if required
  if ($element['#formatter'] == 'swftools') {
    $return .= "\n" . theme('filefield_formatter_default', $element);
  }

  // Return the resulting markup
  return $return;
}

/**
 * Theme function to turn multiple value CCK filefield in to a playlist.
 * 
 * @param $element
 *   The element to render.
 * @return
 *   A string of markup to produce the flash content, or nothing if the element was empty.
 */
function theme_swftools_formatter_playlist($element) {

  // Initialise an array for results
  $files = array();

  // Get the children
  $children = element_children($element);

  // If there is only one child then maybe we don't want a playlist
  if (count($children) == 1) {

    // Pop the first value of the children array
    $_children = $children;
    $child = array_pop($_children);

    // Get the name of the alternate formatter for this content type
    $formatter_name = variable_get('swftools_' . $element['#type_name'] . '_' . $element['#field_name'], 'swftools_playlist');

    // What happens next depends on the formatter name
    switch ($formatter_name) {
      case 'hidden':

        // If the format is set to hidden then return nothing
        if ($formatter_name == 'hidden') {
          return;
        }
      case 'swftools_playlist':

        // If swftools_playlist don't do anything different
        break;
      default:

        // Find out what the alternate formatter should be
        if ($formatter = _content_get_formatter($formatter_name, 'filefield')) {
          $theme = $formatter['module'] . '_formatter_' . $formatter_name;

          // Theme the element according to the alternate formatter
          return theme($theme, $element[$child]);
        }
    }
  }

  // Cycle through the file elements
  foreach ($children as $key) {

    // If nothing has been uploaded then there are items, but they are empty, so check they are set
    if (isset($element[$key]['#item']['filepath'])) {
      $files[] = $element[$key]['#item']['filepath'];
    }
  }

  // If files array is empty then there is nothing to be rendered
  if (empty($files)) {
    return;
  }

  // But if we got something then we can call swf() now to render it
  return swf($files);
}

/**
 * Invokes hook_swftools_flashvars() in the relevant player module.
 * 
 * We cannot use module_invoke() for this, because the arguments need to be passed by reference.
 * 
 * @param $action
 *   String defining the action that is to be performed, eg SWFTOOLS_FLV_DISPLAY
 * @param &$methods
 *   Object containing two keys - player and method. Each consists of an array
 *   that defines the details of the resolved player and embedding method that
 *   is being used for this file.
 * @param &$vars
 *   Object containing three keys - othervars, flashvars and params. These are
 *   arrays containing key/value pairs that contain all the data assigned to this
 *   file so far. Refer to swf() for more details about the $vars array.
 * @return
 *   Return an array of flashvars needed to allow the player to work.
 */
function swftools_flashvars_invoke($action, &$methods, &$vars) {

  // Build the name of the function we are going to call
  $function = $methods->player['module'] . '_swftools_flashvars';

  // Call the function and return the resulting flashvars to the caller
  return $function($action, $methods, $vars);
}

Functions

Namesort descending Description
swf Return output, which might be embed markup, or pre-flash markup that includes the appropriate jQuery added to the <head>
swftools_admin_form_submit
swftools_field_formatter_info Implementation of hook_field_formatter_info().
swftools_file_download Implementation of hook_file_download Allows SWF Tools to work with a private file system that might include files upload outside the control of an upload module, e.g. FTP of large video files If the file is in the playlists directory then return a…
swftools_filter
swftools_filter_tips
swftools_flashvars_invoke Invokes hook_swftools_flashvars() in the relevant player module.
swftools_generate_playlist Saves a playlist (xml file) to the playlist directory ready for the swf player to use.
swftools_get_action Identify the most likely SWF Tools action for a file, based on its extension.
swftools_get_filter_alias
swftools_get_info Attempt to return information for the specified file Supply the path to the file to be processed, and it return FALSE if no data was obtained. The return variable, if successful, is an array that may include width, height, extension, file_size, mime_type.
swftools_get_media_path Returns the media path relative to webroot. There is a setting called 'swftools_media_url'. If this is set, we assume the media is on a different server.
swftools_get_media_url Resolve a path to a full url, either on the local file system, or at a remote address if the swftools_media_url variable has been set. If the path describes a file, is local and the swftools_check_media variable is set then check if the file…
swftools_get_player Identify the currently configured player for the specified action.
swftools_get_player_path Returns a flash player path relative to webroot. The default path is in the modules/swftools/shared directory. It may suit some sites to store flash players in an alternative location, but the assumption is the location will be on the same server. If…
swftools_get_playlist_path Returns the playlist path relative to webroot. This path needs to be writeable, so it is fitting to limit valid locations to the files directory.
swftools_init Implementation of hook_init() swftools_init() is used to force embedding JavaScript on to all pages
swftools_json_params
swftools_menu Implementation of hook_menu().
swftools_methods_available Collect information from all modules about the players and embedding methods available.
swftools_perm Implementation of hook_perm().
swftools_prepare_playlist_data Take an array of filenames and prepare them to be used as a playlist
swftools_push_js Add to the page any supporting files required by a given embedding method.
swftools_set_size Helper function to set the size of the swf content in to $vars->params
swftools_strip_base_root Return a customised file download url that doesn't include the $base_root
swftools_swftools_embed Implementation of swftools_embed hook Returns the markup for the page. This method generates standards compliant HTML
swftools_swftools_methods Report the methods that are supported by the SWF Tools module.
swftools_theme Implementation of hook_theme
swftools_url_parse
swf_list Take an array of play list data and options, and return a markup string.
theme_swftools_embed Produce finished markup ready for inserting on the page
theme_swftools_formatter_playlist Theme function to turn multiple value CCK filefield in to a playlist.
theme_swftools_formatter_swftools Theme function to turn CCK filefield in to flash content.
_swftools_filter_process_text
_swftools_get_flashvars_string "flashvars" is a parameter like height and width, which are passed into the flash player as a=1&b=2&...
_swftools_params Return an array of default values to use as the swf parameters. Parameters are described in the Adobe knowledge base TechNote 12701 http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
_swftools_tf Returns 'true' or 'false' for JavaScript based the supplied value $bool.

Constants