swftools.module

Tracking 6.x-3.x branch
  1. drupal
    1. 5 contributions/swftools/swftools.module
    2. 6 contributions/swftools/swftools.module

The primary component of SWF Tools that enables comprehensive media handling.

Functions & methods

NameDescription
swfProcesses a file, or an array of files, and returns the relevant mark-up to render a Flash based player.
swftools_array_flattenFlatten an array which has sub-arrays in to a single keyed array.
swftools_array_mergeMerges two multi-dimensional arrays.
swftools_create_urlCreates a relative path url from a file path, using private or public file system.
swftools_elementsImplementation of hook_elements().
swftools_field_formatter_infoImplementation of hook_field_formatter_info().
swftools_file_downloadImplementation of hook_file_download().
swftools_filterImplementation of hook_filter().
swftools_filter_tipsImplementation of hook_filter_tips().
swftools_fix_old_action_namesChanges old action names to the new ones so existing content doesn't break.
swftools_fix_old_player_namesChanges old player names to the new ones so existing content doesn't break.
swftools_flush_cachesImplementation of hook_flush_caches().
swftools_form_system_performance_settings_alterImplementation of hook_form_FORM_ID_alter().
swftools_generate_playlistGenerates an playlist and places it in {cache_swftools} ready for use.
swftools_get_actionDetermines the action to be taken, based on the extension of a filename.
swftools_get_actionsRetrieves the list of actions, and their descriptions, that modules are presenting to SWF Tools.
swftools_get_baseReturns a string defining a base path for flash to use.
swftools_get_filter_aliasImplements a hook that extends the parameters that can be passed to the filter so that myvar="value" can be mapped to flashvars, etc.
swftools_get_from_cacheCreates a cid for the call to swf() and returns its data from the cache when available.
swftools_get_htmlServes just the swf content from the cache via the path swftools/page/nnnn
swftools_get_infoReturns information about the specified file.
swftools_get_playerReturns the currently configured player for the specified action and profile.
swftools_get_playersReturns the default handlers, or customised handlers, for each action.
swftools_get_url_and_pathDetermines the url for a file, and expands its filepath if necessary.
swftools_get_xmlServes an xml playlist from the {cache_swftools} table.
swftools_imagecache_create_pathModifies a file path to include the appropriate imagecache preset.
swftools_image_html_altReplaces the html_alt string with an image tag when rendering an image playlist.
swftools_initImplementation of hook_init().
swftools_json_paramsConverts an array of paramters to JSON and returns them as a string ready for use as a flashvar.
swftools_menuImplementation of hook_menu().
swftools_parse_strParses a string passed to the input filter in to separate key value pairs.
swftools_permImplementation of hook_perm().
swftools_prepare_playlistPrepares an array of filenames, or file objects, for use in a playlist.
swftools_set_error
swftools_set_sizeHelper function to set the size of the swf content in to $options['othervars']['height'] and ['width']
swftools_swftools_methodsImplementation of hook_swftools_methods().
swftools_themeImplementation of hook_theme().
swftools_variable_getReturns a variable from the relevant profile, or the global settings, or the default values.
swftools_views_apiImplementation of hook_views_api().
theme_swftools_accessible_controlsBuilds a list of accessible controls for the specified player.
_swftools_actionsReturns an array of actions, keyed by file extension.
_swftools_filter_process_textProcesses text obtained from the input filter.
_swftools_mime_typesReturns an array of mime types, keyed by file extension.
_swftools_paramsReturns 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_tfReturns 'true' or 'false' for JavaScript based the supplied value $bool.

Constants

