Skip to content

Commit f9f7dc3

Browse files
fix: usage of preg_match_all out variable (#1116)
The feedzy_image_encode was malformating the `$img_url` in case of links like https://heavy.com/wp-content/uploads/2025/05/GettyImages-2172500144.jpg?quality=65&strip=all where $url_tab['query'] was available to process. This was caused because $img_url was used as an out variable for `&$matches` param for `preg_match_all`.
1 parent b45131c commit f9f7dc3

File tree

2 files changed

+135
-13
lines changed

2 files changed

+135
-13
lines changed

includes/abstract/feedzy-rss-feeds-admin-abstract.php

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,9 +1149,10 @@ private function render_content( $sc, $feed, $feed_url, $content = '' ) {
11491149
if ( $feed_title['use_title'] ) {
11501150
$feed_title = ! empty( $feed->get_title() ) ? $feed->get_title() : '';
11511151
$feed_description = ! empty( $feed->get_description() ) ? $feed->get_description() : '';
1152+
$feed_permalink = ! empty( $feed->get_permalink() ) ? $feed->get_permalink() : '';
11521153

11531154
$content .= '<div class="rss_header">';
1154-
$content .= '<h2><a href="' . esc_url( $feed->get_permalink() ) . '" class="rss_title" rel="noopener">' . wp_kses_post( html_entity_decode( $feed_title ) ) . '</a> <span class="rss_description"> ' . wp_kses_post( $feed_description ) . '</span></h2>';
1155+
$content .= '<h2><a href="' . esc_url( $feed_permalink ) . '" class="rss_title" rel="noopener">' . wp_kses_post( html_entity_decode( $feed_title ) ) . '</a> <span class="rss_description"> ' . wp_kses_post( $feed_description ) . '</span></h2>';
11551156
$content .= '</div>';
11561157
}
11571158
$content .= '<ul>';
@@ -1279,7 +1280,7 @@ private function get_feed_title_filter( $feed, $sc, $feed_url ) {
12791280
return array(
12801281
'rss_url' => $feed->get_permalink(),
12811282
'rss_title_class' => 'rss_title',
1282-
'rss_title' => html_entity_decode( $feed->get_title() ),
1283+
'rss_title' => html_entity_decode( ! empty( $feed->get_title() ) ? $feed->get_title() : '' ),
12831284
'rss_description_class' => 'rss_description',
12841285
'rss_description' => $feed->get_description(),
12851286
'rss_classes' => array( $sc['classname'], 'feedzy-' . md5( is_array( $feed_url ) ? implode( ', ', $feed_url ) : $feed_url ) ),
@@ -1887,28 +1888,31 @@ public function feedzy_blacklist_images() {
18871888
}
18881889

18891890
/**
1890-
* Image name encoder and url retrieve if in url param
1891+
* Extracts image URLs from query parameters and sanitizes them.
1892+
*
1893+
* Processes URLs that contain image URLs as query parameters (e.g., proxy or CDN URLs).
1894+
* Supports GIF, JPG, JPEG, PNG, WebP, and AVIF formats.
18911895
*
18921896
* @since 3.0.0
18931897
* @access public
18941898
*
1895-
* @param string $img_url A string containing the image URL.
1899+
* @param string $img_url URL containing either a direct image URL or one embedded in query parameters.
18961900
*
1897-
* @return string
1901+
* @return string Extracted and sanitized image URL, or the original URL if no image found.
18981902
*/
18991903
public function feedzy_image_encode( $img_url ) {
19001904
// Check if img url is set as an URL parameter.
1901-
$url_tab = wp_parse_url( $img_url );
1902-
if ( isset( $url_tab['query'] ) ) {
1903-
preg_match_all( '/(http|https):\/\/[^ ]+(\.gif|\.GIF|\.jpg|\.JPG|\.jpeg|\.JPEG|\.png|\.PNG)/', $url_tab['query'], $img_url );
1904-
if ( isset( $img_url[0][0] ) ) {
1905-
$img_url = $img_url[0][0];
1905+
$parsed_url = wp_parse_url( $img_url );
1906+
if ( isset( $parsed_url['query'] ) ) {
1907+
preg_match_all( '/(http|https):\/\/[^ ]+(\.(gif|jpg|jpeg|png|webp|avif))/i', $parsed_url['query'], $matches );
1908+
if ( isset( $matches[0][0] ) && $this->is_image_url( $matches[0][0] ) ) {
1909+
$img_url = $matches[0][0];
19061910
}
19071911
}
19081912

1909-
$return = apply_filters( 'feedzy_image_encode', esc_url( $img_url ), $img_url );
1910-
do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Changing image URL from %s to %s', $img_url, $return ), 'debug', __FILE__, __LINE__ );
1911-
return $return;
1913+
$filtered_url = apply_filters( 'feedzy_image_encode', esc_url( $img_url ), $img_url );
1914+
do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Changing image URL from %s to %s', $img_url, $filtered_url ), 'debug', __FILE__, __LINE__ );
1915+
return $filtered_url;
19121916
}
19131917

19141918
/**

tests/test-admin-abstract.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,52 @@ public function test_feedzy_retrieve_image_with_enclosure_image() {
6363
$this->assertEquals('https://example.com/image.jpg', $result);
6464
}
6565

66+
/**
67+
* Test feedzy_retrieve_image method with enclosure containing image which has query parameters.
68+
*/
69+
public function test_feedzy_retrieve_image_with_enclosure_image_and_query_params() {
70+
// Create a SimplePie feed with test data
71+
$feed = new SimplePie();
72+
// Reference: https://heavy.com/author/jgbuck/feed/
73+
$feed->set_raw_data('<?xml version="1.0" encoding="UTF-8"?>
74+
<rss version="2.0"
75+
xmlns:content="http://purl.org/rss/1.0/modules/content/"
76+
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
77+
xmlns:dc="http://purl.org/dc/elements/1.1/"
78+
xmlns:atom="http://www.w3.org/2005/Atom"
79+
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
80+
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
81+
82+
xmlns:georss="http://www.georss.org/georss"
83+
xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
84+
xmlns:media="http://search.yahoo.com/mrss/"
85+
>
86+
<channel>
87+
<title>Test Feed</title>
88+
<item>
89+
<title>Test Item</title>
90+
<media:thumbnail url="https://heavy.com/wp-content/uploads/2025/05/GettyImages-2172500144.jpg?quality=65&#038;strip=all" />
91+
<media:content url="https://heavy.com/wp-content/uploads/2025/05/GettyImages-2172500144.jpg?quality=65&#038;strip=all" medium="image" type="image/*">
92+
<media:title type="html">Houston Texans head coach DeMeco Ryans reacts before a game against the Chicago Bears.</media:title>
93+
94+
<media:credit>Getty</media:credit>
95+
</media:content>
96+
</item>
97+
</channel>
98+
</rss>');
99+
$feed->init();
100+
101+
$items = $feed->get_items();
102+
103+
// Check if we have items before accessing
104+
$this->assertNotEmpty($items, 'No items found in feed');
105+
$item = $items[0];
106+
107+
$result = $this->feedzy_abstract->feedzy_retrieve_image($item);
108+
109+
$this->assertEquals('https://heavy.com/wp-content/uploads/2025/05/GettyImages-2172500144.jpg?quality=65&strip=all', $result);
110+
}
111+
66112
/**
67113
* Test feedzy_retrieve_image method with iTunes podcast image.
68114
*/
@@ -506,4 +552,76 @@ public function test_extract_image_from_enclosure_with_media_thumbnail() {
506552
$this->assertEquals('https://example.com/thumb.jpg', $result);
507553
}
508554
}
555+
556+
/**
557+
* Test feedzy_image_encode method with regular image URLs.
558+
*/
559+
public function test_feedzy_image_encode_regular_urls() {
560+
$test_cases = array(
561+
// [input, expected]
562+
['https://example.com/image.jpg', 'https://example.com/image.jpg'],
563+
['https://example.com/simple-image.png', 'https://example.com/simple-image.png'],
564+
['not-a-valid-url', 'http://not-a-valid-url'], // esc_url adds http://
565+
['', ''] // Empty URL
566+
);
567+
568+
foreach ($test_cases as [$input, $expected]) {
569+
$result = $this->feedzy_abstract->feedzy_image_encode($input);
570+
$this->assertEquals($expected, $result, "Failed for URL: $input");
571+
}
572+
}
573+
574+
/**
575+
* Test feedzy_image_encode method with query parameter extraction.
576+
*/
577+
public function test_feedzy_image_encode_query_parameter_extraction() {
578+
$test_cases = array(
579+
// [input_url, expected_result]
580+
['https://example.com/proxy?url=https://cdn.example.com/image.jpg&width=300', 'https://cdn.example.com/image.jpg'],
581+
['https://proxy.example.com/image?src=https://secure.example.com/photo.png', 'https://secure.example.com/photo.png'],
582+
['https://example.com/proxy?url=http://legacy.example.com/photo.gif', 'http://legacy.example.com/photo.gif'],
583+
['https://example.com/proxy?callback=jsonp&url=https://cdn.example.com/uploads/2023/image.jpg&format=json', 'https://cdn.example.com/uploads/2023/image.jpg'],
584+
);
585+
586+
foreach ($test_cases as [$input, $expected]) {
587+
$result = $this->feedzy_abstract->feedzy_image_encode($input);
588+
$this->assertEquals($expected, $result, "Failed for input: $input");
589+
}
590+
}
591+
592+
/**
593+
* Test feedzy_image_encode method with various image extensions.
594+
*/
595+
public function test_feedzy_image_encode_image_extensions() {
596+
$extensions = ['jpeg', 'PNG', 'webp', 'WEBP', 'avif', 'AVIF', 'gif', 'GIF'];
597+
598+
foreach ($extensions as $ext) {
599+
$url = "https://example.com/proxy?url=https://cdn.example.com/image.$ext";
600+
$expected = "https://cdn.example.com/image.$ext";
601+
602+
$result = $this->feedzy_abstract->feedzy_image_encode($url);
603+
$this->assertEquals($expected, $result, "Failed for extension: $ext");
604+
}
605+
}
606+
607+
/**
608+
* Test feedzy_image_encode method with non-image and edge cases.
609+
*/
610+
public function test_feedzy_image_encode_edge_cases() {
611+
$test_cases = array(
612+
// Non-image URL in query - should return original (with & escaped)
613+
['https://example.com/proxy?url=https://example.com/document.pdf&width=300', 'https://example.com/proxy?url=https://example.com/document.pdf&#038;width=300'],
614+
// URL with image separated by spaces (more realistic test case)
615+
['https://example.com/proxy?description=Check this image: https://example.com/image.jpg out', 'https://example.com/image.jpg'],
616+
// Invalid image format in query (with & escaped)
617+
['https://example.com/proxy?url=https://example.com/image&format=jpg', 'https://example.com/proxy?url=https://example.com/image&#038;format=jpg'],
618+
// URL with special characters - this should extract the image
619+
['https://example.com/proxy?url=https://example.com/images/file%20name.jpg', 'https://example.com/images/file%20name.jpg'],
620+
);
621+
622+
foreach ($test_cases as [$input, $expected]) {
623+
$result = $this->feedzy_abstract->feedzy_image_encode($input);
624+
$this->assertEquals($expected, $result, "Failed for input: $input");
625+
}
626+
}
509627
}

0 commit comments

Comments
 (0)