From 6ec77ccb6913cb365fc49eb6194f3bf725080c14 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Tue, 19 Nov 2024 16:21:39 +0100 Subject: [PATCH] Improve Image-Handling (#999) * Improve Image-Handling Allow filtering the image-srcs and upload-baseurl, if upload url might differ or if a CDN is used. * try to fix `exif_read_data(test.jpg): Illegal IFD size` error * silence errors * escape global functions * Update tests/class-test-activitypub-post.php Co-authored-by: Alex Kirk * Update includes/transformer/class-post.php Co-authored-by: Alex Kirk * use `wp_get_upload_dir` --------- Co-authored-by: Alex Kirk --- includes/functions.php | 16 ++++ includes/transformer/class-post.php | 23 +++++- tests/assets/test.jpg | Bin 0 -> 3574 bytes tests/class-test-activitypub-post.php | 103 ++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 tests/assets/test.jpg diff --git a/includes/functions.php b/includes/functions.php index 616391ad8..7065edb01 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1471,3 +1471,19 @@ function get_attribution_domains() { return $domains; } + +/** + * Get the base URL for uploads. + * + * @return string The upload base URL. + */ +function get_upload_baseurl() { + $upload_dir = \wp_get_upload_dir(); + + /** + * Filters the upload base URL. + * + * @param string \wp_get_upload_dir()['baseurl'] The upload base URL. + */ + return apply_filters( 'activitypub_get_upload_baseurl', $upload_dir['baseurl'] ); +} diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php index 1272b5bc2..3d0326c36 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -15,6 +15,7 @@ use function Activitypub\esc_hashtag; use function Activitypub\is_single_user; use function Activitypub\get_enclosures; +use function Activitypub\get_upload_baseurl; use function Activitypub\get_content_warning; use function Activitypub\site_supports_blocks; use function Activitypub\generate_post_summary; @@ -477,14 +478,22 @@ protected function get_classic_editor_image_embeds( $max_images ) { } $images = array(); - $base = \wp_get_upload_dir()['baseurl']; + $base = get_upload_baseurl(); $content = \get_post_field( 'post_content', $this->wp_object ); $tags = new \WP_HTML_Tag_Processor( $content ); // This linter warning is a false positive - we have to re-count each time here as we modify $images. // phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found while ( $tags->next_tag( 'img' ) && ( \count( $images ) <= $max_images ) ) { - $src = $tags->get_attribute( 'src' ); + /** + * Filter the image source URL. + * + * This can be used to modify the image source URL before it is used to + * determine the attachment ID. + * + * @param string $src The image source URL. + */ + $src = \apply_filters( 'activitypub_image_src', $tags->get_attribute( 'src' ) ); /* * If the img source is in our uploads dir, get the @@ -499,16 +508,22 @@ protected function get_classic_editor_image_embeds( $max_images ) { if ( null !== $src && \str_starts_with( $src, $base ) ) { $img_id = \attachment_url_to_postid( $src ); + if ( 0 === $img_id ) { + $count = 0; + $src = \strtok( $src, '?' ); + $img_id = \attachment_url_to_postid( $src ); + } + if ( 0 === $img_id ) { $count = 0; - $src = preg_replace( '/-(?:\d+x\d+)(\.[a-zA-Z]+)$/', '$1', $src, 1, $count ); + $src = \preg_replace( '/-(?:\d+x\d+)(\.[a-zA-Z]+)$/', '$1', $src, 1, $count ); if ( $count > 0 ) { $img_id = \attachment_url_to_postid( $src ); } } if ( 0 === $img_id ) { - $src = preg_replace( '/(\.[a-zA-Z]+)$/', '-scaled$1', $src ); + $src = \preg_replace( '/(\.[a-zA-Z]+)$/', '-scaled$1', $src ); $img_id = \attachment_url_to_postid( $src ); } diff --git a/tests/assets/test.jpg b/tests/assets/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c21946f645e4871fa33e9f7e9f2638c765a610da GIT binary patch literal 3574 zcmeHKU2xP?6h1e}{Y_dsP>}FUxw50+w%Rs4uyk(QLP21fK+0;!t z;{%AIyx}kUR8UZSL&e_*MNxj9C5z+)KvcOIjK`7t=S#n#2kC4`~ z4}*>};1!y1I7A6}GxD9gEa1v>_u`!bSFDZ=mS>LTG`HaJZDLB4Wl)kzyDH17+{w#H zN|X)&c8XNflwHZ$zHwkk>aqNo{#tSRb+oaAY?B#TK2R&;r`rjME~ zpEZZ9d|LS7op%M^GSb54j!ZIR_n5=hnn}mpG`W62pB&XwhS0T=U*V}<&d!;x#(TN3 zd{On%LJ(XfzDw3ik&?8Zt$h(@C$QN7YBJ`R?-LY)fD&%<@QOg#_-L!x!UrQ-xSHfOb z`<$bpSN!a8XDnFU&?R%s%$a$&h;@>woSdy@3WhZ}(W|*;TA=%qkmZEjIWV^`G%-V0 zi{sf5Q+LZcyR{(+sq_znMDzVy{?viK!lF=GsqRX?j(P>^6{uIBUV(ZA>J|9^RiN6R znR#r=O4xmY{~pAnV1U6A0hl;p{kQ1T$!fs2Ql7R#%`^EYY{VOz7Zeb2sVOZVZU3;L%oFKNpr)MR)vxk~cB=(9VY++4bmS zyB~kz$)}!vX797l?SKA-0|#Gx>Cnrsy!zUa*WY;at+(I*;Mj*B9Y1mM)R~#H=gxn8 z;o_y)&%gNctFOQL_Pg(|{P@$)zx?{!?|=MBbz!S}O%`6St1FJW7>;AP2-QWH5)~fj zLW|{a)2fXTZQFc7*&c1~-m~xU(O64c|K$Z)XS!kGlJ?o9SE#f=*^LR?@t>4cgjIEY z0zLT0LBZh3G7N4Ni{Qc>MK}@;5Gf-XAV$$xfsa85oyoExJR76oXvKEJ#Qzlk7$W{9 qxQQkBF|l#zf~!|s_wR;(8~*7U_URh-Gd1ipHSA|=*w59lU;GOJxydU4 literal 0 HcmV?d00001 diff --git a/tests/class-test-activitypub-post.php b/tests/class-test-activitypub-post.php index d05e9c0e6..de47694e0 100644 --- a/tests/class-test-activitypub-post.php +++ b/tests/class-test-activitypub-post.php @@ -74,4 +74,107 @@ public function test_content_visibility() { $this->assertEquals( array(), $object->get_to() ); $this->assertEquals( array(), $object->get_cc() ); } + + /** + * Test different variations of Attachment parsing. + */ + public function test_block_attachments_with_fallback() { + $attachment_id = $this->create_upload_object( __DIR__ . '/assets/test.jpg' ); + $attachment_src = \wp_get_attachment_image_src( $attachment_id ); + + $post_id = \wp_insert_post( + array( + 'post_author' => 1, + 'post_content' => sprintf( + '
', + $attachment_id, + $attachment_src[0] + ), + 'post_status' => 'publish', + ) + ); + + $object = \Activitypub\Transformer\Post::transform( get_post( $post_id ) )->to_object(); + + $this->assertEquals( + array( + array( + 'type' => 'Image', + 'url' => $attachment_src[0], + 'mediaType' => 'image/jpeg', + ), + ), + $object->get_attachment() + ); + + $post_id = \wp_insert_post( + array( + 'post_author' => 1, + 'post_content' => sprintf( + '

this is a photo

', + $attachment_id, + $attachment_src[0] + ), + 'post_status' => 'publish', + ) + ); + + $object = \Activitypub\Transformer\Post::transform( get_post( $post_id ) )->to_object(); + + $this->assertEquals( + array( + array( + 'type' => 'Image', + 'url' => $attachment_src[0], + 'mediaType' => 'image/jpeg', + ), + ), + $object->get_attachment() + ); + + \wp_delete_attachment( $attachment_id, true ); + } + + /** + * Saves an attachment. + * + * @param string $file The file name to create attachment object for. + * @param int $parent_id ID of the post to attach the file to. + * + * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure. + */ + public function create_upload_object( $file, $parent_id = 0 ) { + $file_array = array( + 'name' => wp_basename( $file ), + 'tmp_name' => $file, + ); + + $upload = wp_handle_sideload( $file_array, array( 'test_form' => false ) ); + + $type = ''; + if ( ! empty( $upload['type'] ) ) { + $type = $upload['type']; + } else { + $mime = wp_check_filetype( $upload['file'] ); + if ( $mime ) { + $type = $mime['type']; + } + } + + $attachment = array( + 'post_title' => wp_basename( $upload['file'] ), + 'post_content' => '', + 'post_type' => 'attachment', + 'post_parent' => $parent_id, + 'post_mime_type' => $type, + 'guid' => $upload['url'], + ); + + // Save the data. + $id = wp_insert_attachment( $attachment, $upload['file'], $parent_id ); + // phpcs:ignore + @wp_update_attachment_metadata( $id, @wp_generate_attachment_metadata( $id, $upload['file'] ) ); + + return $id; + } }