Часто возникает вопрос — как посчитать число скачиваний файла и спрятать реальную ссылку на скачиваемый файл?
Для решения этой задачи надо сделать две вещи: перехватить клик на ссылку и отдать реальный файл пользователю средствами php.
Что происходит при клике на фиктивную ссылку, указывающую на несуществующую страницу сайта? WordPress инициализирует ядро и пытается выдать страницу 404. В этот момент надо вмешаться своей функцией, обновить счётчик загрузок и отдать реальный файл. Ниже код такой функции.
/**
* Rewrite download link by its url.
* Increase download count.
*/
public function rewrite_download_link() {
/** @var wpdb $wpdb */
global $wpdb;
$uri = $_SERVER['REQUEST_URI'];
$path = wp_parse_url( $uri, PHP_URL_PATH );
if ( 0 === strpos( trailingslashit( $path ), self::$link_base ) ) {
$download_link = untrailingslashit( $path );
$url = self::get_url( $download_link );
if ( $url ) {
$count = self::get_count( $url );
$data = array(
'count' => ++ $count,
);
$where = array(
'url' => $url,
);
$wpdb->update( self::$table, $data, $where );
self::download_file( $url );
}
}
}
Функция rewrite_download_link()
срабатывает на событии init
, и проверяет, не начинается ли url с $link_base
. Например, это может быть /downloads/
. Любая ссылка вида http://site.org/downloads/cool.jpg
считается фиктивной и подлежит обработке, в которой обновляется счётчик загрузок, вычисляется реальный url файла и вызывается функция отдачи реального файла пользователю.
Код этой функции приведён ниже.
/**
* Download file.
*
* @param string $url file url.
*/
private static function download_file( $url ) {
if ( ! $url ) {
return;
}
$file_path = ABSPATH . wp_make_link_relative( $url );
$file_name = pathinfo( $file_path, PATHINFO_FILENAME );
$file_extension = pathinfo( $file_path, PATHINFO_EXTENSION );
switch ( $file_extension ) {
case 'png':
$content_type = 'image/png';
break;
case 'gif':
$content_type = 'image/gif';
break;
case 'tiff':
$content_type = 'image/tiff';
break;
case 'jpeg':
case 'jpg':
$content_type = 'image/jpg';
break;
default:
$content_type = 'application/force-download';
}
header( 'Expires: 0' );
header( 'Cache-Control: no-cache, no-store, must-revalidate' );
header( 'Cache-Control: pre-check=0, post-check=0, max-age=0', false );
header( 'Pragma: no-cache' );
header( "Content-type: {$content_type}" );
header( "Content-Disposition:attachment; filename={$file_name}.{$file_extension}" );
header( 'Content-Type: application/force-download' );
// @codingStandardsIgnoreLine
readfile( "{$file_path}" );
exit();
}
Функция download_file()
делает полученную ссылку на файл относительной и вычисляет путь к файлу, а потом отдаёт его средствами php. Таким образом, пользователь не имеет возможности узнать, где находится реальный файл и скачать его напрямую.
Полный код класса, который содержит приведённые выше методы, можно найти на нашем GitHub.