File: /var/www/intranet.kauko.lt/wp-content/plugins/prevent-direct-access/download.php
<?php
/**
*
* Download Functions and Protections
*
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Call Required Files
require_once 'includes/repository.php';
require_once 'includes/helper.php';
ignore_user_abort( true );
set_time_limit( 0 ); // disable the time limit for this script
$is_direct_access = isset( $_GET['is_direct_access'] ) ? sanitize_text_field( $_GET['is_direct_access'] ) : '';
if ( $is_direct_access === 'true' ) {
/**
* Quick fix for FAP
* Current FAP is "No user roles" => send file not found to client
* Later if we need to improve FAP, then we can handle in the check_file_is_prevented function
*/
check_file_is_prevented();
} else {
show_file_from_private_link();
}
/**
* Check if option existed
*/
function check_stop_image_hotlinking() {
// Check File is set or not
if ( ! isset( $_GET['file_type'] ) ) {
return;
}
$pda_option = get_option( 'FREE_PDA_SETTINGS' );
if ( is_array( $pda_option ) && array_key_exists( 'enable_image_hot_linking', $pda_option ) && $pda_option['enable_image_hot_linking'] === "on" ) {
$file_type = sanitize_text_field( $_GET['file_type'] );
$images = [ 'jpg', 'png', 'PNG', 'gif' ];
if ( in_array( $file_type, $images ) ) {
if ( ( isset( $_SERVER['HTTP_REFERER'] ) && ! empty( $_SERVER['HTTP_REFERER'] ) ) ) {
$referer_host = parse_url( $_SERVER['HTTP_REFERER'] )['host']; //localhost
$my_domain = $_SERVER['HTTP_HOST']; //staging.ymese.com
if ( $referer_host !== $my_domain ) {
file_not_found();
}
}
}
}
}
/**
* Get Page 404 from settings
*/
function get_page_404() {
$pda_settings = get_option( 'FREE_PDA_SETTINGS' );
if ( isset( $pda_settings['search_result_page_404'] ) ) {
$page_404 = $pda_settings['search_result_page_404'];
$link_page_404 = explode( ";", $page_404 );
return $link_page_404[0];
} else {
return null;
}
}
/**
* Check file is prevented
*/
function check_file_is_prevented() {
$configs = Pda_Helper::get_plugin_configs();
$endpoint = $configs['endpoint'];
if ( ! isset( $_GET[ $endpoint ], $_GET['file_type'] ) ) {
file_not_found();
}
$file_name = sanitize_text_field( $_GET[ $endpoint ] );
$file_type = sanitize_text_field( $_GET['file_type'] );
$original_file = "$file_name.$file_type";
$attachment_id = pda_free_get_attachment_id_from_url( $original_file );
$mime = wp_check_filetype( $original_file );
$attachment_id = apply_filters( 'pda_handle_attachment_id', $attachment_id, $original_file, $mime );
if ( empty( $attachment_id ) ) {
file_not_found();
} else {
_check_advance_file( $attachment_id, $original_file );
}
}
/**
* Get attachment ID from file path
*
* @param string $file_path The file path from .htaccess without _pda.
*
* @return int|bool
*/
function pda_free_get_attachment_id_from_url( $file_path ) {
// Need to pre append the _pda due to no _pda in current .htaccess rule.
$file_path = '/_pda' . strtok( $file_path, '?' );
$extension = wp_check_filetype( $file_path );
$upload_dir = wp_upload_dir();
if ( false === $extension['type'] || false === strpos( $extension['type'], 'image' ) ) {
$attachment_id = attachment_url_to_postid( $upload_dir['baseurl'] . $file_path );
} else {
$attachment = pda_free_attachment_image_url_to_post( $upload_dir['baseurl'], $file_path );
$attachment_id = empty( $attachment ) ? false : (int) $attachment->post_id;
}
return $attachment_id;
}
/**
* Attachment UEL to Post
*
* @param array $options
* @param string $option_key
*
* @return Mixed
*/
function pda_free_attachment_image_url_to_post( $baseurl, $filepath ) {
global $wpdb;
list( $size, $file_no_size ) = get_image_size_of_link( $filepath );
// Massage attachment URL before handle.
$url_has_size = massage_file_url( $baseurl . $filepath );
/**
* Only return post_id if attachment have not file size.
*/
if ( empty( $size ) ) {
$sql = $wpdb->prepare(
"SELECT * FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
$url_has_size
);
$post = $wpdb->get_row( $sql );
return $post;
}
// Massage attachment URL before handle.
$url_no_size = massage_file_url( $baseurl . $file_no_size );
/**
* Input image: test.jpg
* Output image: test-scaled.jpg
*/
$url_no_size_scaled = pda_free_get_scaled_url( $url_no_size );
/**
* Get all file which has size and no size.
*/
if ( $url_no_size_scaled ) {
$sql = $wpdb->prepare(
"SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value IN (%s, %s, %s)",
$url_has_size,
$url_no_size,
$url_no_size_scaled
);
} else {
$sql = $wpdb->prepare(
"SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value IN (%s, %s)",
$url_has_size,
$url_no_size
);
}
$posts = $wpdb->get_results( $sql );
if ( count( $posts ) === 1 ) {
return $posts[0];
}
/**
* Priority:
* 1. Get file which has size first
* 2. Get file which has no size.
*/
foreach ( $posts as $post ) {
if ( $url_has_size === $post->meta_value ) {
return $post;
}
}
foreach ( $posts as $post ) {
if ( $url_no_size === $post->meta_value ) {
return $post;
}
}
if ( $url_no_size_scaled ) {
foreach ( $posts as $post ) {
if ( $url_no_size_scaled === $post->meta_value ) {
return $post;
}
}
}
return pda_free_might_get_post_id_from_backup_sizes( $url_no_size, $url_no_size_scaled );
}
/**
* Get scaled image.
*
* @param string $url URL.
* @param string $optimize_name Optimize name for image.
*
* @return bool|string
*/
function pda_free_get_scaled_url( $url, $optimize_name = '-scaled' ) {
$url_no_size_scaled = false;
$url_no_size_pattern = explode( '.', $url );
$len_url_no_size = count( $url_no_size_pattern );
/**
* Check file have extension and concat '-scaled' to image URL.
* -scaled WP release 5.3 version.
*/
if ( $len_url_no_size > 1 ) {
$url_no_size_pattern[ $len_url_no_size - 2 ] = $url_no_size_pattern[ $len_url_no_size - 2 ] . $optimize_name;
$url_no_size_scaled = implode( '.', $url_no_size_pattern );
}
return $url_no_size_scaled;
}
/**
* Try to guess the post ID from backup sizes data.
*
* @param string $url_no_size The request URL.
* @param string $url_no_size_scaled The scaled file URL.
*
* @return object|bool
* object having the post_id key.
* bool (false) cannot find any attachment file.
*/
function pda_free_might_get_post_id_from_backup_sizes( $url_no_size, $url_no_size_scaled ) {
$file = wp_basename( $url_no_size );
$scaled_file = wp_basename( $url_no_size_scaled );
$query_args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'meta_query' => array(
'relation' => 'OR',
array(
'value' => $file,
'compare' => 'LIKE',
'key' => '_wp_attachment_backup_sizes', // Case when rotate the images.
),
array(
'value' => $scaled_file,
'compare' => 'LIKE',
'key' => '_wp_attachment_backup_sizes', // Case when crop scaled images with small size
),
),
);
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) {
foreach ( $query->posts as $post_id ) {
// Need to query the backup sizes and double check with the input file.
$backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
$backup_image_files = wp_list_pluck( $backup_sizes, 'file' );
if ( in_array( $file, $backup_image_files, true ) || in_array( $scaled_file, $backup_image_files, true ) ) {
return (object) array(
'post_id' => $post_id,
);
}
}
}
return false;
}
/**
* Massage File URL
*
* @param string $url
*
* @return Mixed
*/
function massage_file_url( $url ) {
$dir = wp_get_upload_dir();
$path = $url;
$site_url = parse_url( $dir['url'] );
$image_path = parse_url( $path );
//force the protocols to match if needed
if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
$path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
}
if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) {
$path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
}
return $path;
}
/**
* Get image size
*
* @param string $file
*
* @return Mixed
*/
function get_image_size_of_link( $file ) {
$default_results = array( '', $file );
if ( ! is_image( $file ) ) {
return $default_results;
}
preg_match_all( '(-\d+x\d+\.\w+$)', $file, $matches, PREG_PATTERN_ORDER );
$found = end( $matches[0] );
if ( empty( $found ) ) {
return $default_results;
}
$arr = explode( '.', $found );
$size = $arr[0];
$ext = $arr[1];
$url_file = str_replace( $found, ".$ext", $file );
return array( $size, $url_file );
}
/**
* Check download limitation
*
* @param array $advance_file
*
* @return Mixed
*/
function is_under_limited_downloads( $advance_file ) {
if ( isset( $advance_file->limit_downloads ) ) {
return $advance_file->hits_count >= $advance_file->limit_downloads;
} else {
return false;
}
}
/**
* Is Expired or not
*
* @param array $advance_file
*
* @return Mixed
*/
function is_expired( $advance_file ) {
if ( ! isset( $advance_file->expired_date ) ) {
return false;
}
$expired_date = date( 'm/d/Y', $advance_file->expired_date );
$today = date( 'm/d/Y' );
return $today >= $expired_date;
}
/**
* Show File From Private Link
*/
function show_file_from_private_link() {
$configs = Pda_Helper::get_plugin_configs();
$endpoint = $configs['endpoint'];
if ( isset( $_GET[ $endpoint ] ) ) {
$private_url = sanitize_text_field( $_GET[ $endpoint ] );
$repository = new PDA_Repository;
$advance_file = $repository->get_advance_file_by_url( $private_url );
if ( isset( $advance_file ) &&
$advance_file->is_prevented === "1" &&
! is_under_limited_downloads( $advance_file ) &&
! is_expired( $advance_file ) ) {
$post_id = $advance_file->post_id;
$post = $repository->get_post_by_id( $post_id );
if ( isset( $post ) ) {
$new_hits_count = isset( $advance_file->hits_count ) ? $advance_file->hits_count + 1 : 1;
$repository->update_advance_file_by_id( $advance_file->ID, array( 'hits_count' => $new_hits_count ) );
} else {
echo '<h2>Sorry! Invalid post!</h2>';
}
if ( isset( $post ) ) {
download_file( $post );
} else {
$post = $repository->get_post_meta_by_post_id( $post_id );
download_file_by_meta_value( $post );
}
} else {
file_not_found();
}
} else {
file_not_found();
}
}
/**
* Try to send file
*
* @param array $file
*
*/
function try_to_send_file( $file ) {}
/**
* Check mime type of file
*
* @param string $mime_type
*
* @return mime_type
*/
function is_pdf( $mime_type ) {
return $mime_type == "application/pdf";
}
/**
* Check mime type of file
*
* @param string $mime_type
*
* @return mime_type
*/
function is_video( $mime_type ) {
return strstr( $mime_type, "video/" );
}
/**
* Check images format
*
* @param array $file
*
* @return Mixed
*/
function is_image( $file ) {
preg_match( '/\.(gif|jpg|jpe?g|tiff|png|bmp|webp)$/i', $file, $matches );
return ! empty( $matches );
}
/**
* Check mime type of file
*
* @param array $mime_type
*
* @return mime_type
*/
function is_audio( $mime_type ) {
return strstr( $mime_type, "audio/" );
}
/**
* Send file to client
*
* @param array $file
*
* @return Mixed
*/
function send_file_to_client( $file ) {
if ( ! is_file( $file ) ) {
file_not_found();
}
$mime = wp_check_filetype( $file );
if ( false === $mime['type'] && function_exists( 'mime_content_type' ) ) {
$mime['type'] = mime_content_type( $file );
}
if ( $mime['type'] ) {
$mimetype = $mime['type'];
} else {
$mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );
}
if ( is_image( $file ) == false && is_pdf( $mimetype ) == false && is_video( $mimetype ) == false && is_audio( $mimetype ) == false ) {
$file_name = wp_basename( $file );
header( "Content-Disposition: attachment; filename=$file_name" );
}
//set header
header( 'Content-Type: ' . $mimetype ); // always send this
if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) ) {
header( 'Content-Length: ' . filesize( $file ) );
}
$last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
$etag = '"' . md5( $last_modified ) . '"';
header( "Last-Modified: $last_modified GMT" );
header( 'ETag: ' . $etag );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
header( 'X-Robots-Tag: none' );
// Support for Conditional GET
$client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;
if ( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;
}
$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
// If string is empty, return 0. If not, attempt to parse into a timestamp
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
// Make a timestamp for our most recent modification...
$modified_timestamp = strtotime( $last_modified );
if ( ( $client_last_modified && $client_etag )
? ( ( $client_modified_timestamp >= $modified_timestamp ) && ( $client_etag == $etag ) )
: ( ( $client_modified_timestamp >= $modified_timestamp ) || ( $client_etag == $etag ) )
) {
status_header( 304 );
exit;
}
status_header( 200 );
readfile( $file );
}
/**
* Get full path of file
*
* @param array $original_file
*
* @return file_path
*/
function get_full_file_path( $original_file ) {
$upload_base_dir = wp_upload_dir()['basedir'];
$file_path = $upload_base_dir . "/_pda" . $original_file;
return $file_path;
}
/**
* Check Advance File
*
* @param integer $id
* @param array $original_file
*
* @return Mixed
*/
function _check_advance_file( $id, $original_file ) {
$repository = new PDA_Repository;
$advance_file = $repository->get_status_advance_file_by_post_id( $id, true );
$is_file_protected = isset( $advance_file ) && $advance_file->is_prevented === "1";
if ( $is_file_protected ) {
$fap = Pda_Helper::get_fap_setting();
if ( ! pda_free_check_fap_for_file( $id, $fap ) ) {
file_not_found();
exit();
}
}
$file_path = get_full_file_path( $original_file );
send_file_to_client( $file_path );
}
/**
* Check FAP.
*
* @param integer $id Attachment ID.
* @param string $fap File access permission.
*
* @return bool
*/
function pda_free_check_fap_for_file( $id, $fap ) {
switch ( $fap ) {
case 'admin_users':
return Pda_Helper::is_admin_user_role();
default:
return apply_filters( 'pda_handle_file_author_permission', is_post_author( $id ), $id );
}
}
/**
* Check file found or not
*/
function file_not_found() {
$page_404 = get_page_404();
if ( isset( $page_404 ) && ! empty( $page_404 ) ) {
header( "Location: " . $page_404, true, 301 );
} else {
header( "Location: " . get_site_url() . "/pda_404", true, 301 );
}
}
/**
* Remove number.
*
* @param integer $guid Attachment ID.
* @param string $file_type
*
* @return Mixed
*/
function remove_crop_numbers( $guid, $file_type ) {
$pattern = "/-\d+x\d+.$file_type$/";
$result = preg_replace( $pattern, ".$file_type", $guid );
return $result;
}
/**
* Download file by metavalue
*
* @param array $post
*
*/
function download_file_by_meta_value( $post ) {
$meta_value = $post->meta_value;
$upload_base_dir = wp_upload_dir()['basedir'] . '/';
$filePath = $upload_base_dir . $meta_value;
send_file_to_client( $filePath );
}
/**
* Download file
*
* @param array $post
*
* @return bool
*/
function download_file( $post ) {
$fullPath = $post->guid;
$wpDir = ABSPATH; //Applications/MAMP/htdocs/abc/cdf/wordpress-2/
$upload_base_dir = wp_upload_dir()['basedir']; //Applications/MAMP/htdocs/abc/cdf/wordpress-2/wp-content/uploads
$upload_path = str_replace( $wpDir, '', $upload_base_dir );
$filePath = $upload_base_dir . '/' . get_post_meta( $post->ID, '_wp_attached_file', true );
// $pattern = '/^((http|https|ftp):\/\/)?([^\/]+\/)/i';
// $fullPath = preg_replace( $pattern, $wpDir, $fullPath );
send_file_to_client( $filePath );
}
/**
* Check whitelist list for user role
*/
function is_in_whitelist() {
$user = wp_get_current_user();
if ( 0 === $user->ID ) {
return false;
} else {
$white_list_roles = get_option( 'whitelist_roles' );
if ( is_array( $white_list_roles ) ) {
$result = array_intersect( $white_list_roles, $user->roles );
return ! empty( $result );
} else {
return false;
}
}
}
/**
* Wrapper function to check whether the current user is post's author
*
* @param int $attachment_id The Attachment's ID
*
* @return bool
* false: User is anonymous or the post doesn't have the author.
* true: Current user ID equals to post's author ID.
*/
function is_post_author( $attachment_id ) {
if ( ! is_user_logged_in() ) {
return false;
}
// Post does not have the author or attachment ID cannot find.
if ( empty( get_post_field( 'post_author', $attachment_id, 'raw' ) ) ) {
return false;
}
return (int) get_current_user_id() === (int) get_post_field( 'post_author', $attachment_id, 'raw' );
}