WP доступ к файлу по паролю?

Подскажите, пожалуйста как в WordPress организовать доступ к файлу, но только после выполнения некого действия? Предположим, после ввода пароля на странице.

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


Ответы (2 шт):

Автор решения: Евгений Молдовану

Из самого простого варианта - организовать перевод пользователя из одного статуса (роль) в другой. пример

Также необходимо написать плагин WP который после кадого получения файла будет переименовывать иего на рандомное название и сохранение юрл. ЧатЖПТ в состоянии реализовать такой плагин. Если заказывать - 20-30 долларов максимум. Есть плагин Simple Download Monitor

→ Ссылка
Автор решения: KAGG Design

Есть плагины типа 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
    }
}
→ Ссылка