NameDescription
SWFTOOLS_ACCESSIBLE_DISABLEDAccessible controls should be disabled.
SWFTOOLS_ACCESSIBLE_HIDDENAccessible controls should be enabled but hidden.
SWFTOOLS_ACCESSIBLE_VISIBLEAccessible controls should be enabled and visible on the page.
SWFTOOLS_ADMIN_RETRIEVESettings are being retrieved from the variables table.
SWFTOOLS_ADMIN_STORESettings are being stored in to the variables table.
SWFTOOLS_ERROR_NONEDon't write any error messages.
SWFTOOLS_ERROR_SCREENWrite error messages to the screen.
SWFTOOLS_ERROR_WATCHDOGWrite error messages to the watchdog.
SWFTOOLS_ERROR_WATCHDOG_AND_SCREENWrite error messages to both screen and watchdog.
SWFTOOLS_FULL_SETTINGSThe calling function is requesting player settings and wants the full set, including blanks and defaults.
SWFTOOLS_INSTALLEDOther modules can query whether SWF Tools is present by checking for this constant.
SWFTOOLS_MINIMUM_SETTINGSThe calling function is requesting player settings and only needs settings that are non-default.
SWFTOOLS_NON_XML_PLAYLISTThis playlist does not return xml but updates the data array directly.
SWFTOOLS_NOT_CACHEDThe swf content was not available in the cache.
SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONSWhen private access via SWF Tools is enabled grant access to these extensions.
SWFTOOLS_PRIVATE_ACCESS_DENIEDSWF Tools does not allow access to private files by default.
SWFTOOLS_RETURN_CIDSWF Tools should return the cid for the content which was stored in the cache.
SWFTOOLS_RETURN_MARKUPSWF Tools should return mark up to place on the page.
SWFTOOLS_UNDEFINEDUsed in various places to indicate that the requested item is undefined.

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * The primary component of SWF Tools that enables comprehensive media handling.
  5. */
  6. // Include the generic player module for basic mp3 and flv support
  7. module_load_include('inc', 'swftools', 'includes/swftools.genericplayers');
  8. // Load core module
  9. module_load_include('inc', 'swftools', 'includes/swftools.core');
  10. /**
  11. * @addtogroup swftools
  12. * @{
  13. */
  14. /**
  15. * Other modules can query whether SWF Tools is present by checking for this constant.
  16. */
  17. define('SWFTOOLS_INSTALLED', TRUE);
  18. /**
  19. * Used in various places to indicate that the requested item is undefined.
  20. */
  21. define('SWFTOOLS_UNDEFINED', '__undefined');
  22. /**
  23. * The calling function is requesting player settings and only needs settings that are non-default.
  24. */
  25. define('SWFTOOLS_MINIMUM_SETTINGS', 0x0001);
  26. /**
  27. * The calling function is requesting player settings and wants the full set, including blanks and defaults.
  28. */
  29. define('SWFTOOLS_FULL_SETTINGS', 0x0002);
  30. /**
  31. * SWF Tools should return mark up to place on the page.
  32. */
  33. define('SWFTOOLS_RETURN_MARKUP', 0x0000);
  34. /**
  35. * SWF Tools should return the cid for the content which was stored in the cache.
  36. */
  37. define('SWFTOOLS_RETURN_CID', 0x0001);
  38. /**
  39. * This playlist does not return xml but updates the data array directly.
  40. */
  41. define('SWFTOOLS_NON_XML_PLAYLIST', '');
  42. /**
  43. * Settings are being stored in to the variables table.
  44. */
  45. define('SWFTOOLS_ADMIN_STORE', 0x0001);
  46. /**
  47. * Settings are being retrieved from the variables table.
  48. */
  49. define('SWFTOOLS_ADMIN_RETRIEVE', 0x0000);
  50. /**
  51. * Don't write any error messages.
  52. */
  53. define('SWFTOOLS_ERROR_NONE', 0x0000);
  54. /**
  55. * Write error messages to the watchdog.
  56. */
  57. define('SWFTOOLS_ERROR_WATCHDOG', 0x0001);
  58. /**
  59. * Write error messages to the screen.
  60. */
  61. define('SWFTOOLS_ERROR_SCREEN', 0x0002);
  62. /**
  63. * Write error messages to both screen and watchdog.
  64. */
  65. define('SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN', 0x0003);
  66. /**
  67. * Accessible controls should be disabled.
  68. */
  69. define('SWFTOOLS_ACCESSIBLE_DISABLED', 0x0000);
  70. /**
  71. * Accessible controls should be enabled but hidden.
  72. */
  73. define('SWFTOOLS_ACCESSIBLE_HIDDEN', 0x0001);
  74. /**
  75. * Accessible controls should be enabled and visible on the page.
  76. */
  77. define('SWFTOOLS_ACCESSIBLE_VISIBLE', 0x0003);
  78. /**
  79. * SWF Tools does not allow access to private files by default.
  80. */
  81. define('SWFTOOLS_PRIVATE_ACCESS_DENIED', 0x0000);
  82. /**
  83. * When private access via SWF Tools is enabled grant access to these extensions.
  84. */
  85. define('SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS', 'swf flv xml mp3 jpg jpeg png');
  86. /**
  87. * The swf content was not available in the cache.
  88. */
  89. define('SWFTOOLS_NOT_CACHED', FALSE);
  90. /**
  91. * @} End of "addtogroup swftools"
  92. */
  93. /**
  94. * Implementation of hook_init().
  95. */
  96. function swftools_init() {
  97. // Add JavaScript that allows other scripts to access movies from the DOM
  98. drupal_add_js(drupal_get_path('module', 'swftools') . '/swftools.js');
  99. // Add CSS to enable hiding of accessible controls
  100. drupal_add_css(drupal_get_path('module', 'swftools') . '/swftools.css');
  101. }
  102. /**
  103. * Implementation of hook_menu().
  104. */
  105. function swftools_menu() {
  106. // Reset methods cache
  107. $methods = swftools_get_methods('', TRUE);
  108. // Should this be administer swf tools?
  109. $swf_admin = array('administer flash');
  110. $items['admin/settings/swftools'] = array(
  111. 'title' => 'SWF Tools',
  112. 'description' => 'Settings to control how SWF Tools integrates with Adobe Flash related methods and tools like video players, MP3 players and image viewers.',
  113. 'access arguments' => $swf_admin,
  114. 'page callback' => 'system_admin_menu_block_page',
  115. 'file' => 'system.admin.inc',
  116. 'file path' => drupal_get_path('module', 'system'),
  117. );
  118. $items['admin/settings/swftools/handling'] = array(
  119. 'title' => 'File handling',
  120. 'description' => 'Configure how SWF Tools should handle different types of file.',
  121. 'access arguments' => $swf_admin,
  122. 'weight' => -2,
  123. 'page callback' => 'drupal_get_form',
  124. 'page arguments' => array('swftools_admin_handling_form'),
  125. 'file' => 'includes/swftools.admin.inc',
  126. );
  127. $items['swftools/playlist/%'] = array(
  128. 'title' => 'SWF Tools playlist',
  129. 'page callback' => 'swftools_get_xml',
  130. 'page arguments' => array(2),
  131. 'access arguments' => array('access content'),
  132. 'type' => MENU_CALLBACK,
  133. );
  134. $items['swftools/page/%'] = array(
  135. 'title' => 'SWF Tools',
  136. 'page callback' => 'swftools_get_html',
  137. 'page arguments' => array(2),
  138. 'access arguments' => array('access content'),
  139. 'type' => MENU_CALLBACK,
  140. );
  141. $items['admin/settings/swftools/embed'] = array(
  142. 'title' => 'Embedding settings',
  143. 'description' => 'Set the embedding method that SWF Tools should use, and configure embedding defaults.',
  144. 'access arguments' => $swf_admin,
  145. 'weight' => -2,
  146. 'page callback' => 'drupal_get_form',
  147. 'page arguments' => array('swftools_admin_embed_form'),
  148. 'file' => 'includes/swftools.admin.inc',
  149. );
  150. // If CCK is active then add a link to the CCK formatters
  151. if (module_exists('content')) {
  152. $items['admin/settings/swftools/cck'] = array(
  153. 'title' => 'CCK formatters',
  154. 'description' => 'Additional settings to control how SWF Tools should interact with CCK.',
  155. 'access arguments' => $swf_admin,
  156. 'page callback' => 'drupal_get_form',
  157. 'page arguments' => array('swftools_admin_cck_form'),
  158. 'file' => 'includes/swftools.admin.inc',
  159. );
  160. }
  161. // Add SWF Tools status report
  162. $items['admin/reports/swftools'] = array(
  163. 'title' => 'SWF Tools status',
  164. 'description' => 'Get an overview of the status of the SWF Tools module and its supporting files.',
  165. 'page callback' => 'swftools_status',
  166. 'access arguments' => $swf_admin,
  167. 'file' => 'includes/swftools.admin.status.inc',
  168. 'weight' => 9,
  169. );
  170. // Integrate items from the generic players module
  171. $items = array_merge($items, swftools_genericplayers_menu());
  172. // Return array of menu items
  173. return $items;
  174. }
  175. /**
  176. * Implementation of hook_perm().
  177. */
  178. function swftools_perm() {
  179. return array(
  180. 'administer flash',
  181. );
  182. }
  183. /**
  184. * Processes a file, or an array of files, and returns the relevant mark-up to
  185. * render a Flash based player.
  186. *
  187. * @param mixed $content
  188. * The content to be played. If it is a SWF file it will usually be embedded directly.
  189. * Use a full URL, a path relative to webroot, or a path relative to the configured files directory.
  190. * If an array is passed then the array will be converted to a playlist automatically.
  191. * If it is a string and it is a complete url then SWF Tools will pass it along unaltered.
  192. * If the string is a partial path then it will either be resolved to the local file system,
  193. * or to a remote host, depending whether the swftools_media_url variable is set.
  194. * @param array $options
  195. * An associative array of optional paramters and settings containing:
  196. * - params: An associative array of <param> variables to set.eg. array('bgcolor'=>'FF00FF'),
  197. * or to set the height and width: array('width'=>'200', 'height'=>'120').
  198. * If you pass nothing, and the file to play is a .swf, swftools will try and
  199. * establish a natural width and height from the actual .swf file that you've
  200. * passed into $file.
  201. * - flashvars: An associative array of flashvar variables to set. eg.
  202. * array('playlist'=>'files/my_playlist.xml')
  203. * - othervars: An associative array of variables that might be required by the $player
  204. * or $embed technique. These values are not output as params or flashvars.
  205. * - methods: An array of data to explicitly declare an action, player or embed method and
  206. * over-ride the default value that SWF Tools will otherwise use. Contains the following
  207. * optional keys:
  208. * - action: (string) A specific action to be taken, e.g. image_list
  209. * - player: (string) A specific player to be used, e.g. flowplayer3
  210. * - embed: (string) A specific embedding method, e.g. swftools_direct
  211. *
  212. * @return string
  213. * A markup string.
  214. *
  215. * @ingroup swftools
  216. */
  217. function swf($content, $options = array()) {
  218. // $time_start = microtime(true);
  219. // TODO: We should put SWF Tools own settings somewhere safe in the othervars array
  220. // If someone passes a variable from the input filter it could collide.
  221. // Maybe put them under #swftools (since the data are properties of swftools?)
  222. // A finished item has player, profile, cid, id, file_url, src_path, src
  223. // Initialise any $options array elements that weren't passed by the caller
  224. swftools_initialise_options($options);
  225. // Initialise othervars with some defaults
  226. $options['othervars'] += array(
  227. 'profile' => '',
  228. 'return' => SWFTOOLS_RETURN_MARKUP,
  229. 'playlist_data' => '',
  230. 'image' => '',
  231. 'stream' => FALSE,
  232. 'xml' => '',
  233. );
  234. // Initialise methods with some defaults
  235. $options['methods'] += array(
  236. 'action' => '',
  237. 'player' => '',
  238. 'embed' => '',
  239. // 'stream' => '',
  240. );
  241. // Initialise params with some defaults
  242. $options['params'] += array(
  243. 'base' => swftools_get_base(),
  244. );
  245. // See if we can get this item from the SWF Tools cache
  246. if (($ret = swftools_get_from_cache($content, $options)) && variable_get('swftools_cache', CACHE_NORMAL)) {
  247. // $time_end = microtime(true);
  248. // $time = $time_end - $time_start;
  249. // dsm('Used cache in ' . $time);
  250. if ($ret->headers && $script_location = variable_get('swftools_javascript_location', SWFTOOLS_JAVASCRIPT_INLINE)) {
  251. drupal_add_js($ret->headers, 'inline', $script_location == SWFTOOLS_JAVASCRIPT_HEADER ? 'header' : 'footer');
  252. }
  253. return $options['othervars']['return'] == SWFTOOLS_RETURN_CID ? $options['othervars']['cid'] : $ret->data['html'];
  254. }
  255. // Ensure id is unique, or assign an id if one isn't set
  256. $options['othervars']['id'] = swftools_get_id($options['othervars']['id']);
  257. // If swf() was called with an array of files, make a playlist
  258. if (is_array($content)) {
  259. // Turn the array in to a playlist and attach it to othervars
  260. swftools_prepare_playlist($content, $options);
  261. }
  262. // ACTION
  263. // Work out what SWF Tools should do with this file (e.g. video, audio)
  264. // If an explicit action wasn't set then try to determine an appropriate one using the filename
  265. $options['methods']['action'] = $options['methods']['action'] ? swftools_fix_old_action_names($options['methods']['action']) : swftools_get_action($content);
  266. // RESOLVE PLAYER AND EMBEDDING
  267. // 'resolved' refers to the fact that these are the methods we now intend to use, not /all/ methods available.
  268. // PLAYER
  269. // Work out what player SWF Tools will need to use for this action
  270. // If an explicit player wasn't set then find out what player is configured for the current action
  271. $options['methods']['player'] = $options['methods']['player'] ? swftools_fix_old_player_names($options['methods']['player']) : swftools_get_player($options['methods']['action'], $options['othervars']['profile']);
  272. // If there is no player assigned we don't what to do with this action
  273. if (!$options['methods']['player']) {
  274. // Get the descriptions that go with the actions
  275. $actions = swftools_get_actions();
  276. // If we have a matching description for the specified action, create a meaningful message
  277. if (isset($actions[$options['methods']['action']]['#description'])) {
  278. // If we also have a meaningful profile name use that too
  279. if ($options['othervars']['profile']) {
  280. if (function_exists('swftools_profiles_get_profile') && ($profile = swftools_profiles_get_profile($options['othervars']['profile']))) {
  281. $profile = $profile['name'];
  282. }
  283. else {
  284. $profile = $options['othervars']['profile'];
  285. }
  286. $profile = t('@profile profile', array('@profile' => $profile));
  287. }
  288. else {
  289. $profile = 'SWF Tools';
  290. }
  291. // And output a message
  292. 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);
  293. }
  294. // Otherwise we have an action that SWF Tools doesn't understand, so create a fallback message
  295. else {
  296. 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);
  297. }
  298. // We couldn't find a player for this content, so fallback to the alternate markup and return
  299. return theme('swftools_html_alt', $options);
  300. }
  301. // Get all the actions, tools and embedding options available to us
  302. $all_methods = swftools_get_methods();
  303. // Check that the action / player combination is valid (it should appear in the array of all methods)
  304. if (isset($all_methods[$options['methods']['action']][$options['methods']['player']])) {
  305. // The combination was found, place player information in to resolved_methods
  306. $options['resolved_methods']['player'] = $all_methods[$options['methods']['action']][$options['methods']['player']];
  307. }
  308. // If the action / player combination doesn't appear then we give up here
  309. else {
  310. // Get the descriptions that go with the actions
  311. $actions = swftools_get_actions();
  312. // Set an error
  313. 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);
  314. // Return alternate markup
  315. return theme('swftools_html_alt', $options);
  316. }
  317. // EMBED
  318. // Work out what embedding method SWF Tools should use for this content
  319. // If an explicit embed method was not set then assign one now
  320. $options['methods']['embed'] = $options['methods']['embed'] ? $options['methods']['embed'] : variable_get('swftools_embed_method', 'swftools_direct');
  321. // Place the embedding method information in to resolved_methods
  322. $options['resolved_methods']['embed'] = $all_methods['swftools_embed_method'][$options['methods']['embed']];
  323. // PARAMS
  324. // If $options['params'] is not an array then assume it is width x height as a string
  325. // TODO: This is an ugly legacy - can we retire it?
  326. if (!is_array($options['params'])) {
  327. // Explode string
  328. $dimensions = explode('x', $options['params']);
  329. // If we got two pieces assume success
  330. if (count($dimensions) == 2) {
  331. $options['params'] = array(
  332. 'width' => $dimensions[0],
  333. 'height' => $dimensions[1],
  334. );
  335. }
  336. }
  337. // FLASHVARS
  338. // If the flashvars were passed as a string then turn it in to an array
  339. // Does the filter pass the flashvars as a string? Could we explode the string in
  340. // their, and then we know we only get an array?
  341. if (!is_array($options['flashvars'])) {
  342. parse_str($options['flashvars'], $options['flashvars']);
  343. }
  344. // XML PLAYLIST
  345. // Determine if we are trying to generate a playlist that needs xml output, and create it if required
  346. // If $options['othervars']['playlist_data'] is set then we are processing a playlist
  347. if ($options['othervars']['playlist_data']) {
  348. // Try to generate an xml playlist and get the path to the xml file. $content will be an empty string if we don't need xml.
  349. $content = swftools_generate_playlist($options);
  350. }
  351. // FILE
  352. // Make sure that the file path in $content is valid, and as necessary try to
  353. // expand it to a relative url on the local file system, or point to the remote media directory
  354. // First we assume that we can just set $file_url to the value in $content
  355. $file_url = $content;
  356. // If we are not streaming this file, and $content isn't empty, then we might need to process it to get a proper path
  357. if (!$options['othervars']['stream'] && $content) {
  358. // Process to get a url (in src) and expand the path (in src_path) if necessary
  359. $source = swftools_get_url_and_path($content);
  360. // If FALSE was returned then the file doesn't exist so return $html_alt
  361. if (!$source) {
  362. return theme('swftools_html_alt', $options);
  363. }
  364. // $file might need to be changed to reflect a path on the local file system
  365. // This happens when the user just supplied a filename and files are being sourced locally
  366. // Put $content = $source['filepath'] in case that happened
  367. $content = $source['filepath'];
  368. // In all cases $file_url is now an absolute, or relative, url to the file that we can use
  369. $file_url = $source['fileurl'];
  370. }
  371. // Attach file_url to othervars so player modules have access if required
  372. $options['othervars']['file_url'] = $file_url;
  373. // Depending if we are outputting a swf or using a player we need to attach $file in different places
  374. switch ($options['methods']['player']) {
  375. // Embedding an swf directly - no player
  376. case 'swf':
  377. $options['othervars']['filepath'] = $content;
  378. $options['othervars']['fileurl'] = $file_url;
  379. break;
  380. // Embedding with a player
  381. default:
  382. if ($options['resolved_methods']['player']['library']) {
  383. $options['othervars']['filepath'] = $options['resolved_methods']['player']['library'];
  384. $options['othervars']['fileurl'] = base_path() . $options['othervars']['filepath'];
  385. }
  386. }
  387. // Merge default and user defined parameters, with user defined ones taking precedence
  388. $options['params'] = array_merge(_swftools_params(), $options['params']);
  389. // If player requires a higher version of flash than the current default then over-ride the default
  390. if (version_compare($options['resolved_methods']['player']['version'], $options['params']['version'], '>')) {
  391. $options['params']['version'] = $options['resolved_methods']['player']['version'];
  392. }
  393. /**
  394. * We used to call hook_flashvars, using the module name, but we are starting to do a lot
  395. * more than just flashvars. So we will borrow from the theme system and implement
  396. * hook_swftools_preprocess_[playername]. Normally you would just expect the module that
  397. * defines the player to handle its own players, but in theory anyone can hook in at this
  398. * point and manipulate the entire data array just before we output it.
  399. */
  400. $preprocess = 'swftools_preprocess_' . $options['resolved_methods']['player']['name'];
  401. foreach (module_implements($preprocess) as $module) {
  402. $function = $module . '_' . $preprocess;
  403. $function($options);
  404. }
  405. // TODO: Can we deprecate this - we are accommodating the ability to specify width x height in a string on params.
  406. // We used to set height and width on $vars->params, but they're not actually params and they were
  407. // being unset in individual embedding functions. So we'll move them to $vars->othervars.
  408. // We will continue to let users pass the data on $vars->params so as not to break existing code.
  409. if (!isset($options['othervars']['height']) && !empty($options['params']['height'])) {
  410. $options['othervars']['height'] = $options['params']['height'];
  411. unset($options['params']['height']);
  412. }
  413. if (!isset($options['othervars']['width']) && !empty($options['params']['width'])) {
  414. $options['othervars']['width'] = $options['params']['width'];
  415. unset($options['params']['width']);
  416. }
  417. // Try and make sure we have a size set on this content
  418. swftools_set_size($options);
  419. // Change html_alt to include the first image when handling an image list
  420. // TODO: Should this be an option that can be disabled?
  421. if ($options['methods']['action'] == 'image_list') {
  422. swftools_image_html_alt($options);
  423. }
  424. // See if anyone wants to alter anything just before it is output
  425. drupal_alter('swftools', $options);
  426. // Call theme function
  427. $output = theme('swftools_embed', $options);
  428. // See if the embed placed a script for us to cache
  429. $script = ($data = drupal_get_js($options['othervars']['id'])) ? str_replace(array("<script type=\"text/javascript\">\n<!--//--><![CDATA[//><!--\n", "\n//--><!]]>\n</script>\n"), '', $data) : '';
  430. // Cache the result using an array to store the markup and any associated xml
  431. cache_set($options['othervars']['cid'], array('html' => $output, 'xml' => $options['othervars']['xml']), 'cache_swftools', CACHE_TEMPORARY, $script);
  432. // If we want just the cid then return that
  433. if ($options['othervars']['return'] == SWFTOOLS_RETURN_CID) {
  434. return $options['othervars']['cid'];
  435. }
  436. // Return the markup
  437. return $output;
  438. }
  439. /**
  440. * Converts an array of paramters to JSON and returns them as a string ready for use as a flashvar.
  441. *
  442. * @param array $params
  443. * An array of parameters.
  444. * @param string $attribute
  445. * The attribute that the JSON string will be attached to.
  446. *
  447. * @return string
  448. * A string in the form [attr]={JSON}
  449. */
  450. function swftools_json_params(&$params, $attribute = 'swftools') {
  451. return $attribute . "='" . drupal_to_js($params) . "'";
  452. }
  453. /**
  454. * Returns 'true' or 'false' for JavaScript based the supplied value $bool.
  455. *
  456. * @param bool $bool
  457. * The value that should be cast to true or false.
  458. *
  459. * @return string
  460. * The string value 'true' or 'false' depending on the supplied value.
  461. */
  462. function _swftools_tf($bool) {
  463. // String 'false' is treated as TRUE in PHP logic, so force to FALSE
  464. if (strtolower($bool) == 'false') {
  465. $bool = FALSE;
  466. }
  467. // Return 'true' or 'false' now we are sure of result
  468. return $bool ? 'true' : 'false';
  469. }
  470. /**
  471. * Returns the currently configured player for the specified action and profile.
  472. *
  473. * We use a static array so that if we are generating a complex page we can
  474. * quickly locate the relevant action/profile player after we've done it the
  475. * first time. This saves us from repeat calls to swftools_variable_get().
  476. *
  477. * @param string $action
  478. * The SWF Tools action to be performed.
  479. * @param string $profile
  480. * (optional) The profile being used for this item.
  481. *
  482. * @return string
  483. * The name of the currently configured player for this action.
  484. */
  485. function swftools_get_player($action, $profile = '') {
  486. // Initialise a static array for this page call
  487. static $players = array();
  488. // We need to give the empty profile a name to place it in the array
  489. $_profile = $profile ? $profile : SWFTOOLS_UNDEFINED;
  490. // Do we already know the players for this profile?
  491. if (!isset($players[$_profile])) {
  492. // Register the players for this profile in the array
  493. $players[$_profile] = swftools_get_players($profile);
  494. }
  495. // Return the result
  496. return isset($players[$_profile][$action]) ? $players[$_profile][$action] : FALSE;
  497. }
  498. /**
  499. * Returns an array of default values to use as the swf parameters.
  500. * Parameters are described in the Adobe knowledge base TechNote 12701
  501. * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
  502. */
  503. function _swftools_params() {
  504. // Cache this
  505. static $params = array();
  506. // If not set then get defaults
  507. if (!$params) {
  508. // Define default parameters for case when settings have been stored
  509. $defaults = array(
  510. 'swliveconnect' => 'false',
  511. 'play' => 'true',
  512. 'loop' => 'true',
  513. 'menu' => 'false',
  514. 'allowfullscreen' => 'true',
  515. 'quality' => 'autohigh',
  516. 'scale' => 'showall',
  517. 'align' => 'l',
  518. 'salign' => 'tl',
  519. 'wmode' => 'opaque',
  520. 'bgcolor' => '',
  521. 'version' => '7',
  522. 'allowscriptaccess' => 'sameDomain',
  523. );
  524. // Retrieve settings from the database if available
  525. $params = variable_get('swftools_params', $defaults);
  526. }
  527. // Return the default parameters
  528. return $params;
  529. }
  530. /**
  531. * Returns information about the specified file.
  532. *
  533. * We use this function to try and get the height and width for content that
  534. * we don't have a specific size for.
  535. *
  536. * The returned value is an array that may include width, height, extension,
  537. * file_size, mime_type. We return FALSE if we didn't get a valid file, or if
  538. * image_get_info() couldn't tell us anything.
  539. *
  540. * @parameter string $file
  541. * Path to a local file that we want to interrogate.
  542. *
  543. * @return mixed
  544. * An array of data, or FALSE if we didn't get anything.
  545. */
  546. function swftools_get_info($file) {
  547. // Assume we won't have data
  548. $info = FALSE;
  549. // Try to get image info (first assume it is in the file directory (most likely case))
  550. if ($try = file_create_path($file)) {
  551. $info = image_get_info($try);
  552. }
  553. // If it wasn't in the file system just try the file path - that might be valid
  554. if (!$info) {
  555. $info = image_get_info($file);
  556. }
  557. // Return either the info array, or it will be FALSE if we got nothing
  558. return $info;
  559. }
  560. /**
  561. * Generates an playlist and places it in {cache_swftools} ready for use.
  562. *
  563. * This relies on player modules implementing hook_swftools_playlist_[player].
  564. * A module implementing this hook may either return an xml string that will be
  565. * used by the player, or it may update the data array directly.
  566. *
  567. * We don't check for the existence of this content in the cache already. If we
  568. * are here then the swf wasn't in the cache, so the xml isn't either.
  569. *
  570. * We used to create an actual file. Now we place the content in {cache_swftools}
  571. * and access it via swftools/playlist/nnn, where nnn is the cid.
  572. *
  573. * The xml result from this function is attached to $options['othervars']['xml']
  574. * and the the calling swf() function will cache this for us.
  575. *
  576. * @param &$options
  577. * The SWF Tools data array for this element.
  578. *
  579. * @return
  580. * The path to the virtual xml file (will be in the form swftools/playlist/nnn),
  581. * or an empty string (SWFTOOLS_NON_XML_PLAYLIST) if there is no xml.
  582. */
  583. function swftools_generate_playlist(&$options) {
  584. // Determine the name of the hook that would be used to generate an xml playlist
  585. $hook = '_swftools_playlist_' . $options['resolved_methods']['player']['name'];
  586. // Build the name of the function we would call
  587. $function = $options['resolved_methods']['player']['module'] . $hook;
  588. // See if the function exists - if it doesn't the module doesn't implement this hook
  589. if (function_exists($function)) {
  590. // Call the function and pass variables by reference
  591. $playlist = $function($options);
  592. // If playlist is not empty this is an xml playlist
  593. if ($playlist) {
  594. // Store the result on to $optinos['othervars']['xml']
  595. $options['othervars']['xml'] = $playlist;
  596. // Return the path to the xml
  597. // return url('swftools/playlist/' . $options['othervars']['cid'] . '.xml');
  598. return url('swftools/playlist/' . $options['othervars']['cid']);
  599. }
  600. }
  601. // We don't have hook_swftools_playlist_[player] for this player, return an empty string
  602. return SWFTOOLS_NON_XML_PLAYLIST;
  603. }
  604. /**
  605. * Prepares an array of filenames, or file objects, for use in a playlist.
  606. *
  607. * This function processes the supplied array and returns an array of playlist data which has
  608. * two elements, header and playlist. The header array contains the playlist title, which may
  609. * be an empty string if nothing was set. The playlist array contains an array of playlist
  610. * elements. As a minimum each element will contain:
  611. * - filepath : the filepath for the file, if it is a local file, or FALSE if a full url
  612. * - title : the title for the element, set to the filename if nothing given
  613. * - filename : the filename for the file
  614. * - fileurl : the full url to the file
  615. *
  616. * drupal_alter is called just prior to returning the playlist, so a module can implement
  617. * hook_swftools_playlist_alter(&$playlist_data) to modify the playlist prior to return. This
  618. * means other modules can modify, or add, elements. For example, the swftools_getid3 module
  619. * implements this hook to attach ID3 data to each playlist element.
  620. *
  621. * @param array $files
  622. * An array of files that will be added to the playlist.
  623. * @param array $options
  624. * Array of data passed in from the calling swf() function.
  625. *
  626. * @return nothing
  627. * Attaches the resulting playlist data to $options['othervars']['playlist_data']
  628. */
  629. function swftools_prepare_playlist($files, &$options) {
  630. // Make sure stream and action are present on options
  631. $options['methods'] += array(
  632. 'player' => '',
  633. );
  634. // Initialise two flags for establishing the action to be taken on this playlist
  635. $action = '';
  636. $mixed_media = FALSE;
  637. // Initialise playlist data array
  638. $playlist_data = array(
  639. 'header' => array(),
  640. 'playlist' => array(),
  641. );
  642. // Iterate over the array of files to set filepath, fileurl and title keys
  643. foreach ($files AS $key => $data) {
  644. // If $data is an object convert it to an array
  645. if (is_object($data)) {
  646. $data = (array)$data;
  647. }
  648. // If $data is a string then make it array with this value on the filepath key
  649. elseif (!is_array($data)) {
  650. // Create an array with key filepath set to the $data string
  651. $data = array(
  652. 'filepath' => $data,
  653. );
  654. }
  655. // Attach the incoming element to the playlist
  656. $playlist_data['playlist'][$key] = $data;
  657. /**
  658. * Ensure the title key is present to simplify later code as we know it will be present.
  659. * Note we no longer set a default title. We leave it empty since all output should
  660. * now be handled by a theme function, so if the user wants to make a default we can
  661. * let them since they will know a specific value wasn't given. We don't do it for them.
  662. *
  663. * We also initialise some other empty strings to make checks in other modules easier.
  664. */
  665. $playlist_data['playlist'][$key] += array(
  666. 'title' => '',
  667. 'image' => '',
  668. 'description' => '',
  669. 'author' => '',
  670. 'date' => '',
  671. 'link' => '',
  672. 'duration' => '',
  673. 'stream' => FALSE,
  674. );
  675. // Find out if this item is a stream by checking for rtmp and exploding it
  676. if (strpos($playlist_data['playlist'][$key]['filepath'], 'rtmp:') === 0) {
  677. $stream = explode(' ', $playlist_data['playlist'][$key]['filepath']);
  678. // If the filepath exploded then assume we have a valid stream
  679. if (count($stream) == 2) {
  680. list($playlist_data['playlist'][$key]['stream'], $playlist_data['playlist'][$key]['filepath']) = $stream;
  681. $options['othervars']['stream'] = TRUE;
  682. // TODO: Action checking fails as streams don't have an extension - assume mixed media
  683. $options['methods']['action'] = 'media_list';
  684. }
  685. }
  686. // If this whole playlist isn't a stream, and this item isn't a stream
  687. if (!is_string($options['othervars']['stream']) && !$playlist_data['playlist'][$key]['stream']) {
  688. // Expand $file as necessary if local or remote
  689. $source = swftools_get_url_and_path($playlist_data['playlist'][$key]['filepath']);
  690. // Store results
  691. $playlist_data['playlist'][$key]['filepath'] = $source['filepath'];
  692. $playlist_data['playlist'][$key]['fileurl'] = $source['fileurl'];
  693. }
  694. else {
  695. $playlist_data['playlist'][$key]['fileurl'] = $playlist_data['playlist'][$key]['filepath'];
  696. }
  697. // See if we have an image we need to expand
  698. if ($playlist_data['playlist'][$key]['image']) {
  699. $source = swftools_get_url_and_path($playlist_data['playlist'][$key]['image']);
  700. $playlist_data['playlist'][$key]['image'] = $source['fileurl'];
  701. }
  702. // Allow other modules to modify this playlist element (e.g. getID3)
  703. drupal_alter('swftools_playlist_element', $playlist_data['playlist'][$key]);
  704. // If the caller wants us to work out the action for them then it happens in here
  705. if (!$options['methods']['action']) {
  706. // Get the extension for this item
  707. $extension = strtolower(pathinfo($playlist_data['playlist'][$key]['fileurl'], PATHINFO_EXTENSION));
  708. // Only try to determine actions if there's an extension to work with, and we didn't already work out it's mixed
  709. if ($extension && !$mixed_media) {
  710. // Work out what we'd do with this file
  711. $action_for_this_file = swftools_get_action('dummy.' . $extension);
  712. // If this is the first file we've processed we log it
  713. if (!$action) {
  714. $action = $action_for_this_file;
  715. }
  716. // Is this action the same as the first file we saw? If not we have mixed media
  717. if ($action != $action_for_this_file) {
  718. $mixed_media = TRUE;
  719. $action = 'media_list';
  720. }
  721. }
  722. }
  723. }
  724. // If we didn't get an action (happens with streams as they have no extension) then specify an action now
  725. $action = $action ? $action : 'media_list';
  726. // Pluralize the action for multiple files if not already pluralized
  727. $action = (substr($action, -5, 5) == '_list') ? $action : $action . '_list';
  728. // If the called didn't specify an action then assign it now
  729. $options['methods']['action'] = $options['methods']['action'] ? $options['methods']['action'] : $action;
  730. // Attach the resulting playlist to the array (we are working by reference)
  731. $options['othervars']['playlist_data'] = $playlist_data;
  732. // Call drupal_alter to let other modules modify the entire playlist if they want
  733. drupal_alter('swftools_playlist', $playlist_data);
  734. }
  735. /**
  736. * Implementation of hook_filter_tips().
  737. */
  738. function swftools_filter_tips($delta, $format, $long = FALSE) {
  739. if ($long) {
  740. return t('
  741. <h3 id="swftools_filter">SWF Tools Filter</h3>
  742. <p>The basic syntax for embedding a flash file (.swf), flash movie (.flv) or audio file (.mp3) is:</p>
  743. <blockquote><code>[swf file="filename.swf"]</code></blockquote>
  744. <p>If you would like to override SWF Tools and flash player default settings,
  745. you can specify additional parameters. For example:</p>
  746. <blockquote><code>[swf file="song.mp3" flashvars="backcolor=#AABBCC&&forecolor=#11AA11"]</code></blockquote>
  747. <p>If you would like to output a list of files then the format is:</p>
  748. <blockquote><code>[swf files="image1.jpg&&image2.jpg&&..."]</code></blockquote>
  749. SWF Tools Filter will accept following:
  750. <ul>
  751. <li><b>params</b> : You can specify values for parameters to be passed to Flash
  752. to control the appearance of the output. Typical values are
  753. bgcolor and wmode. Example: <code>params="wmode=true&&bgcolor="#00FF00"</code>
  754. Alternatively you can supply each parameter individually without using
  755. <code>params</code>. Example <code>wmode="true" bgcolor="#00FF00"</code></li>
  756. <li><b>flashvars</b> : You can specify values for output as flashvars, which
  757. become available to the Flash movie that is playing. This is often done
  758. to control a media player. Refer to the documentation of the flash player
  759. you are using to know what flashvar options are available.
  760. Example: <code>flashvars="autostart=true&&volume=80"</code></li>
  761. <li><b>methods</b> : Optional information about how to display the file. The most
  762. common usage is to specify a particular media player and
  763. thus override the default specified on the settings page.
  764. Example: <code>methods="player=onepixelout_mp3"</code></li>
  765. </ul>
  766. <p><strong>WARNING</strong>: with params, flashvars and othervars, pass multiple values
  767. separated by <strong>&amp;&amp;</strong>.</p>');
  768. }
  769. else {
  770. return t('You may use [swf file="song.mp3"] to display Flash files and media.');
  771. }
  772. }
  773. /**
  774. * Implementation of hook_filter().
  775. */
  776. function swftools_filter($op, $delta = 0, $format = -1, $text = '') {
  777. switch ($op) {
  778. case 'list':
  779. return array(0 => t('SWF Tools filter'));
  780. case 'no cache':
  781. return FALSE;
  782. case 'description':
  783. return t('Substitutes [swf file="filename.flv"] or [swf files="file1.jpg&&file2.jpg"] with embedding code.');
  784. case 'prepare':
  785. // replace <swf > with [swf ] to prevent other filters stripping
  786. return (preg_replace('/\<(swflist|swf)\s*(.*)>/sU', '[\1 \2]', $text));
  787. case 'process':
  788. return _swftools_filter_process_text($text);
  789. }
  790. }
  791. /**
  792. * Processes text obtained from the input filter.
  793. *
  794. * This function processes the filter text that the user has added to the text area.
  795. * If the filter is wrapped in <p></p> then these are stripped as part of the processing
  796. * This eliminates a validation error in the resulting mark up if SWF Tools filter is
  797. * being used in conjunction with other HTML filters that correct line breaks.
  798. * It won't work in EVERY case, but it will work in MOST cases.
  799. * Filters that are embedded in-line with text will continue to fail validation.
  800. */
  801. function _swftools_filter_process_text($text) {
  802. $endl = chr(13) ;
  803. if (preg_match_all('@(?:<p>)?\[(swflist|swf)\s*(.*?)\](?:</p>)?@s', $text, $match)) {
  804. // $match[0][#] .... fully matched string <swf|swflist parm_0="value_0" parm_1="value_1" parm_2="value_2">
  805. // $match[1][#] .... matched tag type ( swf | swflist )
  806. // $match[2][#] .... full params string until the closing '>'
  807. $swftools_parameters = array('file', 'params', 'flashvars', 'othervars', 'methods', 'files');
  808. $match_vars = array();
  809. // Initialise an array to hold playlist arrays
  810. $files = array();
  811. foreach ($match[2] as $key => $passed_parameters) {
  812. //preg_match_all('/(\w*)=\"(.*?)\"/', $passed_parameters, $match_vars[$key]);
  813. preg_match_all('/(\w*)=(?:\"|&quot;)(.*?)(?:\"|&quot;)/', $passed_parameters, $match_vars[$key]);
  814. // $match_vars[0][#] .... fully matched string
  815. // $match_vars[1][#] .... matched parameter, eg flashvars, params
  816. // $match_vars[2][#] .... value after the '='
  817. // Process the parameters onto the $prepared array.
  818. // Search for standard parameters, parse the values out onto the array.
  819. foreach ($match_vars[$key][1] as $vars_key => $vars_name) {
  820. // Switch to swf or swflist, based on file or files
  821. // Need to tidy up this line, probably use switch/case
  822. if ($vars_name == 'file') {
  823. $match[1][$key] = 'swf';
  824. }
  825. else {
  826. if ($vars_name == 'files') {
  827. $match[1][$key] = 'swflist';
  828. }
  829. }
  830. if ($vars_name == 'file') {
  831. $prepared[$key][$vars_name] = $match_vars[$key][2][$vars_key];
  832. unset($match_vars[$key][1][$vars_key]);
  833. }
  834. elseif (in_array($vars_name, $swftools_parameters)) {
  835. $prepared[$key][$vars_name] = swftools_parse_str(str_replace(array('&amp;&amp;', '&&'), '&', $match_vars[$key][2][$vars_key]));
  836. unset($match_vars[$key][1][$vars_key]);
  837. }
  838. else {
  839. $prepared[$key]['othervars'][$vars_name] = $match_vars[$key][2][$vars_key];
  840. }
  841. }
  842. // Search for remaining parameters, map them as elements of the standard parameters.
  843. if (isset($prepared[$key]['methods']['player'])) {
  844. $player = strtolower($prepared[$key]['methods']['player']);
  845. }
  846. else {
  847. $player_key = array_search('player', $match_vars[$key][1]);
  848. if ($player_key!==FALSE) {
  849. $player = strtolower($match_vars[$key][2][$player_key]);
  850. }
  851. else {
  852. $player = FALSE;
  853. }
  854. }
  855. $prepared[$key]['methods']['player'] = $player;
  856. if (count($match_vars[$key][1])) {
  857. // Find out if a player has been set.
  858. foreach ($match_vars[$key][1] as $vars_key => $vars_name) {
  859. if ($parent = swftools_get_filter_alias($vars_name, $player)) {
  860. if ($parent) {
  861. $prepared[$key][$parent][$vars_name] = $match_vars[$key][2][$vars_key];
  862. }
  863. }
  864. }
  865. }
  866. // Just assigning parameters as false if not already set on the $prepared array.
  867. // Really just to avoid declaration warnings when we call swf and swf_list
  868. if (count($prepared[$key])) {
  869. foreach ($swftools_parameters AS $swfparameter) {
  870. if (!isset($prepared[$key][$swfparameter])) {
  871. $prepared[$key][$swfparameter] = array();
  872. }
  873. }
  874. }
  875. // Assemble in to an array of options ready to pass
  876. $options = array();
  877. $options['params'] = $prepared[$key]['params'];
  878. $options['flashvars'] = $prepared[$key]['flashvars'];
  879. $options['othervars'] = $prepared[$key]['othervars'];
  880. $options['methods'] = $prepared[$key]['methods'];
  881. // Do not allow override of alternate HTML unless setteings allow it
  882. if (isset($options['othervars']['html_alt']) && !variable_get('swftools_override_html_alt', 0)) {
  883. $options['othervars']['html_alt'] = variable_get('swftools_html_alt', SWFTOOLS_DEFAULT_HTML_ALT);
  884. }
  885. // Process the filter
  886. switch ($match[1][$key]) {
  887. case 'swf':
  888. $replace = swf($prepared[$key]['file'], $options);
  889. break;
  890. case 'swflist':
  891. // If this filter contains a key called files
  892. if ($prepared[$key]['files']) {
  893. // Iterate over the
  894. foreach ($prepared[$key]['files'] AS $name => $filename) {
  895. if (!$filename) {
  896. $prepared[$key]['files'][$name] = $name;
  897. }
  898. // Put in to proper format for new swftools_prepare_playlist()
  899. $files[$key][$name]['filepath'] = $prepared[$key]['files'][$name];
  900. }
  901. // Get playlist data, but don't determine action if the user specified a player
  902. $replace = swf($files[$key], $options);
  903. }
  904. else {
  905. $replace = '<!-- No files passed to the playlist -->';
  906. }
  907. break;
  908. }
  909. $matched[] = $match[0][$key];
  910. $rewrite[] = $replace;
  911. }
  912. return str_replace($matched, $rewrite, $text);
  913. }
  914. return $text;
  915. }
  916. /**
  917. * Implements a hook that extends the parameters that can be passed to the filter
  918. * so that myvar="value" can be mapped to flashvars, etc.
  919. */
  920. function swftools_get_filter_alias($var, $player = FALSE) {
  921. static $general_mapping = array();
  922. static $player_mapping = array();
  923. if (!count($general_mapping)) {
  924. // Build up the mapping arrays.
  925. $general_mapping = array(
  926. 'action' => 'methods',
  927. 'embed' => 'methods',
  928. 'width' => 'params',
  929. 'height' => 'params',
  930. 'swliveconnect' => 'params',
  931. 'play' => 'params',
  932. 'loop' => 'params',
  933. 'menu' => 'params',
  934. 'quality' => 'params',
  935. 'scale' => 'params',
  936. 'align' => 'params',
  937. 'salign' => 'params',
  938. 'wmode' => 'params',
  939. 'bgcolor' => 'params',
  940. 'base' => 'params',
  941. 'version' => 'params',
  942. 'allowfullscreen' => 'params',
  943. 'allowscriptaccess' => 'params',
  944. );
  945. if (!count($player_mapping)) {
  946. $player_mapping = module_invoke_all('swftools_variable_mapping');
  947. }
  948. $combined = array();
  949. if (count($player_mapping)) {
  950. foreach ($player_mapping AS $mapping) {
  951. $combined = array_merge($combined, $mapping);
  952. }
  953. $general_mapping = array_merge($combined, $general_mapping);
  954. }
  955. }
  956. // Return the parent of the variable.
  957. if ($player && isset($player_mapping[$player][$var])) {
  958. return $player_mapping[$player][$var];
  959. }
  960. else {
  961. return (isset($general_mapping[$var])) ? $general_mapping[$var] : FALSE;
  962. }
  963. }
  964. /**
  965. * Parses a string passed to the input filter in to separate key value pairs.
  966. *
  967. * We cannot automatically use parse_str() because things like the list of
  968. * files are not key-value pairs, but just a list of items.
  969. *
  970. * @param string $string
  971. * The string to parse.
  972. *
  973. * @return array
  974. * An array of key/value pairs.
  975. */
  976. function swftools_parse_str($string) {
  977. // Initialise the array
  978. $return = array();
  979. // Split the string at each &
  980. $pairs = split('&', $string);
  981. // Iterate over each piece
  982. foreach ($pairs as $pair) {
  983. // Split each piece at =
  984. $splitpair = split('=', $pair);
  985. // If there was only one item, or this key is already in the array append the value
  986. if (!isset($splitpair[1]) || array_key_exists($splitpair[0], $return)) {
  987. $return[] = $splitpair[0];
  988. }
  989. // Otherwise we had a key-value we can add to the array
  990. else {
  991. $return[$splitpair[0]] = $splitpair[1];
  992. }
  993. }
  994. // Return the result
  995. return $return;
  996. }
  997. /**
  998. * Implementation of hook_theme().
  999. */
  1000. function swftools_theme() {
  1001. return array(
  1002. // This is called by swf() when it is ready to embed
  1003. 'swftools_embed' => array(
  1004. 'arguments' => array('data' => NULL),
  1005. 'file' => 'includes/swftools.theme.inc',
  1006. ),
  1007. // This implements the direct embedding method
  1008. 'swftools_direct' => array(
  1009. 'arguments' => array('file' => NULL, 'data' => NULL),
  1010. 'file' => 'includes/swftools.core.inc',
  1011. ),
  1012. // This themes the alternate HTML markup
  1013. 'swftools_html_alt' => array(
  1014. 'arguments' => array('data' => NULL),
  1015. 'file' => 'includes/swftools.core.inc',
  1016. ),
  1017. // These are the SWF Tools CCK formatters
  1018. 'swftools_formatter_swftools' => array(
  1019. 'arguments' => array('element' => NULL, 'profile' => NULL),
  1020. 'function' => 'theme_swftools_formatter_swftools',
  1021. 'file' => 'includes/swftools.theme.inc',
  1022. ),
  1023. 'swftools_formatter_swftools_no_file' => array(
  1024. 'arguments' => array('element' => NULL),
  1025. 'function' => 'theme_swftools_formatter_swftools',
  1026. 'file' => 'includes/swftools.theme.inc',
  1027. ),
  1028. 'swftools_formatter_swftools_playlist' => array(
  1029. 'arguments' => array('element' => NULL, 'profile' => NULL),
  1030. 'function' => 'theme_swftools_formatter_playlist',
  1031. 'file' => 'includes/swftools.theme.inc',
  1032. ),
  1033. 'swftools_formatter_swftools_thumbnail' => array(
  1034. 'arguments' => array('element' => NULL, 'retrieve' => NULL),
  1035. 'function' => 'theme_swftools_formatter_thumbnail',
  1036. 'file' => 'includes/swftools.theme.inc',
  1037. ),
  1038. // This implements the swftools Form API element
  1039. 'swftools' => array(
  1040. 'arguments' => array('content' => NULL),
  1041. 'file' => 'includes/swftools.core.inc',
  1042. ),
  1043. // This implements the theme for basic pages served from the cache
  1044. 'swftools_page' => array(
  1045. 'template' => 'swftools-page',
  1046. 'arguments' => array('content' => NULL),
  1047. 'path' => drupal_get_path('module', 'swftools') . '/includes',
  1048. 'preprocess functions' => array('template_preprocess_page'),
  1049. ),
  1050. // This implements a generic accessible controls handler
  1051. 'swftools_accessible_controls' => array(
  1052. 'arguments' => array('player' => NULL, 'id' => NULL, 'actions' => NULL, 'visible' => NULL),
  1053. ),
  1054. // This defines the path to an empty image when no thumbnail is given
  1055. 'swftools_empty_image' => array(
  1056. 'arguments' => array('data' => NULL),
  1057. 'file' => 'includes/swftools.theme.inc',
  1058. ),
  1059. );
  1060. }
  1061. /**
  1062. * Implementation of hook_file_download().
  1063. *
  1064. * Allows SWF Tools to work with a private file system that might include files
  1065. * uploaded outside the control of an upload module, e.g. FTP of large video files.
  1066. *
  1067. * If the file is of a supported type, based on extension, then return a valid header.
  1068. * If any other module returns -1 for this file then access will be denied
  1069. * even if SWF Tools tries to allow it. See hook_file_download() for details.
  1070. */
  1071. function swftools_file_download($file) {
  1072. // If SWF Tools is allowed to grant access then check to see if access will be allowed
  1073. if (variable_get('swftools_grant_access_to_private_files', SWFTOOLS_PRIVATE_ACCESS_DENIED)) {
  1074. // Get extension of file in question
  1075. $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
  1076. // Get list of extensions that SWF Tools can grant access to
  1077. $extensions = variable_get('swftools_grant_access_extensions', SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS);
  1078. // Need access to the user object
  1079. global $user;
  1080. // Check if SWF Tools should grant access to this extension - skip the check for user #1
  1081. if ($user->uid != 1) {
  1082. $regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i';
  1083. if (!preg_match($regex, $file)) {
  1084. return;
  1085. }
  1086. }
  1087. // Build an array of types that SWF Tools can react to
  1088. $mime_types = _swftools_mime_types();
  1089. // If file is one of the above types, based on the extension, return headers
  1090. if (isset($mime_types[$extension])) {
  1091. return array(
  1092. 'Content-Type: '. $mime_types[$extension],
  1093. 'Content-Length: '. filesize(file_create_path($file)),
  1094. );
  1095. }
  1096. }
  1097. }
  1098. /**
  1099. * Implementation of hook_swftools_methods().
  1100. */
  1101. function swftools_swftools_methods() {
  1102. // Module implements swf embedding (action swf)
  1103. $methods['swf']['swf'] = array(
  1104. 'module' => 'swftools',
  1105. 'title' => t('Display the swf directly on the page'),
  1106. );
  1107. // Add on generic players (we have to call this hook manually as it isn't in a module)
  1108. $methods += swftools_genericplayers_swftools_methods();
  1109. // Return the methods that are native to SWF Tools
  1110. return $methods;
  1111. }
  1112. /**
  1113. * Helper function to set the size of the swf content in to $options['othervars']['height'] and ['width']
  1114. *
  1115. * @param array &$options
  1116. * Data array that is being assembled by SWF Tools.
  1117. *
  1118. * @return nothing
  1119. * Function operates by reference.
  1120. */
  1121. function swftools_set_size(&$options) {
  1122. // We use these defaults to filter arrays for their height and width, and assign a fallback value
  1123. $defaults = array(
  1124. 'height' => '100%',
  1125. 'width' => '100%',
  1126. );
  1127. // If height and width are already set then just return
  1128. if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
  1129. return;
  1130. }
  1131. // See if we can get height and width from flashvars
  1132. $try = array_intersect_key($options['flashvars'], $defaults);
  1133. $options['othervars'] += $try;
  1134. // See if we can get height and width from player
  1135. $try = array_intersect_key($options['resolved_methods']['player'], $defaults);
  1136. $options['othervars'] += $try;
  1137. // If we have a height and width now then return
  1138. if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
  1139. return;
  1140. }
  1141. // Try and get size from the file to be embedded, but preserve height or width if just one was set
  1142. $info = swftools_get_info($options['othervars']['filepath']);
  1143. // If sizes were retrieved then use them
  1144. if ($info) {
  1145. $try = array_intersect_key($info, $defaults);
  1146. $options['othervars'] += $try;
  1147. };
  1148. // And if all else fails, assign 100%
  1149. $options['othervars'] += $defaults;
  1150. }
  1151. /**
  1152. * Implementation of hook_field_formatter_info().
  1153. */
  1154. function swftools_field_formatter_info() {
  1155. return array(
  1156. 'swftools_no_file' => array('label' => t('SWF Tools - no download link'),
  1157. 'field types' => array('filefield', 'link', 'text'),
  1158. 'multiple values' => CONTENT_HANDLE_CORE,
  1159. ),
  1160. 'swftools_playlist' => array('label' => t('SWF Tools - playlist'),
  1161. 'field types' => array('filefield', 'link', 'text'),
  1162. 'multiple values' => CONTENT_HANDLE_MODULE,
  1163. ),
  1164. 'swftools' => array('label' => t('SWF Tools - with download link'),
  1165. 'field types' => array('filefield', 'link'),
  1166. 'multiple values' => CONTENT_HANDLE_CORE,
  1167. ),
  1168. 'swftools_thumbnail' => array('label' => t('SWF Tools - thumbnail'),
  1169. 'field types' => array('filefield', 'link', 'text'),
  1170. 'multiple values' => CONTENT_HANDLE_CORE,
  1171. ),
  1172. );
  1173. }
  1174. /**
  1175. * Creates a relative path url from a file path, using private or public file system.
  1176. *
  1177. * This is an SWF Tools version of file_create_url(). The only difference is that
  1178. * here we do not output absolute paths as we are only using these paths within the
  1179. * context of a page and therefore relative is fine.
  1180. *
  1181. * @param string $path
  1182. * Path to the file.
  1183. *
  1184. * @return string
  1185. * A string with a complete path, relative to the local file system.
  1186. */
  1187. function swftools_create_url($path) {
  1188. // Strip file_directory_path from $path. We only include relative paths in urls.
  1189. if (strpos($path, file_directory_path() .'/') === 0) {
  1190. $path = trim(substr($path, strlen(file_directory_path())), '\\/');
  1191. }
  1192. // Output a relative url, using public or private file transfer
  1193. switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
  1194. case FILE_DOWNLOADS_PUBLIC:
  1195. return base_path() . file_directory_path() . '/' . str_replace('\\', '/', $path);
  1196. case FILE_DOWNLOADS_PRIVATE:
  1197. return url('system/files/' . $path);
  1198. }
  1199. }
  1200. /**
  1201. * Determines the url for a file, and expands its filepath if necessary.
  1202. *
  1203. * This function is necessary because SWF Tools allows flexibility in how the site interprets
  1204. * filenames. If just a filename is provided then this might point to a file on the local system,
  1205. * or it might point to an external location if the remote media path is set. However, for things
  1206. * like auto-detection of sizes to work when the filename is local it must be expanded to include
  1207. * the file path.
  1208. *
  1209. * If $file is a full and valid absolute url then the function returns $file on both keys.
  1210. *
  1211. * If $file is full and valid url on the local system then the function returns $file on both keys.
  1212. *
  1213. * If $file is a path to a local file (sites/default/files/xxx) then src_path will return this,
  1214. * and src will return a full relative url.
  1215. *
  1216. * If $file is just a filename and remote media is active then src and src_path will both be set
  1217. * to the url for the external location.
  1218. *
  1219. * If $file is just a filename and remote media is not active then src_path will return the path
  1220. * to the local system (so xxx becomes sites/default/files/xxx) and src will return the full
  1221. * relative url.
  1222. *
  1223. * @param string $file
  1224. * A string containing a url or a path to a file.
  1225. *
  1226. * @return array
  1227. * An array with two keys
  1228. * - src: The url to the file (relative if on the local system)
  1229. * - src_path: The path to the file, expanded if necessary
  1230. */
  1231. function swftools_get_url_and_path($file) {
  1232. // src will contain a full, or relative, url that is used to render the file
  1233. // src_path will contain a partial path (without webroot), or the original file path
  1234. $ret = array(
  1235. 'fileurl' => '',
  1236. 'filepath' => $file,
  1237. );
  1238. // If already a valid absolute url simply return it
  1239. if (valid_url($file, TRUE)) {
  1240. $ret['fileurl'] = $file;
  1241. return $ret;
  1242. }
  1243. // If a valid url, and starts with /, then assume to be a local path relative to web root
  1244. // No security check is needed as the result of this is only output to the webpage
  1245. // We strip base_path from the file to create filepath that is valid for image_get_info later.
  1246. // FileField will create paths with spaces in - need to reverse that when testing for valid_url
  1247. $temp = str_replace(' ', '%20', $file);
  1248. // if (valid_url($file) && strpos($file, '/') === 0) {
  1249. if (valid_url($temp) && strpos($file, '/') === 0) {
  1250. return array(
  1251. 'fileurl' => $file,
  1252. 'filepath' => str_replace(base_path(), '', $file),
  1253. );
  1254. }
  1255. // If defintely in the local file system return a relative url to the file
  1256. if ($file == file_create_path($file)) {
  1257. // If media checking is active check to see if it actually exists
  1258. if (variable_get('swftools_check_media', TRUE)) {
  1259. // If the file doesn't exist, set an error message and return FALSE to indicate failure
  1260. if (!file_exists($file)) {
  1261. drupal_set_message(t('SWF Tools could not find %file.', array('%file' => $file)), 'error');
  1262. return FALSE;
  1263. }
  1264. }
  1265. // If we got here then return a relative url to the file
  1266. $ret['fileurl'] = swftools_create_url($file);
  1267. return $ret;
  1268. }
  1269. // Retrieve the media url setting
  1270. $media_url = trim(variable_get('swftools_media_url', ''));
  1271. // If a remote path is set build the appropriate url to the file
  1272. if ($media_url) {
  1273. $ret['fileurl'] = $media_url . '/' . $path;
  1274. return $ret;
  1275. }
  1276. // If we got here then expand to a local file path and call again
  1277. return swftools_get_url_and_path(file_create_path($file));
  1278. }
  1279. /**
  1280. * Returns a string defining a base path for flash to use.
  1281. */
  1282. function swftools_get_base() {
  1283. // Cache the result as we might get multiple calls
  1284. static $base = '';
  1285. // If $base is not already defined then set it
  1286. if (!$base) {
  1287. // Retrieve swftools_media_url to see if a remote path has been set
  1288. $base = trim(variable_get('swftools_media_url', ''));
  1289. // If $base is still empty then use local path to file directory
  1290. if (!$base) {
  1291. $base = base_path() . file_directory_path() . '/';
  1292. }
  1293. }
  1294. // Return the base path
  1295. return $base;
  1296. }
  1297. /**
  1298. * Flatten an array which has sub-arrays in to a single keyed array.
  1299. *
  1300. * If keys in the sub-array are the same as ones seen previously the early key will be over-written.
  1301. *
  1302. * @param array $array
  1303. * Array to be processed.
  1304. *
  1305. * @return nothing
  1306. * Manipulate the array directly.
  1307. */
  1308. function swftools_array_flatten(&$array) {
  1309. // Only process if we passed an array
  1310. if (is_array($array)) {
  1311. // Iterate over the array
  1312. foreach ($array as $key => $value) {
  1313. // If the value is in itself an array then flatten that too
  1314. if (is_array($value)) {
  1315. // Unset this key as this contains an array
  1316. unset($array[$key]);
  1317. // Flatten the sub-array
  1318. swftools_array_flatten($value);
  1319. // Merge the flattened sub-array in to the rest of the array
  1320. $array = array_merge($array, $value);
  1321. }
  1322. }
  1323. }
  1324. }
  1325. /**
  1326. * Returns a variable from the relevant profile, or the global settings, or the default values.
  1327. *
  1328. * This is a custom handler to take care of the SWF Tools profile mechanism.
  1329. * If no profile name is given then it simply returns the requested variable,
  1330. * or the default if the variable is not set.
  1331. *
  1332. * If a profile name is given then it will first try to retrive the profiled variable.
  1333. * If that fails it will try to return the global setting, and if that fails then it
  1334. * will return the default. In this way we cascade through the "most relevant" setting.
  1335. *
  1336. * @param string $name
  1337. * The name of the variable to return.
  1338. * @param mixed $default
  1339. * The default value to use if this variable has never been set.
  1340. * @param string $profile
  1341. * (optional) The name of the profile to use.
  1342. *
  1343. * @return mixed
  1344. * The value of the variable.
  1345. */
  1346. function swftools_variable_get($name, $default, $profile = '') {
  1347. if ($profile && ($ret = variable_get('swftools_' . $profile . '_' . $name, SWFTOOLS_UNDEFINED)) != SWFTOOLS_UNDEFINED) {
  1348. return $ret;
  1349. }
  1350. return variable_get($name, $default);
  1351. }
  1352. /**
  1353. * Serves an xml playlist from the {cache_swftools} table.
  1354. *
  1355. * SWF Tools no longer generates a physical file for the playlist. Instead it
  1356. * places an entry in its internal cache table and then serves the file from
  1357. * there. Pages request the files by accessing swftools/playlist/nnn, where
  1358. * nnn is the cid of the content.
  1359. *
  1360. * @param string $playlist
  1361. * The name of the playlist being requested.
  1362. *
  1363. * @return mixed
  1364. * Serve the xml file, or issue drupal_not_found() if it doesn't exist.
  1365. */
  1366. function swftools_get_xml($playlist) {
  1367. if ((!$data = cache_get($playlist, 'cache_swftools')) || !$data->data['xml']) {
  1368. print drupal_not_found();
  1369. }
  1370. else {
  1371. drupal_set_header('Content-Type: text/xml; charset=utf-8');
  1372. print $data->data['xml'];
  1373. }
  1374. }
  1375. /**
  1376. * Serves just the swf content from the cache via the path swftools/page/nnnn
  1377. *
  1378. * This feature is experimental - the only access control at the moment is whether
  1379. * the user is generally allowed to view content. Complex permissions will come
  1380. * later.
  1381. *
  1382. * @param string $cid
  1383. * The cid of the item to retrieve.
  1384. *
  1385. * @return nothing
  1386. * Output an html page, including headers
  1387. */
  1388. function swftools_get_html($cid) {
  1389. // Access global user object
  1390. global $user;
  1391. // User 1 can always access cached content directly, others only if direct serving is enabled
  1392. if (!($user->uid == 1) && !variable_get('swftools_grant_access_to_cache', 0)) {
  1393. print drupal_access_denied();
  1394. }
  1395. elseif (!$content = cache_get($cid, 'cache_swftools')) {
  1396. print drupal_not_found();
  1397. }
  1398. else {
  1399. print theme('swftools_page', $content->data['html']);
  1400. }
  1401. }
  1402. /**
  1403. * Creates a cid for the call to swf() and returns its data from the cache when available.
  1404. *
  1405. * To make our cid we create an array from $file and $options. Then we serialize it, and then
  1406. * we run it through md5. This generates a unique cid for that piece of content.
  1407. *
  1408. * Once the cid is created it is attached to $options['othervars']['cid'] so that
  1409. * subsequent functions don't have to rehash the data to generate it again.
  1410. *
  1411. * Within {cache_swftools} we store each item as an associative array.
  1412. * - html: the actual mark up to place the Flash on the page
  1413. * - xml: associated xml (for xml based playlists)
  1414. *
  1415. * @param string $file
  1416. * The $file parameter from the call to swf().
  1417. * @param array $options
  1418. * The $options parameter from the call to swf().
  1419. *
  1420. * @return mixed
  1421. * The cached content as a array, or FALSE if it is isn't available.
  1422. */
  1423. function swftools_get_from_cache($file, &$options) {
  1424. // Construct a cid for this piece of content
  1425. $cid = md5(serialize(array($file, $options)));
  1426. // Set the cid on othervars ready to store this item if we have to render it
  1427. $options['othervars']['cid'] = $cid;
  1428. // If this is in the cache then return it
  1429. if ($ret = cache_get($cid, 'cache_swftools')) {
  1430. return $ret;
  1431. }
  1432. // Indicate that we don't have cached data
  1433. return SWFTOOLS_NOT_CACHED;
  1434. }
  1435. /**
  1436. * Implementation of hook_flush_caches().
  1437. */
  1438. function swftools_flush_caches() {
  1439. // Flush {cache_swftools}
  1440. return array('cache_swftools');
  1441. }
  1442. /**
  1443. * Returns the default handlers, or customised handlers, for each action.
  1444. */
  1445. function swftools_get_players($profile) {
  1446. // These are the standard defaults (key is action, value is handler)
  1447. $defaults = array(
  1448. 'video' => 'generic_flv',
  1449. 'audio' => 'generic_mp3',
  1450. 'swf' => 'swf',
  1451. );
  1452. // Retrieve settings from the database if available
  1453. $settings = swftools_variable_get('swftools_handlers', $defaults, $profile);
  1454. // Return result
  1455. return $settings;
  1456. }
  1457. /**
  1458. * Merges two multi-dimensional arrays.
  1459. *
  1460. * This function is used by players that filter their settings to strip out
  1461. * blanks or defaults. For the admin page we need a full set of values to prevent
  1462. * errors. Since the arrays might be multi-dimensional we cannot use a regular
  1463. * array_merge(). The values in the first array will be over-written by values in
  1464. * the second, if they exist.
  1465. *
  1466. * @param array $array1
  1467. * The first array to merge.
  1468. * @param array $array2
  1469. * The second array to merge.
  1470. *
  1471. * @return array
  1472. * The result of the merge.
  1473. */
  1474. function swftools_array_merge($array1, $array2) {
  1475. // Iterate over $array 2 (this is normally the smaller of the two)
  1476. foreach ($array2 as $key => $value) {
  1477. // If this key is present in $array1 then work out what to do
  1478. if (isset($array1[$key])) {
  1479. // If both keys hold arrays, combine them
  1480. if (is_array($value) && is_array($array1[$key])) {
  1481. $array1[$key] = swftools_array_merge($array1[$key], $value);
  1482. }
  1483. else {
  1484. // Replace value in $array1 with that from $array2
  1485. $array1[$key] = $value;
  1486. }
  1487. }
  1488. else {
  1489. // Simply put this value in $array1 if it isn't already in $array1
  1490. $array1[$key] = $value;
  1491. }
  1492. }
  1493. // Return the result
  1494. return $array1;
  1495. }
  1496. /**
  1497. * Retrieves the list of actions, and their descriptions, that modules are presenting to SWF Tools.
  1498. *
  1499. * @param bool $reset
  1500. * When TRUE will reset the cache.
  1501. *
  1502. * @return array
  1503. * An array of actions.
  1504. */
  1505. function swftools_get_actions($reset = FALSE) {
  1506. // Cache actions
  1507. static $actions;
  1508. // If user has requested the cache to be reset then reset it
  1509. if ($reset || !isset($actions)) {
  1510. if (!$reset && ($cached = cache_get('actions', 'cache_swftools'))) {
  1511. $actions = $cached->data;
  1512. }
  1513. else {
  1514. // Build a list of standard actions that SWF Tools knows about from its other modules
  1515. $default_actions = array(
  1516. 'swf' => array(
  1517. '#description' => 'a single swf movie',
  1518. '#type' => 'swf movies',
  1519. '#weight' => -8,
  1520. ),
  1521. 'video' => array(
  1522. '#description' => 'a single video',
  1523. '#type' => 'videos',
  1524. '#weight' => -7,
  1525. ),
  1526. 'video_list' => array(
  1527. '#description' => 'a series of videos',
  1528. '#weight' => -6,
  1529. ),
  1530. 'audio' => array(
  1531. '#description' => 'a single audio file',
  1532. '#type' => 'audio',
  1533. '#weight' => -5,
  1534. ),
  1535. 'audio_list' => array(
  1536. '#description' => 'a series of audio files',
  1537. '#weight' => -4,
  1538. ),
  1539. 'image' => array(
  1540. '#description' => 'a single image',
  1541. '#type' => 'images',
  1542. '#weight' => -3,
  1543. ),
  1544. 'image_list' => array(
  1545. '#description' => 'a series of images',
  1546. '#weight' => -2,
  1547. ),
  1548. 'media_list' => array(
  1549. '#description' => 'a series of mixed media files',
  1550. '#weight' => -1,
  1551. ),
  1552. );
  1553. // Plan ahead - give other modules the chance to declare an action
  1554. $actions = array();
  1555. foreach (module_implements('swftools_actions') as $module) {
  1556. $function = $module .'_swftools_actions';
  1557. $result = $function();
  1558. if (isset($result) && is_array($result)) {
  1559. $actions = array_merge($actions, $result);
  1560. }
  1561. }
  1562. // Merge additional or new values over the defaults (allows defaults to be renamed)
  1563. $actions = array_merge($default_actions, $actions);
  1564. // Sort the list
  1565. uasort($actions, 'element_sort');
  1566. // Set the cache
  1567. cache_set('actions', $actions, 'cache_swftools');
  1568. }
  1569. }
  1570. // Return the list of available actions
  1571. return $actions;
  1572. }
  1573. /**
  1574. * Determines the action to be taken, based on the extension of a filename.
  1575. *
  1576. * @param string $extension
  1577. * The file being queried.
  1578. *
  1579. * @return string
  1580. * An SWF Tools action if one is associated with the extension, or 'media_list' if we don't know.
  1581. */
  1582. function swftools_get_action($file) {
  1583. // Get the array of actions, keyed on extension
  1584. $actions = _swftools_actions();
  1585. // Get the extension for this file
  1586. $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
  1587. // If we know the handler for this then use it, otherwise return 'media_list'
  1588. return isset($actions[$extension]) ? $actions[$extension] : 'media_list';
  1589. }
  1590. /**
  1591. * Returns an array of actions, keyed by file extension.
  1592. */
  1593. function _swftools_actions() {
  1594. // Cache this as there may be multiple calls
  1595. static $actions;
  1596. // Do we need to fetch the array of actions?
  1597. if (!$actions) {
  1598. // Defaults to use if no settings have been stored
  1599. $defaults = array(
  1600. 'swf' => 'swf',
  1601. 'flv' => 'video',
  1602. 'f4v' => 'video',
  1603. 'mp3' => 'audio',
  1604. 'jpg' => 'image',
  1605. 'jpeg' => 'image',
  1606. 'jpe' => 'image',
  1607. 'png' => 'image',
  1608. 'gif' => 'image',
  1609. );
  1610. // Use settings from configuration page, or defaults
  1611. $actions = variable_get('swftools_actions', $defaults);
  1612. }
  1613. // Return the result
  1614. return $actions;
  1615. }
  1616. /**
  1617. * Returns an array of mime types, keyed by file extension.
  1618. */
  1619. function _swftools_mime_types() {
  1620. $defaults = array(
  1621. 'swf' => 'application/x-shockwave-flash',
  1622. 'flv' => 'video/x-flv',
  1623. 'mp3' => 'audio/mpeg',
  1624. 'jpg' => 'image/jpeg',
  1625. 'jpeg' => 'image/jpeg',
  1626. 'jpe' => 'image/jpeg',
  1627. 'png' => 'image/png',
  1628. 'gif' => 'image/gif',
  1629. );
  1630. // Use settings from configuration page, or defaults
  1631. $mime_types = variable_get('swftools_mime_types', $defaults);
  1632. // Return the result
  1633. return $mime_types;
  1634. }
  1635. /**
  1636. * Implementation of hook_form_FORM_ID_alter().
  1637. *
  1638. * Alters the system_performance_settings form so the SWF Tools cache can be managed along with other caches.
  1639. */
  1640. function swftools_form_system_performance_settings_alter(&$form, &$form_state) {
  1641. $form['swftools_cache'] = array(
  1642. '#type' => 'fieldset',
  1643. '#title' => t('SWF Tools cache'),
  1644. '#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.'),
  1645. );
  1646. $form['swftools_cache']['swftools_cache'] = array(
  1647. '#type' => 'radios',
  1648. '#title' => t('SWF Tools cache'),
  1649. '#default_value' => variable_get('swftools_cache', CACHE_NORMAL),
  1650. '#options' => array(
  1651. CACHE_DISABLED => t('Disabled'),
  1652. CACHE_NORMAL => t('Enabled (recommended)'),
  1653. ),
  1654. '#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')),
  1655. );
  1656. // We want to slot our new section above 'clear cached data' but we can't use weights
  1657. // We use a trick and unset and reset the elements we want lower
  1658. $temp = $form['clear_cache'];
  1659. unset($form['clear_cache']);
  1660. $form['clear_cache'] = $temp;
  1661. $temp = $form['buttons'];
  1662. unset($form['buttons']);
  1663. $form['buttons'] = $temp;
  1664. }
  1665. /**
  1666. * Implementation of hook_elements().
  1667. */
  1668. function swftools_elements() {
  1669. $type['swftools'] = array(
  1670. '#params' => array(),
  1671. '#flashvars' => array(),
  1672. '#othervars' => array(),
  1673. '#methods' => array(),
  1674. '#value' => '',
  1675. );
  1676. // Return the type
  1677. return $type;
  1678. }
  1679. /**
  1680. * Changes old player names to the new ones so existing content doesn't break.
  1681. *
  1682. * @param string $name
  1683. * The currently assigned player name.
  1684. *
  1685. * @return string
  1686. * The corrected player name (which will be unchanged if it is already ok).
  1687. */
  1688. function swftools_fix_old_player_names($name) {
  1689. // This is the array to map old names to new names
  1690. $map = array(
  1691. 'flowplayer_mediaplayer' => 'flowplayer',
  1692. 'flowplayer3_mediaplayer' => 'flowplayer3',
  1693. 'wijering_imagerotator' => 'imagerotator',
  1694. 'wijering4_mediaplayer' => 'jwplayer4',
  1695. );
  1696. // Attach the supplied action name as both key and value
  1697. $map += array(
  1698. $name => $name,
  1699. );
  1700. // Return the mapped result
  1701. return $map[$name];
  1702. }
  1703. /**
  1704. * Changes old action names to the new ones so existing content doesn't break.
  1705. *
  1706. * @param string $name
  1707. * The currently assigned action name.
  1708. *
  1709. * @return string
  1710. * The corrected action name (which will be unchanged if it is already ok).
  1711. */
  1712. function swftools_fix_old_action_names($name) {
  1713. // This is the array to map old names to new names
  1714. $map = array(
  1715. 'swftools_swf_display_direct' => 'swf',
  1716. 'swftools_flv_display' => 'video',
  1717. 'swftools_flv_display_list' => 'video_list',
  1718. 'swftools_mp3_display' => 'audio',
  1719. 'swftools_mp3_display_list' => 'audio_list',
  1720. 'swftools_image_display' => 'image',
  1721. 'swftools_image_display_list' => 'image_list',
  1722. 'swftools_media_display_list' => 'media_list',
  1723. );
  1724. // Attach the supplied action name as both key and value
  1725. $map += array(
  1726. $name => $name,
  1727. );
  1728. // Return the mapped result
  1729. return $map[$name];
  1730. }
  1731. /**
  1732. * Implementation of hook_views_api().
  1733. */
  1734. function swftools_views_api() {
  1735. return array(
  1736. 'api' => 2,
  1737. 'path' => drupal_get_path('module', 'swftools') . '/views',
  1738. );
  1739. }
  1740. /**
  1741. * Outputs a message to the screen and/or the watchdog, according to the configuration settings.
  1742. *
  1743. * Parameters are as watchdog().
  1744. *
  1745. * @see watchdog()
  1746. */
  1747. function swftools_set_error($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
  1748. // Find out where this message should go
  1749. $destination = variable_get('swftools_error_output', SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN);
  1750. // drupal_set_message uses error, warning and status, not severity levels
  1751. $status = array(
  1752. WATCHDOG_EMERG => 'error',
  1753. WATCHDOG_ALERT => 'error',
  1754. WATCHDOG_CRITICAL => 'error',
  1755. WATCHDOG_ERROR => 'error',
  1756. WATCHDOG_WARNING => 'warning',
  1757. );
  1758. $status += array(
  1759. $severity => 'status',
  1760. );
  1761. // Write to screen?
  1762. if ($destination & SWFTOOLS_ERROR_SCREEN) {
  1763. drupal_set_message(t($message, $variables), $status[$severity]);
  1764. }
  1765. // Write to watchdog?
  1766. if ($destination & SWFTOOLS_ERROR_WATCHDOG) {
  1767. watchdog($type, $message, $variables, $severity, $link);
  1768. }
  1769. }
  1770. /**
  1771. * Replaces the html_alt string with an image tag when rendering an image playlist.
  1772. *
  1773. * This is designed so that if the Flash embed fails the user will see the
  1774. * first image from the image playlist, rather than just an empty message.
  1775. *
  1776. * TODO: Could extend this to substitute thumbnails on audio? Or is that too much!
  1777. *
  1778. * @param array $options
  1779. * SWF Tools data array.
  1780. *
  1781. * @return nothing
  1782. * Modifies the array directly.
  1783. */
  1784. function swftools_image_html_alt(&$options) {
  1785. // Make sure there is a playlist (not using Flickr etc)
  1786. if ($file = $options['othervars']['playlist_data']['playlist']) {
  1787. // Get the first array element - use array_shift on a copy of the playlist in case there are named keys
  1788. $file = array_shift($file);
  1789. // Get height and width data for the first image
  1790. $info = swftools_get_info($file['filepath']);
  1791. // Initialise an empty array
  1792. $attributes = array();
  1793. // Try to make sure the image height and width don't exceed the player height and width to keep the layout as we expect
  1794. if ($info) {
  1795. $attributes['height'] = ($info['height'] > $options['othervars']['height']) ? $options['othervars']['height'] : $info['height'];
  1796. $attributes['width'] = ($info['width'] > $options['othervars']['width']) ? $options['othervars']['width'] : $info['width'];
  1797. }
  1798. // Replace html_alt with an image, setting alt text as both alt and title (so when user hovers they see a sensible message)
  1799. $alt = strip_tags(theme('swftools_html_alt', $options));
  1800. $options['othervars']['html_alt'] = theme('image', $file['filepath'], $alt, $alt, $attributes, FALSE);
  1801. }
  1802. }
  1803. /**
  1804. * Builds a list of accessible controls for the specified player.
  1805. *
  1806. * SWF Tools accessibility scripts use classes of the form
  1807. * !player-accessible-!action-!id.
  1808. * See theme_swftools_wijering4_accessible() for an example of how
  1809. * to implement accessible controls.
  1810. *
  1811. * @param string $player
  1812. * The player name to be made accessible (e.g. jwplayer4).
  1813. * @param string $id
  1814. * The id of the player these controls relate to.
  1815. * @param array $actions
  1816. * The list of actions as an associative array, where the key is the action name,
  1817. * and the value is the label. The calling function should translate the text first.
  1818. * @param int $visible
  1819. * Whether the controls should be visible. Options are one the following constants:
  1820. * - SWFTOOLS_ACCESSIBLE_DISABLED
  1821. * - SWFTOOLS_ACCESSIBLE_HIDDEN
  1822. * - SWFTOOLS_ACCESSIBLE_VISIBLE
  1823. *
  1824. * @return string
  1825. * HTML markup to generate a list.
  1826. *
  1827. * @ingroup swftools
  1828. * @ingroup themeable
  1829. */
  1830. function theme_swftools_accessible_controls($player, $id, $actions, $visible) {
  1831. foreach ($actions as $action => $label) {
  1832. $list[] = l($label, '', array('fragment' => ' ', 'external' => TRUE, 'attributes' => array('class' => t('!player-accessible-!action-!id', array('!player' => $player, '!action' => $action, '!id' => $id)))));
  1833. }
  1834. return theme_item_list($list, '', 'ul', array('class' => $visible == SWFTOOLS_ACCESSIBLE_VISIBLE ? '' : 'swftools-accessible-hidden'));
  1835. }
  1836. /**
  1837. * Modifies a file path to include the appropriate imagecache preset.
  1838. *
  1839. * @param string $preset
  1840. * The imagecache preset to be applied.
  1841. * @param string $path
  1842. * The existing path.
  1843. *
  1844. * @return string
  1845. * The modified path, or an unaltered path if not on the local file system.
  1846. */
  1847. function swftools_imagecache_create_path($preset, $path) {
  1848. if (module_exists('imagecache')) {
  1849. $path = str_replace(file_directory_path(), file_directory_path() . '/imagecache/' . $preset, $path);
  1850. }
  1851. return $path;
  1852. }