Skip to content

Instantly share code, notes, and snippets.

@mjangda
Last active January 12, 2021 23:08
Show Gist options
  • Save mjangda/8657cfde2b2a4cafd95f509dd1d3dde9 to your computer and use it in GitHub Desktop.
Save mjangda/8657cfde2b2a4cafd95f509dd1d3dde9 to your computer and use it in GitHub Desktop.
<?php
<?php
namespace Automattic\VIP\Files\Acl;
use WP_Error;
class VIP_Files_Acl_Unpublished_Files_Test extends \WP_UnitTestCase {
const TEST_IMAGE_PATH = VIP_GO_MUPLUGINS_TESTS__DIR__ . '/fixtures/image.jpg';
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
require_once( __DIR__ . '/../../files/acl/vip-private-files-unpublished-files.php' );
}
public function test__get_file_path_from_attachment_id__attachment_not_found() {
$attachment_path = '/2020/12/not-an-attachment.pdf';
$expected_attachment_id = 0;
// Run the test.
$actual_attachment_id = get_file_path_from_attachment_id( $attachment_path );
$this->assertEquals( $expected_attachment_id, $actual_attachment_id );
}
public function test__get_file_path_from_attachment_id__attachment_only_one_result() {
// Set up a test attachment.
$expected_attachment_id = $this->factory->attachment->create_upload_object( self::TEST_IMAGE_PATH );
list( $attachment_src ) = wp_get_attachment_image_src( $expected_attachment_id, 'full' );
$attachment_path = parse_url( $attachment_src, PHP_URL_PATH );
$attachment_path = $this->strip_wpcontent_uploads( $attachment_path );
// Run the test.
$actual_attachment_id = get_file_path_from_attachment_id( $attachment_path );
$this->assertEquals( $expected_attachment_id, $actual_attachment_id );
}
public function test__get_file_path_from_attachment_id__attachment_multiple_results_first_in_list() {
// Set up the first attachment.
$attachment_id = $this->factory->attachment->create_upload_object( self::TEST_IMAGE_PATH );
// Create a second attachment with the same file path.
$duplicate_attachment_id = $this->factory->attachment->create_upload_object( self::TEST_IMAGE_PATH );
$duplicate_attachment_file = get_post_meta( $duplicate_attachment_id, '_wp_attached_file', true );
update_post_meta( $duplicate_attachment_id, '_wp_attached_file', $duplicate_attachment_file );
// Look up the first one in the list.
$expected_attachment_id = $attachment_id;
list( $attachment_src ) = wp_get_attachment_image_src( $expected_attachment_id, 'full' );
$attachment_path = parse_url( $attachment_src, PHP_URL_PATH );
$attachment_path = $this->strip_wpcontent_uploads( $attachment_path );
// Run the test.
$actual_attachment_id = get_file_path_from_attachment_id( $attachment_path );
$this->assertEquals( $expected_attachment_id, $actual_attachment_id );
}
public function test__get_file_path_from_attachment_id__attachment_multiple_results_exact_match_first() {
// Set up the first attachment.
$attachment_id = $this->factory->attachment->create_upload_object( self::TEST_IMAGE_PATH );
// Create a second attachment with the same file path.
$duplicate_attachment_id = $this->factory->attachment->create_upload_object( self::TEST_IMAGE_PATH );
$duplicate_attachment_file = get_post_meta( $duplicate_attachment_id, '_wp_attached_file', true );
update_post_meta( $duplicate_attachment_id, '_wp_attached_file', strtoupper( $duplicate_attachment_file ) );
// Look up the second one in the list.
$expected_attachment_id = $duplicate_attachment_id;
list( $attachment_src ) = wp_get_attachment_image_src( $expected_attachment_id, 'full' );
$attachment_path = parse_url( $attachment_src, PHP_URL_PATH );
$attachment_path = $this->strip_wpcontent_uploads( $attachment_path );
// Run the test.
$actual_attachment_id = get_file_path_from_attachment_id( $attachment_path );
$this->assertEquals( $expected_attachment_id, $actual_attachment_id );
}
private function strip_wpcontent_uploads( $path ) {
return substr( $path, strlen( '/wp-content/uploads/' ) );
}
}
<?php
/**
* Plugin Name: Restricted Files (All media)
* Description: Restrict access to all content from unaothorized users.
*/
add_filter( 'vip_files_acl_file_visibility', function ( $file_visibility, $file_path ) {
if ( ! is_user_logged_in() ) {
return FILE_IS_PRIVATE_AND_DENIED;
}
$user_has_read_permissions = current_user_can( 'read' );
if ( ! $user_has_read_permissions ) {
return FILE_IS_PRIVATE_AND_DENIED;
}
return FILE_IS_PRIVATE_AND_ALLOWED;
}, 10, 2 );
<?php
/**
* Plugin Name: Restricted Files (attachement
* Description: Restrict access to files/media attached to unpublished content.
*/
namespace Automattic\VIP\Files\Acl;
const CACHE_GROUP = 'vip-files-acl';
add_filter( 'vip_files_acl_file_visibility', function( $file_visibility, $file_path ) {
// Reverse lookup for the attachment ID
$attachment_id = get_attachment_id_from_file_path( $file_path );
if ( ! $attachment_id ) {
return FILE_NOT_FOUND;
}
$attachment = get_post( $attachment_id );
if ( ! $attachment ) {
return FILE_NOT_FOUND;
}
if ( 'inherit' === $attachment->post_status && $attachment->post_parent ) {
$parent_post = get_post( $attachment->post_parent );
if ( 'publish' === $parent_post->post_status ) {
return FILE_IS_PUBLIC;
}
$user_has_edit_access = current_user_can( 'edit_post', $parent_post );
if ( $user_has_edit_access ) {
$file_visibility = FILE_IS_PRIVATE_AND_ALLOWED;
} else {
$file_visibility = FILE_IS_PRIVATE_AND_DENIED;
}
}
return $file_visibility;
}, 10, 3 );
/**
* Variant of core's attachment_url_to_postid() function
*
* The core function accepts the full URL and has extra logic for reversing the host / home_uri().
*
* In the contexts where this is used, we are only acting on the path, so we've simplified things
* by only accepting a file path in this function.
*
* @param $path (string) The path to resolve.
*
* @return (int) The found attachment ID, or 0 on failure.
*/
function get_attachment_id_from_file_path( $path ) {
global $wpdb;
$cache_key = 'path_' . md5( $path );
$attachment_id = wp_cache_get( $cache_key, CACHE_GROUP );
if ( false !== $attachment_id ) {
return $attachment_id;
}
$attachment_id = 0;
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
$path
)
);
if ( $results ) {
// Use the first available result, but prefer a case-sensitive match, if exists.
$attachment_id = $results[0]->post_id;
if ( count( $results ) > 1 ) {
foreach ( $results as $result ) {
if ( $path === $result->meta_value ) {
$attachment_id = $result->post_id;
break;
}
}
}
}
wp_cache_set( $cache_key, $attachment_id, CACHE_GROUP, 5 * MINUTE_IN_SECONDS );
return $attachment_id;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment