'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' => -2,
'page callback' => 'drupal_get_form',
'page arguments' => array('swftools_admin_handling_form'),
'file' => 'includes/swftools.admin.inc',
);
$items['swftools/playlist/%'] = array(
'title' => 'SWF Tools playlist',
'page callback' => 'swftools_get_xml',
'page arguments' => array(2),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
$items['swftools/page/%'] = array(
'title' => 'SWF Tools',
'page callback' => 'swftools_get_html',
'page arguments' => array(2),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
$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' => 'includes/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' => 'includes/swftools.admin.inc',
);
}
// Add SWF Tools status report
$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' => 'includes/swftools.admin.status.inc',
'weight' => 9,
);
// Integrate items from the generic players module
$items = array_merge($items, swftools_genericplayers_menu());
// Return array of menu items
return $items;
}
/**
* Implementation of hook_perm().
*/
function swftools_perm() {
return array(
'administer flash',
);
}
/**
* Processes a file, or an array of files, and returns the relevant mark-up to render a
* Flash based player.
*
* @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 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.
*
* @ingroup swftools
*/
function swf($file, $options = array()) {
// $time_start = microtime(true);
// TODO: We should put SWF Tools own settings somewhere safe in the othervars array
// If someone passes a variable from the input filter it could collide.
// Maybe put them under #swftools (since the data are properties of swftools?)
// A finished item has player, profile, cid, id, file_url, src_path, src
// Initialise any $options array elements that weren't passed by the caller
$options += array(
'params' => array(),
'flashvars' => array(),
'othervars' => array(),
'methods' => array(),
);
// Initialise othervars with some defaults
$options['othervars'] += array(
'profile' => '',
'return' => SWFTOOLS_RETURN_MARKUP,
'html_alt' => t(variable_get('swftools_html_alt', SWFTOOLS_DEFAULT_HTML_ALT)),
'playlist_data' => '',
'image' => '',
'id' => '',
'stream' => FALSE,
);
// Initialise methods with some defaults
$options['methods'] += array(
'action' => '',
'player' => '',
'embed' => '',
// 'stream' => '',
);
// Initialise params with some defaults
$options['params'] += array(
'base' => swftools_get_base(),
);
// See if we can get this item from the SWF Tools cache
if (($ret = swftools_get_from_cache($file, $options)) && variable_get('swftools_cache', CACHE_NORMAL)) {
// $time_end = microtime(true);
// $time = $time_end - $time_start;
// dsm('Used cache in ' . $time);
if ($ret->headers && $script_location = variable_get('swftools_javascript_location', SWFTOOLS_JAVASCRIPT_INLINE)) {
drupal_add_js($ret->headers, 'inline', $script_location == SWFTOOLS_JAVASCRIPT_HEADER ? 'header' : 'footer');
}
return $options['othervars']['return'] == SWFTOOLS_RETURN_CID ? $options['othervars']['return'] : $ret->data;
}
// Ensure id is unique, or assign an id if one isn't set
$options['othervars']['id'] = swftools_get_id($options['othervars']['id']);
// If swf() was called with an array of files, make a playlist
if (is_array($file)) {
// Turn the array in to a playlist and attach it to othervars
swftools_prepare_playlist($file, $options);
}
// ACTION
// Work out what SWF Tools should do with this file (e.g. video, audio)
// If an explicit action wasn't set then try to determine an appropriate one using the filename
$options['methods']['action'] = $options['methods']['action'] ? swftools_fix_old_action_names($options['methods']['action']) : swftools_get_action($file);
// RESOLVE PLAYER AND EMBEDDING
// 'resolved' refers to the fact that these are the methods we now intend to use, not /all/ methods available.
// PLAYER
// Work out what player SWF Tools will need to use for this action
// If an explicit player wasn't set then find out what player is configured for the current action
$options['methods']['player'] = $options['methods']['player'] ? swftools_fix_old_player_names($options['methods']['player']) : swftools_get_player($options['methods']['action'], $options['othervars']['profile']);
// If there is no player assigned we don't what to do with this action
if (!$options['methods']['player']) {
// Get the descriptions that go with the actions
$actions = swftools_get_actions();
// If we have a matching description for the specified action, create a meaningful message
if (isset($actions[$options['methods']['action']]['#description'])) {
// If we also have a meaningful profile name use that too
if ($options['othervars']['profile']) {
if (function_exists('swftools_profiles_get_profile') && ($profile = swftools_profiles_get_profile($options['othervars']['profile']))) {
$profile = $profile['name'];
}
else {
$profile = $options['othervars']['profile'];
}
$profile = t('@profile profile', array('@profile' => $profile));
}
else {
$profile = 'SWF Tools';
}
// And output a message
swftools_set_error('swftools', 'No player is configured for %action. Check the %profile file handling settings.', array('%action' => $actions[$options['methods']['action']]['#description'], '%profile' => $profile), WATCHDOG_WARNING);
}
// Otherwise we have an action that SWF Tools doesn't understand, so create a fallback message
else {
swftools_set_error('swftools', 'No modules have registered the action %action. Check any required supporting modules are enabled.', array('%action' => $options['methods']['action']), WATCHDOG_WARNING);
}
// We couldn't find a player for this content, so fallback to the alternate markup and return
return $options['othervars']['html_alt'];
}
// Get all the actions, tools and embedding options available to us
$all_methods = swftools_get_methods();
// Check that the action / player combination is valid (it should appear in the array of all methods)
if (isset($all_methods[$options['methods']['action']][$options['methods']['player']])) {
// The combination was found, place player information in to resolved_methods
$options['resolved_methods']['player'] = $all_methods[$options['methods']['action']][$options['methods']['player']];
}
// If the action / player combination doesn't appear then we give up here
else {
// Get the descriptions that go with the actions
$actions = swftools_get_actions();
// Set an error
swftools_set_error('swftools', 'The combination of %player with %action is not valid. Check that the player is available and that it supports the requested action.', array('%player' => $options['methods']['player'], '%action' => $options['methods']['action']), WATCHDOG_WARNING);
// Return alternate markup
return $options['othervars']['html_alt'];
}
// EMBED
// Work out what embedding method SWF Tools should use for this content
// If an explicit embed method was not set then assign one now
$options['methods']['embed'] = $options['methods']['embed'] ? $options['methods']['embed'] : variable_get('swftools_embed_method', 'swftools_direct');
// Place the embedding method information in to resolved_methods
$options['resolved_methods']['embed'] = $all_methods['swftools_embed_method'][$options['methods']['embed']];
// PARAMS
// If $options['params'] is not an array then assume it is width x height as a string
// TODO: This is an ugly legacy - can we retire it?
if (!is_array($options['params'])) {
// Explode string
$dimensions = explode('x', $options['params']);
// If we got two pieces assume success
if (count($dimensions) == 2) {
$options['params'] = array(
'width' => $dimensions[0],
'height' => $dimensions[1],
);
}
}
// FLASHVARS
// If the flashvars were passed as a string then turn it in to an array
if (!is_array($options['flashvars'])) {
parse_str($options['flashvars'], $options['flashvars']);
}
// XML PLAYLIST
// Determine if we are trying to generate a playlist that needs xml output, and create it if required
// If $options['othervars']['playlist_data'] is set then we are processing a playlist
if ($options['othervars']['playlist_data']) {
// Try to generate an xml playlist and get the path to the xml file. $file will be an empty string if we don't need xml.
$file = swftools_generate_playlist($options);
}
// FILE
// Make sure that the file path in $file is valid, and as necessary try to
// expand it to a relative url on the local file system, or point to the remote media directory
// First we assume that we can just set $file_url to the value in $file
$file_url = $file;
// If we are not streaming this file, and $file isn't empty, then we might need to process it to get a proper path
if (!$options['othervars']['stream'] && $file) {
// Process to get a url (in src) and expand the path (in src_path) if necessary
$source = swftools_get_url_and_path($file);
// If FALSE was returned then the file doesn't exist so return $html_alt
if (!$source) {
return $options['othervars']['html_alt'];
}
// $file might need to be changed to reflect a path on the local file system
// This happens when the user just supplied a filename and files are being sourced locally
// Put $file = $source['filepath'] in case that happened
$file = $source['filepath'];
// In all cases $file_url is now an absolute, or relative, url to the file that we can use
$file_url = $source['fileurl'];
}
// Attach file_url to othervars so player modules have access if required
$options['othervars']['file_url'] = $file_url;
// Depending if we are outputting a swf or using a player we need to attach $file in different places
switch ($options['methods']['player']) {
// Embedding an swf directly - no player
case 'swf':
$options['othervars']['filepath'] = $file;
$options['othervars']['fileurl'] = $file_url;
break;
// Embedding with a player
default:
if ($options['resolved_methods']['player']['library']) {
$options['othervars']['filepath'] = $options['resolved_methods']['player']['library'];
$options['othervars']['fileurl'] = base_path() . $options['othervars']['filepath'];
}
}
// Merge default and user defined parameters, with user defined ones taking precedence
$options['params'] = array_merge(_swftools_params(), $options['params']);
// If player requires a higher version of flash than the current default then over-ride the default
if (version_compare($options['resolved_methods']['player']['version'], $options['params']['version'], '>')) {
$options['params']['version'] = $options['resolved_methods']['player']['version'];
}
/**
* We used to call hook_flashvars, using the module name, but we are starting to do a lot
* more than just flashvars. So we will borrow from the theme system and implement
* hook_swftools_preprocess_[playername]. Normally you would just expect the module that
* defines the player to handle its own players, but in theory anyone can hook in at this
* point and manipulate the entire data array just before we output it.
*/
$preprocess = 'swftools_preprocess_' . $options['resolved_methods']['player']['name'];
foreach (module_implements($preprocess) as $module) {
$function = $module . '_' . $preprocess;
$function($options);
}
// TODO: Can we deprecate this - we are accommodating the ability to specify width x height in a string on params.
// We used to set height and width on $vars->params, but they're not actually params and they were
// being unset in individual embedding functions. So we'll move them to $vars->othervars.
// We will continue to let users pass the data on $vars->params so as not to break existing code.
if (!isset($options['othervars']['height']) && !empty($options['params']['height'])) {
$options['othervars']['height'] = $options['params']['height'];
unset($options['params']['height']);
}
if (!isset($options['othervars']['width']) && !empty($options['params']['width'])) {
$options['othervars']['width'] = $options['params']['width'];
unset($options['params']['width']);
}
// Try and make sure we have a size set on this content
swftools_set_size($options);
// Change html_alt to include the first image when handling an image list
// TODO: Should this be an option that can be disabled?
if ($options['methods']['action'] == 'image_list') {
swftools_image_html_alt($options);
}
// See if anyone wants to alter anything just before it is output
drupal_alter('swftools', $options);
// Call theme function
$output = theme('swftools_embed', $options);
// See if the embed placed a script for us to cache
$script = ($data = drupal_get_js($options['othervars']['id'])) ? str_replace(array("\n"), '', $data) : '';
// Cache the result
cache_set('swf:' . $options['othervars']['cid'], $output, 'cache_swftools', CACHE_PERMANENT, $script);
// If we want just the cid then return that
if ($options['othervars']['return'] == SWFTOOLS_RETURN_CID) {
return $options['othervars']['cid'];
}
// Return the markup
return $output;
}
/**
* Converts an array of paramters to JSON and returns them as a string ready for use as a flashvar.
*
* @param $params
* An array of parameters.
* @param $attribute
* The attribute that the JSON string will be attached to.
*
* @return
* A string in the form [attr]={JSON}
*/
function swftools_json_params(&$params, $attribute = 'swftools') {
return $attribute . "='" . 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';
}
/**
* Returns the currently configured player for the specified action and profile.
*
* We use a static array so that if we are generating a complex page we can
* quickly locate the relevant action/profile player after we've done it the
* first time. This saves us from repeat calls to swftools_variable_get().
*
* @param $action
* The SWF Tools action to be performed.
* @param $profile
* The profile being used for this item.
*
* @return
* The name of the currently configured player for this action.
*/
function swftools_get_player($action, $profile = '') {
// Initialise a static array for this page call
static $players = array();
// We need to give the empty profile a name to place it in the array
$_profile = $profile ? $profile : SWFTOOLS_UNDEFINED;
// Do we already know the players for this profile?
if (!isset($players[$_profile])) {
// Register the players for this profile in the array
$players[$_profile] = swftools_get_players($profile);
}
// Return the result
return isset($players[$_profile][$action]) ? $players[$_profile][$action] : FALSE;
}
/**
* Returns 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
*/
function _swftools_params() {
// Cache this
static $params = array();
// If not set then get defaults
if (!$params) {
// Define default parameters for case when settings have been stored
$defaults = array(
'swliveconnect' => 'false',
'play' => 'true',
'loop' => 'true',
'menu' => 'false',
'allowfullscreen' => 'true',
'quality' => 'autohigh',
'scale' => 'showall',
'align' => 'l',
'salign' => 'tl',
'wmode' => 'opaque',
'bgcolor' => '',
'version' => '7',
'allowscriptaccess' => 'sameDomain',
);
// Retrieve settings from the database if available
$params = variable_get('swftools_params', $defaults);
}
// Return the default parameters
return $params;
}
/**
* Returns information about the specified file.
*
* We use this function to try and get the height and width for content that
* we don't have a specific size for.
*
* The returned value is an array that may include width, height, extension,
* file_size, mime_type. We return FALSE if we didn't get a valid file, or if
* image_get_info() couldn't tell us anything.
*
* @parameter $file
* Path to a local file that we want to interrogate.
*
* @return
* An array of data, or FALSE if we didn't get anything.
*/
function swftools_get_info($file) {
// Assume we won't have data
$info = FALSE;
// Try to get image info (first assume it is in the file directory (most likely case))
if ($try = file_create_path($file)) {
$info = image_get_info($try);
}
// If it wasn't in the file system just try the file path - that might be valid
if (!$info) {
$info = image_get_info($file);
}
// Return either the info array, or it will be FALSE if we got nothing
return $info;
}
/**
* Generates an playlist and places it in {cache_swftools} ready for use.
*
* This relies on player modules implementing hook_swftools_playlist_[player].
* A module implementing this hook may either return an xml string that will be
* used by the player, or it may update the data array directly.
*
* We don't check for the existence of this content in the cache already. If we
* are here then the swf wasn't in the cache, so it's pretty certain the xml
* won't be either.
*
* We used to create an actual file. Now we place the content in {cache_swftools}
* and access it via swftools/playlist/nnn, where nnn is the cid.
*
* @param &$options
* The SWF Tools data array for this element.
*
* @return
* The path to the virtual xml file (will be in the form swftools/playlist/nnn),
* or an empty string (SWFTOOLS_NON_XML_PLAYLIST) if there is no xml.
*/
function swftools_generate_playlist(&$options) {
/**
* We don't need to hash again. We have been given a cid via $vars->othervars['cid']
* which is based on the incoming data, so lets just use that. Then we don't have to
* hash again. We prefix cache entries with xml: when they are a playlist so the cid
* for the playlist will be xml:nnn, and for the movie will be swf:nnn. We have a
* matched pair in the database which is neat.
*/
// Determine the name of the hook that would be used to generate an xml playlist
$hook = '_swftools_playlist_' . $options['resolved_methods']['player']['name'];
// Build the name of the function we would call
$function = $options['resolved_methods']['player']['module'] . $hook;
// See if the function exists - if it doesn't the module doesn't implement this hook
if (function_exists($function)) {
// Call the function and pass variables by reference
$playlist = $function($options);
// If playlist is empty this is a non-xml playlist
if (!$playlist) {
return SWFTOOLS_NON_XML_PLAYLIST;
}
// Cache the result
cache_set('xml:' . $options['othervars']['cid'] . '.xml', $playlist, 'cache_swftools');
// Return the path to the xml
return url('swftools/playlist/' . $options['othervars']['cid'] . '.xml');
}
// We don't have hook_swftools_playlist_[player] for this player, return an empty string
return '';
}
/**
* Prepares an array of filenames, or file objects, for use in a playlist.
*
* This function processes the supplied array and returns an array of playlist data which has
* two elements, header and playlist. The header array contains the playlist title, which may
* be an empty string if nothing was set. The playlist array contains an array of playlist
* elements. As a minimum each element will contain:
* - filepath : the filepath for the file, if it is a local file, or FALSE if a full url
* - title : the title for the element, set to the filename if nothing given
* - filename : the filename for the file
* - fileurl : the full url to the file
*
* drupal_alter is called just prior to returning the playlist, so a module can implement
* hook_swftools_playlist_alter(&$playlist_data) to modify the playlist prior to return. This
* means other modules can modify, or add, elements. For example, the swftools_getid3 module
* implements this hook to attach ID3 data to each playlist element.
*
* @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
* TODO: Do we need to use this? Does anyone ever use it??
* 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
*/
function swftools_prepare_playlist($files, &$options) {
// Make sure stream and action are present on options
$options['methods'] += array(
'player' => '',
);
// Initialise two flags for establishing the action to be taken on this playlist
$action = '';
$mixed_media = FALSE;
// Initialise playlist data array
$playlist_data = array(
'header' => array(),
'playlist' => array(),
);
// Iterate over the array of files to set filepath, fileurl and title keys
foreach ($files AS $key => $data) {
// If $data is an object convert it to an array
if (is_object($data)) {
$data = (array)$data;
}
// If $data is a string then make it array with this value on the filepath key
elseif (!is_array($data)) {
// Create an array with key filepath set to the $data string
$data = array(
'filepath' => $data,
);
}
// Attach the incoming element to the playlist
$playlist_data['playlist'][$key] = $data;
/**
* Ensure the title key is present to simplify later code as we know it will be present.
* Note we no longer set a default title. We leave it empty since all output should
* now be handled by a theme function, so if the user wants to make a default we can
* let them since they will know a specific value wasn't given. We don't do it for them.
*
* We also initialise some other empty strings to make checks in other modules easier.
*/
$playlist_data['playlist'][$key] += array(
'title' => '',
'image' => '',
'description' => '',
'author' => '',
'date' => '',
'link' => '',
'duration' => '',
'stream' => FALSE,
);
// Find out if this item is a stream by checking for rtmp and exploding it
if (strpos($playlist_data['playlist'][$key]['filepath'], 'rtmp:') === 0) {
$stream = explode(' ', $playlist_data['playlist'][$key]['filepath']);
// If the filepath exploded then assume we have a valid stream
if (count($stream) == 2) {
list($playlist_data['playlist'][$key]['stream'], $playlist_data['playlist'][$key]['filepath']) = $stream;
$options['othervars']['stream'] = TRUE;
// TODO: Action checking fails as streams don't have an extension - assume mixed media
$options['methods']['action'] = 'media_list';
}
}
// If this whole playlist isn't a stream, and this item isn't a stream
if (!is_string($options['othervars']['stream']) && !$playlist_data['playlist'][$key]['stream']) {
// Expand $file as necessary if local or remote
$source = swftools_get_url_and_path($playlist_data['playlist'][$key]['filepath']);
// Store results
$playlist_data['playlist'][$key]['filepath'] = $source['filepath'];
$playlist_data['playlist'][$key]['fileurl'] = $source['fileurl'];
}
else {
$playlist_data['playlist'][$key]['fileurl'] = $playlist_data['playlist'][$key]['filepath'];
}
// See if we have an image we need to expand
if ($playlist_data['playlist'][$key]['image']) {
$source = swftools_get_url_and_path($playlist_data['playlist'][$key]['image']);
$playlist_data['playlist'][$key]['image'] = $source['fileurl'];
}
// Allow other modules to modify this playlist element (e.g. getID3)
drupal_alter('swftools_playlist_element', $playlist_data['playlist'][$key]);
// If the caller wants us to work out the action for them then it happens in here
if (!$options['methods']['action']) {
// Get the extension for this item
$extension = strtolower(pathinfo($playlist_data['playlist'][$key]['fileurl'], PATHINFO_EXTENSION));
// Only try to determine actions if there's an extension to work with, and we didn't already work out it's mixed
if ($extension && !$mixed_media) {
// Work out what we'd do with this file
$action_for_this_file = swftools_get_action('dummy.' . $extension);
// If this is the first file we've processed we log it
if (!$action) {
$action = $action_for_this_file;
}
// Is this action the same as the first file we saw? If not we have mixed media
if ($action != $action_for_this_file) {
$mixed_media = TRUE;
$action = 'media_list';
}
}
}
}
// If we didn't get an action (happens with streams as they have no extension) then specify an action now
$action = $action ? $action : 'media_list';
// Pluralize the action for multiple files if not already pluralized
$action = (substr($action, -5, 5) == '_list') ? $action : $action . '_list';
// If the called didn't specify an action then assign it now
$options['methods']['action'] = $options['methods']['action'] ? $options['methods']['action'] : $action;
// Attach the resulting playlist to the array (we are working by reference)
$options['othervars']['playlist_data'] = $playlist_data;
// Call drupal_alter to let other modules modify the entire playlist if they want
drupal_alter('swftools_playlist', $playlist_data);
}
/**
* Implementation of hook_filter_tips().
*/
function swftools_filter_tips($delta, $format, $long = FALSE) {
if ($long) {
return t('
The basic syntax for embedding a flash file (.swf), flash movie (.flv) or audio file (.mp3) is:
[swf file="filename.swf"]
If you would like to override SWF Tools and flash player default settings,
you can specify additional parameters. For example:
[swf file="song.mp3" flashvars="backcolor=#AABBCC&&forecolor=#11AA11"]
If you would like to output a list of files then the format is:
[swf files="image1.jpg&&image2.jpg&&..."]
SWF Tools Filter will accept following:
- params : 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:
params="wmode=true&&bgcolor="#00FF00"
Alternatively you can supply each parameter individually without using
params
. Example wmode="true" bgcolor="#00FF00"
- flashvars : 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:
flashvars="autostart=true&&volume=80"
- methods : 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:
methods="player=onepixelout_mp3"
WARNING: with params, flashvars and othervars, pass multiple values
separated by &&.
');
}
else {
return t('You may use [swf file="song.mp3"] to display Flash files and media.');
}
}
/**
* 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 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);
}
}
/**
* Processes text obtained from the input filter.
*
* This function processes the filter text that the user has added to the text area.
* If the filter is wrapped in 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('@(?:)?\[(swflist|swf)\s*(.*?)\](?:
)?@s', $text, $match)) {
// $match[0][#] .... fully matched string
// $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();
// Initialise an array to hold playlist arrays
$files = array();
foreach ($match[2] as $key => $passed_parameters) {
//preg_match_all('/(\w*)=\"(.*?)\"/', $passed_parameters, $match_vars[$key]);
preg_match_all('/(\w*)=(?:\"|")(.*?)(?:\"|")/', $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_parse_str(str_replace(array('&&', '&&'), '&', $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] = array();
}
}
}
// 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'];
switch ($match[1][$key]) {
case 'swf':
$replace = swf($prepared[$key]['file'], $options);
break;
case 'swflist':
// If this filter contains a key called files
if ($prepared[$key]['files']) {
// Iterate over the
foreach ($prepared[$key]['files'] AS $name => $filename) {
if (!$filename) {
$prepared[$key]['files'][$name] = $name;
}
// Put in to proper format for new swftools_prepare_playlist()
$files[$key][$name]['filepath'] = $prepared[$key]['files'][$name];
}
// Get playlist data, but don't determine action if the user specified a player
$replace = swf($files[$key], $options);
}
else {
$replace = '';
}
break;
}
$matched[] = $match[0][$key];
$rewrite[] = $replace;
}
return str_replace($matched, $rewrite, $text);
}
return $text;
}
/**
* 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;
}
}
/**
* Parses a string passed to the input filter in to separate key value pairs.
*
* We cannot automatically use parse_str() because things like the list of
* files are not key-value pairs, but just a list of items.
*
* @param $string
* The string to parse.
*
* @return
* An array of key/value pairs.
*/
function swftools_parse_str($string) {
// Initialise the array
$return = array();
// Split the string at each &
$pairs = split('&', $string);
// Iterate over each piece
foreach ($pairs as $pair) {
// Split each piece at =
$splitpair = split('=', $pair);
// If there was only one item, or this key is already in the array append the value
if (!isset($splitpair[1]) || array_key_exists($splitpair[0], $return)) {
$return[] = $splitpair[0];
}
// Otherwise we had a key-value we can add to the array
else {
$return[$splitpair[0]] = $splitpair[1];
}
}
// Return the result
return $return;
}
/**
* Implementation of hook_theme().
*/
function swftools_theme() {
return array(
// This is called by swf() when it is ready to embed
'swftools_embed' => array(
'arguments' => array('options' => NULL),
'file' => 'includes/swftools.theme.inc',
),
// This is a specific embedding method
'swftools_direct' => array(
'arguments' => array('file' => NULL, 'options' => NULL),
'file' => 'includes/swftools.core.inc',
),
// These are the SWF Tools CCK formatters
'swftools_formatter_swftools' => array(
'arguments' => array('element' => NULL, 'profile' => NULL),
'function' => 'theme_swftools_formatter_swftools',
'file' => 'includes/swftools.theme.inc',
),
'swftools_formatter_swftools_no_file' => array(
'arguments' => array('element' => NULL),
'function' => 'theme_swftools_formatter_swftools',
'file' => 'includes/swftools.theme.inc',
),
'swftools_formatter_swftools_playlist' => array(
'arguments' => array('element' => NULL, 'profile' => NULL),
'function' => 'theme_swftools_formatter_playlist',
'file' => 'includes/swftools.theme.inc',
),
'swftools_formatter_swftools_thumbnail' => array(
'arguments' => array('element' => NULL, 'retrieve' => NULL),
'function' => 'theme_swftools_formatter_thumbnail',
'file' => 'includes/swftools.theme.inc',
),
// This themes an swftools element in the FormAPI
'swftools' => array(
'arguments' => array('element' => NULL),
'file' => 'includes/swftools.core.inc',
),
// This themes an swftools element in the FormAPI
'swftools' => array(
'arguments' => array('element' => NULL),
'file' => 'includes/swftools.core.inc',
),
'swftools_page' => array(
'template' => 'swftools-page',
'arguments' => array('content' => NULL),
'path' => drupal_get_path('module', 'swftools') . '/includes',
'preprocess functions' => array('template_preprocess_page'),
),
// Generic accessible controls handler
'swftools_accessible_controls' => array(
'arguments' => array('player' => NULL, 'id' => NULL, 'actions' => NULL, 'visible' => NULL),
),
// Path to an empty image when no thumbnail is given
'swftools_empty_image' => array(
'arguments' => array('data' => NULL),
'file' => 'includes/swftools.theme.inc',
),
);
}
/**
* Implementation of hook_file_download().
*
* Allows SWF Tools to work with a private file system that might include files
* uploaded outside the control of an upload module, e.g. FTP of large video files.
*
* If the file is of a supported type, based on extension, then return a valid header.
* 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) {
// 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_PRIVATE_ACCESS_DENIED)) {
// Get extension of file in question
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
// Get list of extensions that SWF Tools can grant access to
$extensions = variable_get('swftools_grant_access_extensions', SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS);
// Need access to the user object
global $user;
// Check if SWF Tools should grant access to this extension - 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 = _swftools_mime_types();
// If file is one of the above types, based on the extension, return headers
if (isset($mime_types[$extension])) {
return array(
'Content-Type: '. $mime_types[$extension],
'Content-Length: '. filesize(file_create_path($file)),
);
}
}
}
/**
* Implementation of hook_swftools_methods().
*/
function swftools_swftools_methods() {
// Module implements swf embedding (action swf)
$methods['swf']['swf'] = array(
'module' => 'swftools',
'title' => t('Display the swf directly on the page'),
);
// Add on generic players (we have to call this hook manually as it isn't in a module)
$methods += swftools_genericplayers_swftools_methods();
// Return the methods that are native to SWF Tools
return $methods;
}
/**
* Helper function to set the size of the swf content in to $options['othervars']['height'] and ['width']
*
* @param &$options
* Data arrays that is being assembled by SWF Tools.
*
* @return
* Nothing - function operates by reference.
*/
function swftools_set_size(&$options) {
// We use these defaults to filter arrays for their height and width, and assign a fallback value
$defaults = array('height' => '100%', 'width' => '100%');
// If height and width are already set then just return
if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
return;
}
// See if we can get height and width from flashvars
$try = array_intersect_key($options['flashvars'], $defaults);
$options['othervars'] += $try;
// See if we can get height and width from player
$try = array_intersect_key($options['resolved_methods']['player'], $defaults);
$options['othervars'] += $try;
// If we have a height and width now then return
if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
return;
}
// Try and get size from the file to be embedded, but preserve height or width if just one was set
$info = swftools_get_info($options['othervars']['filepath']);
// If sizes were retrieved then use them
if ($info) {
$try = array_intersect_key($info, $defaults);
$options['othervars'] += $try;
};
// And if all else fails, assign 100%
$options['othervars'] += $defaults;
}
/**
* 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', 'link', 'text'),
'multiple values' => CONTENT_HANDLE_CORE,
),
'swftools_playlist' => array('label' => t('SWF Tools - playlist'),
'field types' => array('filefield', 'link', 'text'),
'multiple values' => CONTENT_HANDLE_MODULE,
),
'swftools' => array('label' => t('SWF Tools - with download link'),
'field types' => array('filefield', 'link'),
'multiple values' => CONTENT_HANDLE_CORE,
),
'swftools_thumbnail' => array('label' => t('SWF Tools - thumbnail'),
'field types' => array('filefield', 'link', 'text'),
'multiple values' => CONTENT_HANDLE_CORE,
),
);
}
/**
* Verifies that the supplied id is unique, and assigns an id if one was not supplied.
*
* Typically this is called to get us a unique id, but the user can also supply an id. In all cases
* we call form_clean_id to verify that the id is unique in this page generation session.
*
* @param $id
* An id to be checked, or empty if we don't have one yet.
*
* @return
* A unique id.
*/
function swftools_get_id($id = '') {
// If a specific id wasn't set then assign one
$id = $id ? $id : uniqid('swftools-');
// Check the id is unique (ours should be, a user supplied one might not be)
return form_clean_id($id);
}
/**
* Creates a relative path url from a file path, using private or public file system.
*
* This is an SWF Tools version of file_create_url(). The only difference is that
* here we do not output absolute paths as we are only using these paths within the
* context of a page and therefore relative is fine.
*
* @param $path
* Path to the file.
*
* @return
* A string with a complete path, relative to the local file system.
*/
function swftools_create_url($path) {
// Strip file_directory_path from $path. We only include relative paths in urls.
if (strpos($path, file_directory_path() .'/') === 0) {
$path = trim(substr($path, strlen(file_directory_path())), '\\/');
}
// Output a relative url, using public or private file transfer
switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
case FILE_DOWNLOADS_PUBLIC:
return base_path() . file_directory_path() . '/' . str_replace('\\', '/', $path);
case FILE_DOWNLOADS_PRIVATE:
return url('system/files/' . $path);
}
}
/**
* Determines the url for a file, and expands its filepath if necessary.
*
* @param $file
* A string containing a url or a path to a file.
*
* @return
* An array with two keys
* - src: The url to the file (relative if on the local system)
* - src_path: The path to the file, expanded if necessary
*
* This function is necessary because SWF Tools allows flexibility in how the site interprets
* filenames. If just a filename is provided then this might point to a file on the local system,
* or it might point to an external location if the remote media path is set. However, for things
* like auto-detection of sizes to work when the filename is local it must be expanded to include
* the file path.
*
* If $file is a full and valid absolute url then the function returns $file on both keys.
*
* If $file is full and valid url on the local system then the function returns $file on both keys.
*
* If $file is a path to a local file (sites/default/files/xxx) then src_path will return this,
* and src will return a full relative url.
*
* If $file is just a filename and remote media is active then src and src_path will both be set
* to the url for the external location.
*
* If $file is just a filename and remote media is not active then src_path will return the path
* to the local system (so xxx becomes sites/default/files/xxx) and src will return the full
* relative url.
*/
function swftools_get_url_and_path($file) {
// src will contain a full, or relative, url that is used to render the file
// src_path will contain a partial path (without webroot), or the original file path
$ret = array(
'fileurl' => '',
'filepath' => $file,
);
// If already a valid absolute url simply return it
if (valid_url($file, TRUE)) {
$ret['fileurl'] = $file;
return $ret;
}
// If a valid url, and starts with /, then assume to be a local path relative to web root
// No security check is needed as the result of this is only output to the webpage
// We strip base_path from the file to create filepath that is valid for image_get_info later.
// FileField will create paths with spaces in - need to reverse that when testing for valid_url
$temp = str_replace(' ', '%20', $file);
// if (valid_url($file) && strpos($file, '/') === 0) {
if (valid_url($temp) && strpos($file, '/') === 0) {
return array(
'fileurl' => $file,
'filepath' => str_replace(base_path(), '', $file),
);
}
// If defintely in the local file system return a relative url to the file
if ($file == file_create_path($file)) {
// If media checking is active check to see if it actually exists
if (variable_get('swftools_check_media', TRUE)) {
// If the file doesn't exist, set an error message and return FALSE to indicate failure
if (!file_exists($file)) {
drupal_set_message(t('SWF Tools could not find %file.', array('%file' => $file)), 'error');
return FALSE;
}
}
// If we got here then return a relative url to the file
$ret['fileurl'] = swftools_create_url($file);
return $ret;
}
// Retrieve the media url setting
$media_url = trim(variable_get('swftools_media_url', ''));
// If a remote path is set build the appropriate url to the file
if ($media_url) {
$ret['fileurl'] = $media_url . '/' . $path;
return $ret;
}
// If we got here then expand to a local file path and call again
return swftools_get_url_and_path(file_create_path($file));
}
/**
* Returns a string defining a base path for flash to use.
*/
function swftools_get_base() {
// Cache the result as we might get multiple calls
static $base = '';
// If $base is not already defined then set it
if (!$base) {
// Retrieve swftools_media_url to see if a remote path has been set
$base = trim(variable_get('swftools_media_url', ''));
// If $base is still empty then use local path to file directory
if (!$base) {
$base = base_path() . file_directory_path() . '/';
}
}
// Return the base path
return $base;
}
/**
* Flatten an array which has sub-arrays in to a single keyed array.
*
* If keys in the sub-array are the same as ones seen previously the early key will be over-written.
*
* @param $array
* Array to be processed.
*/
function swftools_array_flatten(&$array) {
// Only process if we passed an array
if (is_array($array)) {
// Iterate over the array
foreach ($array as $key => $value) {
// If the value is in itself an array then flatten that too
if (is_array($value)) {
// Unset this key as this contains an array
unset($array[$key]);
// Flatten the sub-array
swftools_array_flatten($value);
// Merge the flattened sub-array in to the rest of the array
$array = array_merge($array, $value);
}
}
}
}
/**
* Returns a variable from the relevant profile, or the global settings, or the default values.
*
* This is a custom handler to take care of the SWF Tools profile mechanism.
* If no profile name is given then it simply returns the requested variable,
* or the default if the variable is not set.
*
* If a profile name is given then it will first try to retrive the profiled variable.
* If that fails it will try to return the global setting, and if that fails then it
* will return the default. In this way we cascade through the "most relevant" setting.
*
* @param $name
* The name of the variable to return.
* @param $default
* The default value to use if this variable has never been set.
* @param $profile
* The name of the profile to use.
*
* @return
* The value of the variable.
*/
function swftools_variable_get($name, $default, $profile = '') {
if ($profile && ($ret = variable_get('swftools_' . $profile . '_' . $name, SWFTOOLS_UNDEFINED)) != SWFTOOLS_UNDEFINED) {
return $ret;
}
return variable_get($name, $default);
}
/**
* Serves an xml playlist from the {cache_swftools} table.
*
* SWF Tools no longer generates a physical file for the playlist. Instead it
* places an entry in its internal cache table and then serves the file from
* there. Pages request the files by accessing swftools/playlist/nnn.xml, where
* nnn is the cid of the content.
*
* Note that we check at swf() whether the relevant cid exists in the table. If
* it doesn't then the playlist file is regenerated.
*
* @param $playlist
* The name of the playlist being requested.
*
* @return
* Serve the xml file, or issue drupal_not_found() if it doesn't exist.
*/
function swftools_get_xml($playlist) {
if (!$data = cache_get('xml:' . $playlist, 'cache_swftools')) {
print drupal_not_found();
}
else {
drupal_set_header('Content-Type: text/xml; charset=utf-8');
print $data->data;
}
}
/**
* Serves just the swf content from the cache via the path swftools/page/nnnn
*
* This feature is experimental - the only access control at the moment is whether
* the user is generally allowed to view content. Complex permissions will come
* later.
*
* @param $cid
* The cid of the item to retrieve.
*
* @return
* An html page, including headers
*/
function swftools_get_html($cid) {
if (!variable_get('swftools_grant_access_to_cache', 0)) {
print drupal_access_denied();
}
elseif (!$content = cache_get('swf:' . $cid, 'cache_swftools')) {
print drupal_not_found();
}
else {
print theme('swftools_page', $content->data);
}
}
/**
* Creates a cid for the call to swf() and returns its data from the cache when available.
*
* To make our cid we create an array from $file and $options. Then we serialize it, and then
* we run it through md5. This generates a unique cid for that piece of content.
*
* Once the cid is created it is attached to $options['othervars']['cid'] so that
* subsequent functions don't have to rehash the data to generate it again.
*
* Within {cache_swftools} we then prefix the cid with swf: or xml: to indicate whether the
* cache entry refers to the markup that produces the content, or the xml: that describes the
* playlist. So for xml playlist content we should have two entries with the same numeric portion
* in their cid.
*
* @param $file
* The $file parameter from the call to swf().
* @param $options
* The $options parameter from the call to swf().
*
* @return
* The cached content, or FALSE if it is isn't available.
*/
function swftools_get_from_cache($file, &$options) {
// Construct a cid for this piece of content
$cid = md5(serialize(array($file, $options)));
// Set the cid on othervars ready to store this item if we have to render it
$options['othervars']['cid'] = $cid;
// If this is in the cache then return it
if ($ret = cache_get('swf:' . $cid, 'cache_swftools')) {
return $ret;
}
// Indicate that we don't have cached data
return FALSE;
}
/**
* Implementation of hook_flush_caches().
*/
function swftools_flush_caches() {
return array('cache_swftools');
}
/**
* Returns the default handlers, or customised handlers, for each action.
*/
function swftools_get_players($profile) {
// These are the standard defaults (key is action, value is handler)
$defaults = array(
'video' => 'generic_flv',
'audio' => 'generic_mp3',
'swf' => 'swf',
);
// Retrieve settings from the database if available
$settings = swftools_variable_get('swftools_handlers', $defaults, $profile);
// Return result
return $settings;
}
/**
* Merges two multi-dimensional arrays.
*
* This function is used by players that filter their settings to strip out
* blanks or defaults. For the admin page we need a full set of values to prevent
* errors. Since the arrays might be multi-dimensional we cannot use a regular
* array_merge(). The values in the first array will be over-written by values in
* the second, if they exist.
*
* @param $array1
* The first array to merge.
* @param $array2
* The second array to merge.
*
* @return
* The result of the merge.
*/
function swftools_array_merge($array1, $array2) {
// Iterate over $array 2 (this is normally the smaller of the two)
foreach ($array2 as $key => $value) {
// If this key is present in $array1 then work out what to do
if (isset($array1[$key])) {
// If both keys hold arrays, combine them
if (is_array($value) && is_array($array1[$key])) {
$array1[$key] = swftools_array_merge($array1[$key], $value);
}
else {
// Replace value in $array1 with that from $array2
$array1[$key] = $value;
}
}
else {
// Simply put this value in $array1 if it isn't already in $array1
$array1[$key] = $value;
}
}
// Return the result
return $array1;
}
/**
* Retrieves the list of actions, and their descriptions, that modules are presenting to SWF Tools.
*
* @param $reset
* When TRUE will reset the cache.
*
* @return
* An array of actions.
*/
function swftools_get_actions($reset = FALSE) {
// Cache actions
static $actions;
// If user has requested the cache to be reset then reset it
if ($reset || !isset($actions)) {
if (!$reset && ($cached = cache_get('actions', 'cache_swftools'))) {
$actions = $cached->data;
}
else {
// Build a list of standard actions that SWF Tools knows about from its other modules
$default_actions = array(
'swf' => array(
'#description' => 'a single swf movie',
'#type' => 'swf movies',
'#weight' => -8,
),
'video' => array(
'#description' => 'a single video',
'#type' => 'videos',
'#weight' => -7,
),
'video_list' => array(
'#description' => 'a series of videos',
'#weight' => -6,
),
'audio' => array(
'#description' => 'a single audio file',
'#type' => 'audio',
'#weight' => -5,
),
'audio_list' => array(
'#description' => 'a series of audio files',
'#weight' => -4,
),
'image' => array(
'#description' => 'a single image',
'#type' => 'images',
'#weight' => -3,
),
'image_list' => array(
'#description' => 'a series of images',
'#weight' => -2,
),
'media_list' => array(
'#description' => 'a series of mixed media files',
'#weight' => -1,
),
);
// Plan ahead - give other modules the chance to declare an action
$actions = array();
foreach (module_implements('swftools_actions') as $module) {
$function = $module .'_swftools_actions';
$result = $function();
if (isset($result) && is_array($result)) {
$actions = array_merge($actions, $result);
}
}
// Merge additional or new values over the defaults (allows defaults to be renamed)
$actions = array_merge($default_actions, $actions);
// Sort the list
uasort($actions, 'element_sort');
// Set the cache
cache_set('actions', $actions, 'cache_swftools');
}
}
// Return the list of available actions
return $actions;
}
/**
* Determines the action to be taken, based on the extension of a filename.
*
* @param $extension
* The file being queried.
*
* @return
* An SWF Tools action, or 'media_list' if we don't know.
*/
function swftools_get_action($file) {
// Get the array of actions, keyed on extension
$actions = _swftools_actions();
// Get the extension for this file
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
// If we know the handler for this then use it, otherwise return 'media_list'
return isset($actions[$extension]) ? $actions[$extension] : 'media_list';
}
/**
* Returns an array of actions, keyed by file extension.
*/
function _swftools_actions() {
// Cache this as there may be multiple calls
static $actions;
// Do we need to fetch the array of actions?
if (!$actions) {
// Defaults to use if no settings have been stored
$defaults = array(
'swf' => 'swf',
'flv' => 'video',
'mp3' => 'audio',
'jpg' => 'image',
'jpeg' => 'image',
'jpe' => 'image',
'png' => 'image',
'gif' => 'image',
);
// Use settings from configuration page, or defaults
$actions = variable_get('swftools_actions', $defaults);
}
// Return the result
return $actions;
}
/**
* Returns an array of mime types, keyed by file extension.
*/
function _swftools_mime_types() {
$defaults = array(
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
'mp3' => 'audio/mpeg',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
);
// Use settings from configuration page, or defaults
$mime_types = variable_get('swftools_mime_types', $defaults);
// Return the result
return $mime_types;
}
/**
* Implementation of hook_form_FORM_ID_alter().
*
* Alters the system_performance_settings form so the SWF Tools cache can be managed along with other caches.
*/
function swftools_form_system_performance_settings_alter(&$form, &$form_state) {
$form['swftools_cache'] = array(
'#type' => 'fieldset',
'#title' => t('SWF Tools cache'),
'#description' => t('Enabling the SWF Tools cache can offer a performance increase for all users by preventing embedding markup and playlists from being reconstructed on each page load. If the page cache is also enabled, performance increases from enabling the SWF Tools cache will mainly benefit authenticated users.'),
);
$form['swftools_cache']['swftools_cache'] = array(
'#type' => 'radios',
'#title' => t('SWF Tools cache'),
'#default_value' => variable_get('swftools_cache', CACHE_NORMAL),
'#options' => array(
CACHE_DISABLED => t('Disabled'),
CACHE_NORMAL => t('Enabled (recommended)'),
),
'#description' => t('During site development it can be helpful to disable the cache and force content to be regenerated on every page call. Note that content being generated via an input filter is always cached by the input filter itself and disabling the SWF Tools cache will not stop the filter cache. Even when the SWF Tools cache is disabled it will continue to store content to allow features such as serving content from %path to function.', array('%path' => base_path() . 'swftools/html/nn')),
);
// We want to slot our new section above 'clear cached data' but we can't use weights
// We use a trick and unset and reset the elements we want lower
$temp = $form['clear_cache'];
unset($form['clear_cache']);
$form['clear_cache'] = $temp;
$temp = $form['buttons'];
unset($form['buttons']);
$form['buttons'] = $temp;
}
/**
* Implementation of hook_elements().
*/
function swftools_elements() {
$type['swftools'] = array(
'#params' => array(),
'#flashvars' => array(),
'#othervars' => array(),
'#methods' => array(),
'#value' => '',
);
// Return the type
return $type;
}
/**
* Changes old player names to the new ones so existing content doesn't break.
*
* @param $name
* The currently assigned player name.
*
* @return
* The corrected player name (which will be unchanged if it is already ok).
*/
function swftools_fix_old_player_names($name) {
// This is the array to map old names to new names
$map = array(
'flowplayer_mediaplayer' => 'flowplayer',
'flowplayer3_mediaplayer' => 'flowplayer3',
'wijering_imagerotator' => 'imagerotator',
'wijering4_mediaplayer' => 'jwplayer4',
);
// Attach the supplied action name as both key and value
$map += array(
$name => $name,
);
// Return the mapped result
return $map[$name];
}
/**
* Changes old action names to the new ones so existing content doesn't break.
*
* @param $name
* The currently assigned action name.
*
* @return
* The corrected action name (which will be unchanged if it is already ok).
*/
function swftools_fix_old_action_names($name) {
// This is the array to map old names to new names
$map = array(
'swftools_swf_display_direct' => 'swf',
'swftools_flv_display' => 'video',
'swftools_flv_display_list' => 'video_list',
'swftools_mp3_display' => 'audio',
'swftools_mp3_display_list' => 'audio_list',
'swftools_image_display' => 'image',
'swftools_image_display_list' => 'image_list',
'swftools_media_display_list' => 'media_list',
);
// Attach the supplied action name as both key and value
$map += array(
$name => $name,
);
// Return the mapped result
return $map[$name];
}
/**
* Implementation of hook_views_api().
*/
function swftools_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'swftools') . '/views',
);
}
/**
* Outputs a message to the screen and/or the watchdog, according to the configuration settings.
*
* Parameters are as watchdog().
*
* @see watchdog()
*/
function swftools_set_error($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
// Find out where this message should go
$destination = variable_get('swftools_error_output', SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN);
// drupal_set_message uses error, warning and status, not severity levels
$status = array(
WATCHDOG_EMERG => 'error',
WATCHDOG_ALERT => 'error',
WATCHDOG_CRITICAL => 'error',
WATCHDOG_ERROR => 'error',
WATCHDOG_WARNING => 'warning',
);
$status += array(
$severity => 'status',
);
// Write to screen?
if ($destination & SWFTOOLS_ERROR_SCREEN) {
drupal_set_message(t($message, $variables), $status[$severity]);
}
// Write to watchdog?
if ($destination & SWFTOOLS_ERROR_WATCHDOG) {
watchdog($type, $message, $variables, $severity, $link);
}
}
/**
* Replaces the html_alt string with an image tag when rendering an image playlist.
*
* This is designed so that if the Flash embed fails the user will see the
* first image from the image playlist, rather than just an empty message.
*
* TODO: Could extend this to substitute thumbnails on audio? Or is that too much!
*
* @param $options
* SWF Tools data array.
*
* @return
* Nothing - modifies the array directly.
*/
function swftools_image_html_alt(&$options) {
// Make sure there is a playlist (not using Flickr etc)
if ($file = $options['othervars']['playlist_data']['playlist']) {
// Get the first array element - use array_shift on a copy of the playlist in case there are named keys
$file = array_shift($file);
// Get height and width data for the first image
$info = swftools_get_info($file['filepath']);
// Initialise an empty array
$attributes = array();
// Try to make sure the image height and width don't exceed the player height and width to keep the layout as we expect
if ($info) {
$attributes['height'] = ($info['height'] > $options['othervars']['height']) ? $options['othervars']['height'] : $info['height'];
$attributes['width'] = ($info['width'] > $options['othervars']['width']) ? $options['othervars']['width'] : $info['width'];
}
// Replace html_alt with an image, setting alt text as both alt and title (so when user hovers they see a sensible message)
$alt = strip_tags($options['othervars']['html_alt']);
$options['othervars']['html_alt'] = theme('image', $file['filepath'], $alt, $alt, $attributes, FALSE);
}
}
/**
* Builds a list of accessible controls for the specified player.
*
* SWF Tools accessibility scripts use classes of the form
* !player-accessible-!action-!id
*
* @param $player
* The player name to be made accessible (e.g. jwplayer4).
* @param $id
* The id of the player these controls relate to.
* @param $actions
* The list of actions, where the key is the action name, and the value is the translated text.
* @param $visible
* Whether the controls should be visible (SWFTOOLS_ACCESSIBLE_VISIBLE.
*
* @return
* HTML markup to generate a list
*
* @ingroup swftools
*/
function theme_swftools_accessible_controls($player, $id, $actions, $visible) {
foreach ($actions as $action => $label) {
$list[] = l($label, '', array('fragment' => ' ', 'external' => TRUE, 'attributes' => array('class' => t('!player-accessible-!action-!id', array('!player' => $player, '!action' => $action, '!id' => $id)))));
}
return theme_item_list($list, '', 'ul', array('class' => $visible == SWFTOOLS_ACCESSIBLE_VISIBLE ? '' : 'swftools-accessible-hidden'));
}
/**
* Modifies a file path to include the appropriate imagecache preset.
* @param $preset
* The imagecache preset to be applied.
* @param $path
* The existing path.
*
* @return
* The modified path, or an unaltered path if not on the local file system.
*/
function swftools_imagecache_create_path($preset, $path) {
if (module_exists('imagecache')) {
$path = str_replace(file_directory_path(), file_directory_path() . '/imagecache/' . $preset, $path);
}
return $path;
}