jplayer_protect.module in jPlayer 7.2
Same filename and directory in other branches
Provides basic content protection for media files accessed with jPlayer.
File
jplayer_protect/jplayer_protect.moduleView source
<?php
/**
* @file
* Provides basic content protection for media files accessed with jPlayer.
*/
function jplayer_protect_menu() {
$items = array();
$items['admin/reports/jplayer-protect'] = array(
'title' => 'jPlayer content protection statistics',
'page callback' => 'jplayer_protection_statistics',
'access arguments' => array(
'access site reports',
),
'description' => 'View statistics related to content protection for jPlayer.',
'file' => 'jplayer_protect.admin.inc',
'file path' => drupal_get_path('module', 'jplayer_protect'),
);
$items['jplayer_protect/authorize'] = array(
'title' => 'jPlayer content authorization',
'page callback' => 'jplayer_protect_authorize',
'delivery callback' => 'ajax_deliver',
'access arguments' => array(
'access content',
),
'description' => 'jPlayer callback to authorize a sound file to be accessed.',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Menu callback to authorize access to a file.
*/
function jplayer_protect_authorize($filepath, $timestamp) {
$filepath = base64_decode($filepath);
$timestamp = (int) base64_decode($timestamp);
if (!isset($_SESSION['jplayer_protect'])) {
$_SESSION['jplayer_protect'] = array();
}
if ($timestamp < REQUEST_TIME + variable_get('jplayer_access_time', 30)) {
$_SESSION['jplayer_protect'][$filepath] = $timestamp;
}
return drupal_json_encode(REQUEST_TIME + variable_get('jplayer_access_time', 30));
}
/**
* Implements hook_cron().
*/
function jplayer_protect_cron() {
// Delete records older than a week.
// TODO Needs dbtng.
db_query("DELETE FROM {jplayer_protect_denied} WHERE timestamp < :time", array(
':time' => time() - 604800,
));
}
/**
* Implements hook_file_download().
*/
function jplayer_protect_file_download($uri) {
if (!variable_get('jplayer_protect', FALSE)) {
return NULL;
}
// We need to determine if we are responsible for this file.
// TODO dbtng.
// TODO use EntityFieldQuery.
$result = db_query("SELECT fid FROM {file_managed} WHERE uri = :uri", array(
':uri' => $uri,
));
// If the file is not found in the database, we're not responsible for it.
if (!($fid = $result
->fetchField())) {
return NULL;
}
// We have a valid fid, go ahead and load the file.
$file = file_load($fid);
// Find out if any file field contains this file, and if so, which field
// and node it belongs to. Required for later access checking.
$instances = array();
$entities = array();
foreach (field_info_fields() as $field_name => $field) {
if ($field['type'] == 'file') {
$query = new EntityFieldQuery();
$query
->fieldCondition($field_name, 'fid', $file->fid, '=');
$entities = $query
->execute();
if (empty($entities)) {
continue;
}
foreach ($entities as $entity_type => $entity_list) {
foreach ($entity_list as $entity) {
$bundle_name = $entity->type;
$instances[$field_name] = field_info_instance($entity_type, $field_name, $bundle_name);
}
}
}
}
// If any of the displays for this field are for jPlayer, then we need to
// protect the file.
$display_found = FALSE;
foreach ($instances as $field_name => $instance) {
foreach ($instance['display'] as $display_mode => $display) {
// Neither the teaser or the full formatter for this field is a jPlayer
// display.
if ($display['type'] == 'jplayer_player') {
$display_found = TRUE;
break;
}
}
}
if (!$display_found) {
return NULL;
}
$access_key = file_create_url($uri);
$filepath = str_replace($GLOBALS['base_url'], '', $access_key);
if (isset($_SESSION['jplayer_protect'][$access_key])) {
$started = (int) $_SESSION['jplayer_protect'][$access_key];
}
else {
// We need to figure out how the browser would have URL-encoded the file
// name. If mod_rewrite is modifying the URL, it will decode URL-encoded
// characters, so we need to check both.
$encoded = str_replace($file->filename, rawurlencode($file->filename), $filepath);
// TODO replace this with the path to the files directory?
$encoded = str_replace('sites/default/files', 'system/files', $encoded);
// For some reason ampersands are encoded twice by the browser.
$encoded = str_replace("%26", "%2526", $encoded);
$encoded_access_key = $GLOBALS['base_url'] . '/' . $encoded;
if (isset($_SESSION['jplayer_protect'][$encoded_access_key])) {
$access_key = $encoded_access_key;
$started = (int) $_SESSION['jplayer_protect'][$access_key];
}
}
// Now we know that content protection is enabled, at least one display for
// the field uses jPlayer, and we know when the player last started to access
// the file.
if (isset($started) && $started) {
if (time() <= $started + variable_get('jplayer_access_time', 30)) {
// Allow access, and immediately expire access to the file. Some browsers
// (such as Chrome) send multiple HTTP requests for an <audio> element,
// so if the RANGE header is set we continue to allow access. Also,
// AppleCoreMedia in OS X 10.7 makes multiple requests in an attempt to
// fetch metadata about the audio. So, we ignore those requests until the
// agent indicates that the connection can be closed.
if (!isset($_SERVER['HTTP_RANGE']) && !(strpos($_SERVER['HTTP_USER_AGENT'], 'AppleCoreMedia') !== FALSE && strpos($_SERVER['HTTP_CONNECTION'], "keep-alive") !== FALSE)) {
unset($_SESSION['jplayer_protect'][$access_key]);
}
return NULL;
}
}
// Otherwise, deny access as the last played time is too far in the past.
$denied = new stdClass();
$denied->uid = $GLOBALS['user']->uid;
$denied->fid = $file->fid;
$denied->hostname = ip_address();
$denied->timestamp = REQUEST_TIME;
drupal_write_record('jplayer_protect_denied', $denied);
return -1;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function jplayer_protect_form_jplayer_settings_form_alter(&$form, &$form_state, $form_id) {
module_load_include('inc', 'jplayer_protect', 'jplayer_protect.admin');
jplayer_protect_settings_form($form, $form_state);
}
/**
* Implements hook_jplayer_add_js().
*/
function jplayer_protect_jplayer_add_js() {
if (!variable_get('jplayer_protect', FALSE)) {
return;
}
$settings = array(
'jPlayer' => array(
'protect' => variable_get('jplayer_protect', FALSE),
),
);
drupal_add_js($settings, array(
'type' => 'setting',
));
return array(
'jplayer_protect' => array(
'#attached' => array(
'js' => array(
drupal_get_path('module', 'jplayer_protect') . '/jplayer-protect.js' => array(
'type' => 'file',
'scope' => 'footer',
'group' => JS_DEFAULT,
),
),
),
),
);
}
Functions
Name | Description |
---|---|
jplayer_protect_authorize | Menu callback to authorize access to a file. |
jplayer_protect_cron | Implements hook_cron(). |
jplayer_protect_file_download | Implements hook_file_download(). |
jplayer_protect_form_jplayer_settings_form_alter | Implements hook_form_FORM_ID_alter(). |
jplayer_protect_jplayer_add_js | Implements hook_jplayer_add_js(). |
jplayer_protect_menu | @file Provides basic content protection for media files accessed with jPlayer. |