WP доступ к файлу по паролю?
Подскажите, пожалуйста как в WordPress организовать доступ к файлу, но только после выполнения некого действия? Предположим, после ввода пароля на странице.
Вот есть пользователь, у него есть какая-то Роль на сайте, дальше он оплачивает услуги и, предположим получает пароль на доступ к скачиванию некого файла с сервера сайта.
Предположим, comics.pdf файл. Как такое организовать ?
Как файл который находиться в /uploads/2024/01/comics.pdf закрыть от индексаций и стороннего доступа, но если у пользователя есть ключь, то дать ему возможность скачать файл.
Ответы (2 шт):
Из самого простого варианта - организовать перевод пользователя из одного статуса (роль) в другой.

Также необходимо написать плагин WP который после кадого получения файла будет переименовывать иего на рандомное название и сохранение юрл. ЧатЖПТ в состоянии реализовать такой плагин. Если заказывать - 20-30 долларов максимум. Есть плагин Simple Download Monitor
Есть плагины типа Easy Digital Downloads, которые дают виртуальную ссылку и контролируют, кто и сколько раз по ней обратился. И после проверки отдают файл через эту ссылку. Там все имеется, включая оплату.
Если надо делать своим кодом, то должна быть своя таблица в базе, в которой прописаны соответствия виртуальных ссылок и реальных файлов. Доступ по реальным файлам долджен быть закрыт. Все виртулаьные ссылки перехватывает свой код, проверят права, смотрит в таблицу и отдает файл.
Вот пример класса для работы с виртуальными ссылками и подсчета количества скачиваний. В него можно добавить проверки прав пользователя.
<?php
/**
* Class to hide file download links and count download number.
*
* @package kagg-downloader
*/
/**
* Class Downloader.
*
* Requires the following table in database:
*
* CREATE TABLE `wp_downloads` (
* `id` bigint(20) UNSIGNED NOT NULL,
* `url` varchar(355) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
* `download_link` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
* `count` bigint(20) UNSIGNED NOT NULL DEFAULT '0'
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
*/
class Downloader {
/**
* Class table name.
*/
private const TABLE = 'downloads';
/**
* Class table name.
*
* @var string $table
*/
protected static string $table;
/**
* Base of download links.
*
* @var string $link_base
*/
protected static string $link_base = '/downloads/';
/**
* Downloader constructor.
*/
public function __construct() {
global $wpdb;
self::$table = $wpdb->prefix . self::TABLE;
add_action( 'init', [ $this, 'rewrite_download_link' ] );
}
/**
* Get download link from url.
*
* @param string $url Download URL.
*
* @return string
*/
public static function get_link( string $url ): string {
global $wpdb;
$table = $wpdb->prefix . self::TABLE;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$record = $wpdb->get_row(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$wpdb->prepare( "SELECT download_link FROM $table WHERE url = %s", $url )
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $record->download_link ?? '';
}
/**
* Get url from download link.
*
* @param string $download_link Download link.
*
* @return string
*/
public static function get_url( string $download_link ): string {
global $wpdb;
$table = $wpdb->prefix . self::TABLE;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$record = $wpdb->get_row(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$wpdb->prepare( "SELECT url FROM $table WHERE download_link = %s", $download_link )
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $record->url ?? '';
}
/**
* Get download count.
*
* @param string $url Download URL.
*
* @return int
*/
public static function get_count( string $url ): int {
global $wpdb;
$table = $wpdb->prefix . self::TABLE;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$record = $wpdb->get_row(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$wpdb->prepare( "SELECT count FROM $table WHERE url = %s", $url )
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $record->count ?? - 1;
}
/**
* Create new download link from $url.
*
* @param string $url Download URL.
*
* @return string
*/
public static function create( string $url ): string {
global $wpdb;
$download_link = self::get_link( $url );
if ( $download_link ) {
return $download_link;
}
$download_link = self::$link_base . wp_hash( $url );
$data = [
'url' => $url,
'download_link' => $download_link,
];
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
$result = $wpdb->insert( self::$table, $data );
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery
return $result ? $download_link : '';
}
/**
* Rewrite download link by its url.
* Increase download count.
*/
public function rewrite_download_link(): void {
$uri = '';
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$uri = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_FULL_SPECIAL_CHARS );
}
$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 ) {
$this->increment_count( $url );
self::download_file( $url );
}
}
}
/**
* Download file.
*
* @param string $url file url.
*/
private static function download_file( string $url ): void {
if ( ! $url ) {
return;
}
$file_path = realpath( untrailingslashit( ABSPATH ) . wp_make_link_relative( $url ) );
if ( ! $file_path ) {
return;
}
$file_name = rawurlencode( pathinfo( $file_path, PATHINFO_FILENAME ) );
$file_extension = rawurlencode( pathinfo( $file_path, PATHINFO_EXTENSION ) );
$file_size = filesize( $file_path );
$known_content_types = [
'html' => 'text/html',
'htm' => 'text/html',
'txt' => 'text/plain',
'jpg' => 'image/jpg',
'jpeg' => 'image/jpg',
'png' => 'image/png',
'gif' => 'image/gif',
'tiff' => 'image/tiff',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'docx' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.ms-powerpoint',
'php' => 'text/plain',
'exe' => 'application/octet-stream',
'zip' => 'application/zip',
];
$content_type = 'application/force-download';
if ( array_key_exists( $file_extension, $known_content_types ) ) {
$content_type = $known_content_types[ $file_extension ];
}
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-Transfer-Encoding: binary' );
header( "Content-Length: $file_size" );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
readfile( $file_path );
exit();
}
/**
* Increment count.
*
* @param string $url Download URL.
*/
private function increment_count( string $url ): void {
global $wpdb;
if ( ! apply_filters( 'downloader_increment_count', true, $url ) ) {
return;
}
$count = self::get_count( $url );
$data = [ 'count' => ++$count ];
$where = [ 'url' => $url ];
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->update( self::$table, $data, $where );
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
}
}