WordPress Snippets

Encrypt automatically all file paths to wp-content/uploads on WordPress pages

<?php
/**
 * Secure Download File
 */
if ( isset( $_GET['secure_download'] ) ) {
	secure_download_file( $_GET['secure_download'], '' );
}

/**
 * Encrypt All Attachment Links
 */
add_action( 'template_redirect', 'encrypt_all_attachment_links' );
function encrypt_all_attachment_links() {
    ob_start( function( $buffer ) {
        return preg_replace_callback(
            '|/wp-content/uploads/\d{4}/[^\s"\']+(\.[^\s"\')]+)|',
            function( $matches ) {
                $file_url = get_site_url() . $matches[0];
                return encrypt_file_url( $file_url, false, '' );
            },
            $buffer
        );
    });
}


/**
 * Method Encrypt File Url
 *
 * This method will encrypt the file url.
 *
 * @param string $attachment_url The url of the file.
 * @param bool $site_url_prefix (Optional) Should it add the site_url() before the file path? Default is true.
 * @param string $ciphering (Optional) The encryption algorithm. Leave it empty for use base64.
 * @param string $key (Optional) The encryption key.
 * @return Encrypted_URL The encrypted url.
 */
function encrypt_file_url( string $attachment_url, bool $site_url_prefix = true, string $ciphering = 'AES-128-CBC', string $key = 'YOUR_KEY_HERE' ) {
	// Parse the URL into components
	$attachment_arr = parse_url($attachment_url, -1);

	// Store the scheme and host into a separate variable
	$attachment_site = $attachment_arr['scheme'] . '://' . $attachment_arr['host'] . '/';

	// Store the path component of the URL
	$attachment_path = $attachment_arr['path'];

	// Encrypt the path component of the URL
	if ( empty( $ciphering ) ) {
		//Just use base64
		$encrypted_url = base64_encode( $attachment_path );

	} else {
		//Use ciphering algorithm
		$encrypted_url = openssl_encrypt( $attachment_path, $ciphering, $key, 0, base64_encode( $key ) );

		//Use base64 for becoming url friendly
		$encrypted_url = base64_encode( $encrypted_url );
	}

	// Concatenate the scheme and host with the encrypted path and return the result
	if ( $site_url_prefix ) {
		return $attachment_site . '?secure_download=' . $encrypted_url;
	} else {
		return '?secure_download=' . $encrypted_url;
	}
}

/**
 * Method Secure Download File
 *
 * This method will decrypt the file path and view or download it.
 *
 * @param string $file_hash The encrypted url.
 * @param string $ciphering (Optional) The encryption algorithm. Leave it empty to use base64.
 * @param string $key (Optional) The encryption key.
 * @param string $disposition (Optional) The beheaviour: inline means that it will open in the browser / attachment will download the file.
 * @return void
 */
function secure_download_file( string $file_hash, string $ciphering = 'AES-128-CBC', string $key = 'YOUR_KEY_HERE', string $disposition = 'inline' ) {
	//Decode base64
	$file_hash_decoded = base64_decode( $file_hash );

	//Decrypt path to file
	if ( empty( $ciphering ) ) {
		$decrypted_url = $file_hash_decoded;
	} else {
		//Decrypt using cipher
		$decrypted_url = openssl_decrypt( $file_hash_decoded, $ciphering, $key, 0, base64_encode( $key ) );
	}


	//Build full file path
	$file_path = site_url() . $decrypted_url;

	//Download file
	header( 'Content-Description: File Transfer' );
	header( 'Content-Type: application/octet-stream' );
	header( 'Content-Disposition: ' . $disposition . '; filename="'.basename( $file_path ).'"' );
	header( 'Expires: 0' );
	header( 'Cache-Control: must-revalidate' );
	header( 'Pragma: public' );

	//Ignore SSL
	stream_context_set_default(
		[
			'ssl' => [
				'verify_peer' => false,
				'verify_peer_name' => false,
			],
		]
	);

	readfile( $file_path );
}

Leave a Reply