download_count.module in Download Count 7.2
Same filename and directory in other branches
Tracks file downloads for files stored in the drupal files table using the private files setting or custom private filefield.
File
download_count.moduleView source
<?php
/**
* @file
* Tracks file downloads for files stored in the drupal files table using the private files setting or custom private filefield.
*/
/**
* Implements hook_help().
*/
function download_count_help($path, $arg) {
switch ($path) {
case 'admin/help#download_count':
return '<p>' . t("Tracks file downloads for files stored in the drupal files table. Requires either the 'private' download method setting or the method for combined public and private files described at <a href=@link>http://drupal.org/node/189239</a>. Also logs a message to the watchdog table.", array(
'@link' => url('http://drupal.org/node/189239'),
)) . '</p>';
}
}
/**
* Implements hook_permission().
*/
function download_count_permission() {
$perms = array(
'view all download counts' => array(
'title' => t('view all download counts'),
'description' => t('TODO Add a description for \'view all download counts\''),
),
'view own download counts' => array(
'title' => t('view own download counts'),
'description' => t('TODO Add a description for \'view own download counts\''),
),
);
return $perms;
}
/**
* Implements hook_menu().
*/
function download_count_menu() {
$items = array();
$items['admin/config/download_count'] = array(
'title' => 'Download count settings',
'description' => 'Tracks file downloads for files stored in the drupal files table.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'download_count_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'includes/download_count.admin.inc',
);
$items['download_count/%download_count_entry/reset'] = array(
'title' => 'Download Count Reset',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'download_count_reset_form',
1,
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_CALLBACK,
'file' => 'includes/download_count.pages.inc',
);
$items['download_count'] = array(
'title' => 'Download Count',
'page callback' => 'download_count_view_page',
'page arguments' => array(
'download_count',
),
'access arguments' => array(
'view all download counts',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'includes/download_count.pages.inc',
);
$items['my_download_count'] = array(
'title' => 'My Download Count',
'page callback' => 'download_count_view_page',
'page arguments' => array(
'my_download_count',
),
'access arguments' => array(
'view own download counts',
),
'type' => MENU_NORMAL_ITEM,
'file' => '/includes/download_count.pages.inc',
);
return $items;
}
/**
* Menu wildcard loader.
*/
function download_count_entry_load($dcid) {
return $dcid == 'all' ? $dcid : db_fetch_array(db_query('SELECT dc.dcid, dc.fid, dc.nid, f.filename FROM {download_count} dc JOIN {files} f ON dc.fid = f.fid WHERE dcid = :dcid', array(
':dcid' => $dcid,
)));
}
/**
* Implements hook_node_view().
*/
function download_count_node_view($node, $view_mode = 'full') {
if (isset($node->files) && count($node->files) && user_access('view uploaded files') && !$teaser) {
global $user;
if (user_access('view own download counts') && $user->uid != 1) {
$result = db_query("SELECT dc.fid, f.filename, COUNT(dc.dcid) AS count, MAX(dc.timestamp) AS last FROM {download_count} dc JOIN {files} f ON dc.fid = f.fid WHERE dc.nid = :dc.nid AND dc.uid = :dc.uid GROUP BY f.filename", array(
':dc.nid' => $node->nid,
':dc.uid' => $user->uid,
));
}
elseif (user_access('view all download counts')) {
$result = db_query("SELECT dc.fid, f.filename, COUNT(dc.dcid) AS count, MAX(dc.timestamp) AS last FROM {download_count} dc JOIN {files} f ON dc.fid = f.fid WHERE dc.nid = :dc.nid GROUP BY f.filename", array(
':dc.nid' => $node->nid,
));
}
while ($download = db_fetch_object($result)) {
$downloads[$download->filename]['count'] = $download->count;
$downloads[$download->filename]['last'] = $download->last;
$node->files[$download->fid]->downloads = $download->count;
}
if (isset($downloads)) {
$node->content['files']['#value'] = theme('download_count_upload_attachments', array(
'files' => $node->files,
'downloads' => $downloads,
));
}
}
}
/**
* Implements hook_nodeapi().
*/
function download_count_nodeapi_OLD(&$node, $op, $teaser) {
// TODO Remaining code in this function needs to be moved to the appropriate new hook function.
$result = array();
}
/**
* Implements hook_theme().
*/
function download_count_theme() {
return array(
'download_count_upload_attachments' => array(
'variables' => array(
'files' => NULL,
'downloads' => NULL,
),
'file' => 'includes/download_count.theme.inc',
),
'download_count_formatter_download_count' => array(
'render element' => 'element',
'file' => 'includes/download_count.theme.inc',
),
);
}
/**
* @todo Please document this function.
* @see http://drupal.org/node/1354
*/
function download_count_field_formatter_info() {
return array(
'download_count' => array(
'label' => t('Generic files with download count'),
'field types' => array(
'filefield',
),
'multiple values' => CONTENT_HANDLE_CORE,
'description' => t('Displays all kinds of files with an icon and a linked file description with download count information.'),
),
);
}
/**
* Implements hook_view_api().
*/
function download_count_views_api() {
return array(
'api' => 2.0,
'path' => drupal_get_path('module', 'download_count') . '/includes',
);
}
/**
* Implements hook_file_download().
*/
function download_count_file_download($filename) {
global $user;
$extensions = explode(' ', strtolower(trim(variable_get('download_count_excluded_file_extensions', 'jpg jpeg gif png'))));
if (count($extensions)) {
$pathinfo = pathinfo($filename);
if (in_array(strtolower($pathinfo['extension']), $extensions)) {
return;
}
}
$filepath = file_create_path($filename);
// NULL: not known
// FALSE: not accessible
// TRUE: accessible
$accessible_file = NULL;
// check if the file is known by Upload
$accessible_file = _download_count_is_accessible_by_upload($filepath);
if ($accessible_file === NULL) {
// check if the file is known by CCK FileField
$accessible_file = _download_count_is_accessible_by_filefield($filepath);
}
if ($accessible_file === NULL) {
// not known by any hooks, so we don't care about this file
return;
}
// inaccessible file
if ($accessible_file === FALSE) {
watchdog('download_count', 'Failed to download %file', array(
'%file' => $filename,
), WATCHDOG_ERROR);
return;
}
// accessible file
if ($fileinfo = _download_count_get_file_by_upload($filepath)) {
// core upload file
$fid = $fileinfo->fid;
$nid = $fileinfo->nid;
$vid = $fileinfo->vid;
}
elseif ($fileinfo = _download_count_get_nodes_by_filefield($filepath)) {
//cck filefield
$fid = db_query("SELECT fid FROM {files} WHERE filepath = :filepath", array(
':filepath' => $filepath,
))
->fetchField();
$node = array_pop($fileinfo);
$nid = $node->nid;
$vid = $node->vid;
}
// TODO Please review the conversion of this statement to the D7 database API syntax.
/* db_query("INSERT INTO {download_count} (fid, nid, uid, vid, ip_address, referrer, timestamp) VALUES (%d, %d, %d, %d, '%s', '%s', %d)", $fid, $nid, $user->uid, $vid, ip_address(), isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : NULL, REQUEST_TIME) */
$id = db_insert('download_count')
->fields(array(
'fid' => $fid,
'nid' => $nid,
'uid' => $user->uid,
'vid' => $vid,
'ip_address' => ip_address(),
'referrer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : NULL,
'timestamp' => REQUEST_TIME,
))
->execute();
watchdog('download_count', '%file was downloaded', array(
'%file' => $filename,
), WATCHDOG_NOTICE);
}
/**
* Implements hook_block_info().
*/
function download_count_block_info() {
$blocks['files']['info'] = t('Top Downloaded Files');
$blocks['downloaders']['info'] = t('Top Downloaders');
$blocks['users']['info'] = t('Top Downloaded Users');
$blocks['nodes']['info'] = t('Top Downloaded Nodes');
return $blocks;
}
/**
* Implements hook_block_configure().
*/
function download_count_block_configure($delta) {
$form['download_count_' . $delta . '_block_limit'] = array(
'#type' => 'textfield',
'#title' => t('Number of items to display'),
'#size' => 5,
'#default_value' => variable_get('download_count_' . $delta . '_block_limit', 10),
);
$form['download_count_' . $delta . '_show_size'] = array(
'#type' => 'checkbox',
'#title' => t('Display aggregated filesize'),
'#default_value' => variable_get('download_count_' . $delta . '_show_size', 0),
);
$form['download_count_' . $delta . '_show_last'] = array(
'#type' => 'checkbox',
'#title' => t('Display last download datetime'),
'#default_value' => variable_get('download_count_' . $delta . '_show_last', 0),
);
if ($delta == 'files') {
$form['download_count_files_file_links'] = array(
'#type' => 'checkbox',
'#title' => t('Display files names as links (based on permissions).'),
'#default_value' => variable_get('download_count_files_file_links', 1),
);
}
return $form;
}
/**
* Implements hook_block_save().
*/
function download_count_block_save($delta, $edit) {
variable_set('download_count_' . $delta . '_block_limit', $edit['download_count_' . $delta . '_block_limit']);
variable_set('download_count_' . $delta . '_show_size', $edit['download_count_' . $delta . '_show_size']);
variable_set('download_count_' . $delta . '_show_last', $edit['download_count_' . $delta . '_show_last']);
$delta == 'files' ? variable_set('download_count_files_file_links', $edit['download_count_files_file_links']) : NULL;
}
/**
* Implements hook_block_view().
*/
function download_count_block_view($delta) {
switch ($delta) {
case 'files':
$blocks['subject'] = t('Top Downloaded Files');
$blocks['content'] = _download_count_block_contents('files');
break;
case 'downloaders':
$blocks['subject'] = t('Top Downloaders');
$blocks['content'] = _download_count_block_contents('downloaders');
break;
case 'users':
$blocks['subject'] = t('Top Downloaded Users');
$blocks['content'] = _download_count_block_contents('users');
break;
case 'nodes':
$blocks['subject'] = t('Top Downloaded Nodes');
$blocks['content'] = _download_count_block_contents('nodes');
break;
}
return $blocks;
}
/**
* Implements hook_block().
*
*/
function download_count_block_OLD($op = 'list', $delta = 0, $edit = array()) {
}
/**
* internal functions
*/
function _download_count_get_file_by_upload($filepath) {
// check if Upload is enabled
if (!function_exists('upload_perm')) {
return NULL;
}
// upload not enabled
$result = db_query("SELECT u.nid, u.vid, f.filepath, f.fid FROM {upload} u JOIN {files} f ON f.fid = u.fid WHERE f.filepath = :f.filepath", array(
':f.filepath' => $filepath,
));
return db_fetch_object($result);
}
function _download_count_is_accessible_by_upload($filepath) {
if ($file = _download_count_get_file_by_upload($filepath)) {
if (user_access('view uploaded files') && node_access('view', node_load($file->nid))) {
return TRUE;
// accessible
}
else {
return FALSE;
// inaccessible
}
}
return NULL;
// not known
}
function _download_count_is_accessible_by_filefield($file) {
$nodes = _download_count_get_nodes_by_filefield($file);
if ($nodes === FALSE) {
return FALSE;
}
if ($nodes === NULL) {
return NULL;
}
return TRUE;
}
function _download_count_get_nodes_by_filefield($file) {
// check if FileField is enabled
if (!function_exists('filefield_view_access')) {
return NULL;
}
// not enabled
// The following logic is snipped from filefield.module 1.209 2009/10/20 17:46:22
// which is part of CCK FileField 6.x-3.2 release, see http://drupal.org/project/filefield
$result = db_query("SELECT * FROM {files} WHERE filepath = :filepath", array(
':filepath' => $file,
));
if (!($file = db_fetch_object($result))) {
// We don't really care about this file.
return NULL;
// not known
}
// Find out if any file field contains this file, and if so, which field
// and node it belongs to. Required for later access checking.
$cck_files = array();
foreach (content_fields() as $field) {
if ($field['type'] == 'filefield' || $field['type'] == 'image') {
$db_info = content_database_info($field);
$table = $db_info['table'];
$fid_column = $db_info['columns']['fid']['column'];
$columns = array(
'vid',
'nid',
);
foreach ($db_info['columns'] as $property_name => $column_info) {
$columns[] = $column_info['column'] . ' AS ' . $property_name;
}
// TODO Please convert this statement to the D7 database API syntax.
$result = db_query("SELECT " . implode(', ', $columns) . "\n FROM {" . $table . "}\n WHERE " . $fid_column . " = %d", $file->fid);
while ($content = db_fetch_array($result)) {
$content['field'] = $field;
$cck_files[$field['field_name']][$content['vid']] = $content;
}
}
}
// If no file field item is involved with this file, we don't care about it.
if (empty($cck_files)) {
return NULL;
// not known
}
// If any node includes this file but the user may not view this field,
// then deny the download.
foreach ($cck_files as $field_name => $field_files) {
if (!filefield_view_access($field_name)) {
return FALSE;
// inaccessible
}
}
// So the overall field view permissions are not denied, but if access is
// denied for ALL nodes containing the file, deny the download as well.
// Node access checks also include checking for 'access content'.
$nodes = array();
$denied = FALSE;
foreach ($cck_files as $field_name => $field_files) {
foreach ($field_files as $revision_id => $content) {
// Checking separately for each revision is probably not the best idea -
// what if 'view revisions' is disabled? So, let's just check for the
// current revision of that node.
if (isset($nodes[$content['nid']])) {
continue;
// Don't check the same node twice.
}
if ($denied == FALSE && ($node = node_load($content['nid'])) && node_access('view', $node) == FALSE) {
// You don't have permission to view the node this file is attached to.
$denied = TRUE;
}
$nodes[$content['nid']] = $node;
}
if ($denied) {
return FALSE;
// inaccessible
}
}
// Access is granted.
return $nodes;
}
function _download_count_block_contents($block) {
$result = '';
$limit = variable_get('download_count_' . $block . '_block_limit', 10);
$show_size = variable_get('download_count_' . $block . '_show_size', 0);
$show_last = variable_get('download_count_' . $block . '_show_last', 0);
$block == 'files' ? $file_links = variable_get('download_count_files_file_links', 1) : NULL;
switch ($block) {
case 'files':
$rows = array();
$header[] = array(
'data' => t('Filename'),
'class' => 'filename',
);
$header[] = $show_size ? array(
'data' => t('Size'),
'class' => 'size',
) : '';
$header[] = array(
'data' => t('Count'),
'class' => 'count',
);
$header[] = $show_last ? array(
'data' => t('Last Downloaded'),
'class' => 'last',
) : '';
if (user_access('view all download counts')) {
$result = db_query('SELECT COUNT(dc.dcid) AS count, f.filename, f.filepath, f.fid, SUM(f.filesize) AS size, MAX(dc.timestamp) as last FROM {download_count} dc JOIN {files} f ON dc.fid = f.fid GROUP BY f.filename ORDER BY count DESC LIMIT %d', (int) $limit);
}
while ($file = db_fetch_object($result)) {
$row = array();
$row[] = $file_links && (user_access('view uploaded files') || _download_count_is_accessible_by_filefield($file->filepath)) ? l(t('@filename', array(
'@filename' => $file->filename,
)), function_exists('_private_upload_create_url') ? _private_upload_create_url($file) : file_create_url($file->filepath)) : check_plain($file->filename);
$row[] = $show_size ? format_size($file->size) : '';
$row[] = $file->count;
$row[] = $show_last ? t('@time ago', array(
'@time' => format_interval(REQUEST_TIME - $file->last),
)) : '';
$rows[] = $row;
}
if (count($rows)) {
return theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => 'no-sticky',
),
));
}
return;
case 'downloaders':
$rows = array();
$header[] = array(
'data' => t('User'),
'class' => 'user',
);
$header[] = $show_size ? array(
'data' => t('Size'),
'class' => 'size',
) : '';
$header[] = array(
'data' => t('Count'),
'class' => 'count',
);
$header[] = $show_last ? array(
'data' => t('Last Downloaded'),
'class' => 'last',
) : '';
if (user_access('view all download counts')) {
$result = db_query('SELECT COUNT(dc.dcid) AS count, SUM(f.filesize) AS size, u.name, u.uid, MAX(dc.timestamp) as last FROM {download_count} dc JOIN {users} u ON dc.uid = u.uid JOIN {files} f on dc.fid = f.fid GROUP BY u.name ORDER BY count DESC LIMIT %d', (int) $limit);
}
while ($file = db_fetch_object($result)) {
$row = array();
$row[] = l($file->name, 'user/' . $file->uid);
$row[] = $show_size ? format_size($file->size) : '';
$row[] = $file->count;
$row[] = $show_last ? t('@time ago', array(
'@time' => format_interval(REQUEST_TIME - $file->last),
)) : '';
$rows[] = $row;
}
if (count($rows)) {
return theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => 'no-sticky',
),
));
}
return;
case 'users':
$rows = array();
$header[] = array(
'data' => t('User'),
'class' => 'user',
);
$header[] = $show_size ? array(
'data' => t('Size'),
'class' => 'size',
) : '';
$header[] = array(
'data' => t('Count'),
'class' => 'count',
);
$header[] = $show_last ? array(
'data' => t('Last Downloaded'),
'class' => 'last',
) : '';
if (user_access('view all download counts')) {
$result = db_query('SELECT COUNT(dc.dcid) AS count, SUM(f.filesize) AS size, u.name, u.uid, MAX(dc.timestamp) as last FROM {download_count} dc JOIN {files} f on dc.fid = f.fid JOIN {users} u ON f.uid = u.uid GROUP BY u.name ORDER BY count DESC LIMIT %d', (int) $limit);
}
while ($file = db_fetch_object($result)) {
$row = array();
$row[] = l($file->name, 'user/' . $file->uid);
$row[] = $show_size ? format_size($file->size) : '';
$row[] = $file->count;
$row[] = $show_last ? t('@time ago', array(
'@time' => format_interval(REQUEST_TIME - $file->last),
)) : '';
$rows[] = $row;
}
if (count($rows)) {
return theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => 'no-sticky',
),
));
}
return;
case 'nodes':
$rows = array();
$header[] = array(
'data' => t('Page'),
'class' => 'node',
);
$header[] = $show_size ? array(
'data' => t('Size'),
'class' => 'size',
) : '';
$header[] = array(
'data' => t('Count'),
'class' => 'count',
);
$header[] = $show_last ? array(
'data' => t('Last Downloaded'),
'class' => 'last',
) : '';
if (user_access('view all download counts')) {
$result = db_query('SELECT COUNT(dc.dcid) AS count, SUM(f.filesize) AS size, dc.nid, MAX(dc.timestamp) as last FROM {download_count} dc JOIN {files} f on dc.fid = f.fid GROUP BY dc.nid ORDER BY count DESC LIMIT %d', (int) $limit);
}
while ($file = db_fetch_object($result)) {
$row = array();
$node = node_load($file->nid);
$row[] = node_access('view', $node) ? l($node->title, 'node/' . $node->nid) : check_plain($node->title);
$row[] = $show_size ? format_size($file->size) : '';
$row[] = $file->count;
$row[] = $show_last ? t('@time ago', array(
'@time' => format_interval(REQUEST_TIME - $file->last),
)) : '';
$rows[] = $row;
}
if (count($rows)) {
return theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => 'no-sticky',
),
));
}
return;
default:
return;
}
}