随机上传文件名(或者另一种隐藏原始图像URL以防被盗的解决方案?)

时间:2021-02-15 作者:obinice

我们的用户上传我们需要防止被盗的高分辨率艺术品。这些图像已经调整了大小并添加了水印,但对于某些人来说,猜测原始URL并访问全分辨率图像仍然很简单。

我正试图找出一个最简单的解决方案(我想?)将文件名随机化。我可以使用以下方法在上传时随机化文件名:

function randomize_uploaded_filename( $filename ) {
    // Do things...
    return $filename
}
add_filter( \'sanitize_file_name\', \'randomize_uploaded_filename\', 10 );
但是,这将更改文件名before wordpress缩放图像。不太好。

我还可以在生成缩放大小时对其进行重命名,以便每个缩放大小都有一个唯一的随机文件名(与上述文件一起使用,这意味着所有图像文件都可以有不可用的文件名,对吗?几乎……):

add_filter( \'image_make_intermediate_size\', \'rename_intermediates\' );
function rename_intermediates( $image ) {
    $info = pathinfo($image);
    $dir = $info[\'dirname\'] . \'/\';
    $ext = \'.\' . $info[\'extension\'];
    $name = wp_basename( $image, "$ext" );

    $randomString = \'\' // random stuff here

    // Build our new image name
    $new_name = $dir . $randomString . $ext;

    // Rename the intermediate size
    $did_it = rename( $image, $new_name );

    // Renaming successful, return new name
    if( $did_it )
        return $new_name;

    return $image;
}
But, 如果我这样做,wordpress就不记得新的文件名了。因此,如果原始文件被上传并保存为,例如,绘画。jpg和缩放版本有一些随机文件名,如jkn4jk53u567u。jpg,wordpress仍然会认为缩放版被称为绘制缩放版。jpg等导致图像损坏。

我哪里做错了?非常感谢您的帮助:-)

Edit - 根据@SallyCJ的要求,下面是第二部分的全文:

Edit -零二很抱歉我的回复太慢,这几天很忙!首先,感谢您极具教育意义的详细回复!:O

你的修复非常棒,但对我来说并不完全有效,我会解释的。当我上传时picture.jpg 它可以像你所说的那样生成所有内容,Wordpress现在可以正确地看到原始图像和缩放图像的位置(例如。768O4Y7q-picture-scaled.jpg). 明亮的不过,它无法看到所有较小的尺寸。在媒体库(upload.php)页面上,它认为较小的大小BFcUGvP8-picture-100x100.jpg 用作缩略图的图像称为picture-100x100.jpg. 然而,在其他地区,它可以看到其他各种重命名的较小尺寸的大小刚刚好。。。

我还注意到,当重新生成较小的文件时,每次都会在文件名的开头添加8个随机字符(基于“new”原始文件名),并且it doesn\'t delete the old smaller sizes during regeneration. 它可以在旧的基础上保存新的。哎哟这是一个会导致磁盘空间使用爆炸的大问题,哈哈。

这在wp_generate_attachment_metadata 参考页:

"E;此函数可用于重新生成图像的缩略图和中间大小[…]但它不会检查或删除以前为同一图像创建的中间尺寸"E;

图像再生还有一些其他的大问题。

目前,仍然存在的问题有:

1. 新的较小尺寸位置没有全部更新,导致一些较小尺寸的图像损坏(可能是自定义图像尺寸导致的问题?100x100是自定义尺寸吗?)

2. 图像再生不会删除旧生成的较小尺寸。

3. 图像再生似乎重新检查了;“原件”;文件的文件名并从中提取,这将显示开头的随机字符串,即;隐藏“;它此外,它还使用另一组随机字符(例如。JGcYJrP9-picture.jpg 将成为H7liJRPW-JGcYJrP9-picture.jpg, 新的较小图像尺寸将被命名为vWCdtas2-JGcYJrP9-picture-100x100.jpg. 再进行一轮更新后,该文件将变成say,2jLL72he-H7liJRPW-JGcYJrP9-picture-100x100.jpg, 等

4. 我想将上传的文件名截断为最多50个字符。我想我之前没有提到这一点,我打算自己用substr($whatever, 0, 50) 但我遇到了麻烦(它对原始图像和缩放图像都很好,但当我在较小的尺寸上尝试时,它不会再正确更新它们的新文件名)。

麻烦你再帮我一会儿好吗?-顺便说一句,我不知道这里是否反对这种做法,但由于你对我很耐心,而且你的回答也非常详细,你是否有机会喝一杯buymeacoffee。com或类似产品?这是你应得的!

坦率地说,我不需要在缩放版本的开头添加随机字符,我只需要在原始版本上添加这些字符,以确保没有人能猜到URL。所以我不需要让它完美工作。不过,我确实需要解决这些重新生成错误:(而且我非常希望能够限制文件名的长度……用户在他们的文件名中书写整个小说!>;<;

1 个回复
SO网友:Sally CJ

Where am I going wrong?

Actually, your code is just fine.

Except that I would simply use wp_generate_password() to generate the random string. :)

WordPress will still think that the scaled version is called painting-scaled.jpg , etc. Resulting in broken images.

Yes, that\'s correct.

Images are stored as posts of the attachment type in the WordPress posts table (in the database), and the details (width, height, full file path, etc.) of the main image and its intermediate sizes (e.g. thumbnail and medium) are stored in a (private) meta named _wp_attachment_metadata — see wp_generate_attachment_metadata() and wp_get_attachment_metadata() for more info, but the meta value basically consists of:

  • \'width\' (int) The width of the attachment.
  • \'height\' (int) The height of the attachment.
  • \'file\' (string) The file path relative to wp-content/uploads.
  • \'sizes\' (array) Keys are size slugs, each value is an array containing \'file\', \'width\', \'height\', and \'mime-type\'.
  • \'image_meta\' (array) Image metadata.

And as for the -scaled version, if available, it will be used with the file item above and there\'ll be an additional item named original_image added to the above meta where the item\'s value will be the path to the originally uploaded image file — see wp_get_original_image_path().

So because the image_make_intermediate_size filters are applied both when generating the -scaled version and the intermediate sizes, then the -scaled version also gets renamed by your custom filter (the rename_intermediates() function), but unlike the above sizes item, WordPress no longer updates the file item once it is set after the -scaled version is generated.

Therefore that resulted in the broken image for the -scaled version.

But don\'t fret, there\'s a solution.

Yes, and basically you just need to use a different hook: wp_generate_attachment_metadata.

So just remove your image_make_intermediate_size filter and use the code below, and just let me know if you need any clarification:

// *UPDATED Feb 27th 2021 UTC

// Renames a file and if it succeeded, returns an array with the first item being the new name
// (e.g. <random string>-my-image.jpg). And this function is intended to be used only with the
// my_rename_images() below.
function my_rename_image( $file, $_rand_str = \'\' ) {
    $info = pathinfo( $file );

    $rand_str = wp_generate_password( 8, false ); // false = do not use special chars
    $new_name = $rand_str . \'-\' . ( $_rand_str ?
        str_replace( "{$_rand_str}-", \'\', $info[\'basename\'] ) : $info[\'basename\'] );
    $new_file = $info[\'dirname\'] . \'/\' . $new_name;

    return rename( $file, $new_file ) ? array( $new_name, $rand_str ) : false;
}

// Note: The _main_rand_str meta is used to prevent re-adding the random string to the name of
// the renamed image files.
add_filter( \'wp_generate_attachment_metadata\', \'my_rename_images\', 10, 3 );
function my_rename_images( $metadata, $attachment_id, $context ) {
    // Do nothing if the attachment is NOT an image, or if the attachment wasn\'t being
    // created.
    if ( \'create\' !== $context || empty( $metadata[\'image_meta\'] ) ) {
        return $metadata;
    }

    $file = get_attached_file( $attachment_id );
    $_rand_str = get_post_meta( $attachment_id, \'_main_rand_str\', true );

    if ( $arr = my_rename_image( $file, $_rand_str ) ) {
        $metadata[\'file\'] = dirname( $metadata[\'file\'] ) . \'/\' . $arr[0];
        update_attached_file( $attachment_id, $metadata[\'file\'] );
        update_post_meta( $attachment_id, \'_main_rand_str\', $arr[1] );
    }

    $dir = dirname( $file );
    foreach ( $metadata[\'sizes\'] as $size => $data ) {
        if ( $arr = my_rename_image( $dir . \'/\' . $data[\'file\'], $_rand_str ) ) {
            $metadata[\'sizes\'][ $size ][\'file\'] = $arr[0];
        }
    }

    if ( ! empty( $metadata[\'original_image\'] ) ) {
        $file = $dir . \'/\' . $metadata[\'original_image\'];
        if ( $arr = my_rename_image( $file, $_rand_str ) ) {
            $metadata[\'original_image\'] = $arr[0];
            update_post_meta( $attachment_id, \'_main_rand_str\', $arr[1] );
        }
    }

    return $metadata;
}

Sample output

So I uploaded a hi-res JPEG image via the Media → Add New admin page, and the generated file names/sizes are:

| File Name                             | Size Name      | Note                    | 
|---------------------------------------|----------------|-------------------------| 
| 768O4Y7q-foo-bar-image-scaled.jpg     |                | The "-scaled" version   | 
| zDQdlxMK-foo-bar-image-300x200.jpg    | medium         |                         | 
| 6CT8XZGI-foo-bar-image-1024x683.jpg   | large          |                         | 
| BFcUGvP8-foo-bar-image-150x150.jpg    | thumbnail      |                         | 
| 2vATG8xN-foo-bar-image-768x512.jpg    | medium_large   |                         | 
| 8xjeou4f-foo-bar-image-1536x1024.jpg  | 1536x1536      |                         | 
| 59YJJsQF-foo-bar-image-2048x1366.jpg  | 2048x2048      |                         | 
| 6HjAlOnr-foo-bar-image-1568x1046.jpg  | post-thumbnail |                         | 
| XQTkPM7I-foo-bar-image.jpg            |                | Original, but renamed   | 

UPDATE

In response to "Edit 27th Feb 2021" in the question:

  1. "The new smaller size locations aren\'t all being updated" — this didn\'t seem to have happened in my case, so please try the updated code above and see if the issue persists.

  2. "Image regeneration doesn\'t delete the old generated smaller sizes." — yes, because as you quoted it yourself, WordPress core says, "it does not check or delete intermediate sizes it previously created for the same image".

    So I\'m afraid you\'ll need to either manually delete the existing intermediate sizes, or find a plugin which can help you delete them. But note that one good reason why WordPress doesn\'t delete the intermediate sizes, is because those images might be in use in that they were linked to from somewhere (which is not a thief..), so simply deleting the images is not a good idea.

  3. Sorry about the random string which got re-added to the name of the renamed files.. But I\'ve corrected it in the updated code above.