<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

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
	 */
//    error_log("is_direct_access ============== " . $is_direct_access);
//    check_stop_image_hotlinking();
	check_file_is_prevented();
} else {
	show_file_from_private_link();
}

function check_stop_image_hotlinking() {
	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();
				}
			}
		}
	}
}

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;
	}
}

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 ] );

//    $guid = $_SERVER['REQUEST_URI'];
	$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;
}

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;
}

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;
}

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 );
}


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;
	}
}

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;
}

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 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();
	}
}

function try_to_send_file( $file ) {
}

function is_pdf( $mime_type ) {
	return $mime_type == "application/pdf";
}

function is_video( $mime_type ) {
	return strstr( $mime_type, "video/" );
}

function is_image( $file ) {
	preg_match( '/\.(gif|jpg|jpe?g|tiff|png|bmp|webp)$/i', $file, $matches );

	return ! empty( $matches );
}

function is_audio( $mime_type ) {
	return strstr( $mime_type, "audio/" );
}

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 );
}

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;
}


function _check_advance_file( $id, $original_file ) {
	$repository        = new 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 );
	}
}

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 );
	}
}


function remove_crop_numbers( $guid, $file_type ) {
	$pattern = "/-\d+x\d+.$file_type$/";
	$result  = preg_replace( $pattern, ".$file_type", $guid );

	return $result;
}

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 );
}

function download_file( $post ) {
	$fullPath = $post->guid; //http://localhost:8888/abc/cdf/wordpress-2/wp-content/uploads/2016/12/IMG_0789.JPG.jpg
	// echo($fullPath);
	$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 );
	// var_dump($upload_path); // wp-content/uploads
	$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 );
}

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' );
}
