Skip to content

Commit fde7633

Browse files
committed
Fix issue
1 parent 97b16f3 commit fde7633

File tree

5 files changed

+77
-3
lines changed

5 files changed

+77
-3
lines changed

includes/Traits/URL_Utils.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,39 @@ trait URL_Utils {
2323
* @return bool true if the URL is valid, otherwise false.
2424
*/
2525
protected function is_valid_url( string $url ): bool {
26-
if ( filter_var( $url, FILTER_VALIDATE_URL ) !== $url || ! str_starts_with( $url, 'http' ) ) {
26+
// Must start with http or https.
27+
if ( ! str_starts_with( $url, 'http' ) ) {
2728
return false;
2829
}
2930

30-
// Detect duplicated protocol (e.g., "https://http://example.com/").
31+
// Parse the URL to validate its structure.
3132
$parsed_url = wp_parse_url( $url );
3233

33-
if ( isset( $parsed_url['scheme'] ) && str_contains( substr( $url, strlen( $parsed_url['scheme'] ) + 3 ), '://' ) ) {
34+
// wp_parse_url returns false on parse failure.
35+
if ( false === $parsed_url || ! is_array( $parsed_url ) ) {
36+
return false;
37+
}
38+
39+
// Must have a valid scheme and host.
40+
if ( empty( $parsed_url['scheme'] ) || empty( $parsed_url['host'] ) ) {
41+
return false;
42+
}
43+
44+
// Scheme must be http or https.
45+
if ( ! in_array( $parsed_url['scheme'], array( 'http', 'https' ), true ) ) {
46+
return false;
47+
}
48+
49+
// Detect duplicated protocol in the host/path portion (e.g., "https://http://example.com/").
50+
// Only check up to the query string to avoid false positives with URLs in query parameters.
51+
$url_without_query = strtok( $url, '?' );
52+
if ( false !== $url_without_query && str_contains( substr( $url_without_query, strlen( $parsed_url['scheme'] ) + 3 ), '://' ) ) {
53+
return false;
54+
}
55+
56+
// Validate host doesn't contain obviously invalid characters.
57+
// Allow alphanumeric, dots, hyphens, and underscores (for localhost, etc.).
58+
if ( preg_match( '/[^a-z0-9.\-_]/i', $parsed_url['host'] ) ) {
3459
return false;
3560
}
3661

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
/**
3+
* Plugin Name: Test Plugin with Valid PayPal Donate Link
4+
* Plugin URI: https://wordpress.org/plugins/test-plugin/
5+
* Description: Test plugin for valid PayPal donation URL.
6+
* Version: 1.0.0
7+
* Author: plugin-check
8+
* Author URI: https://wordpress.org/plugins/test-plugin/
9+
* License: GPL-2.0+
10+
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
11+
* Text Domain: test-plugin
12+
*/
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== Test Plugin with Valid PayPal Donate Link ===
2+
3+
Contributors: plugin-check
4+
Requires at least: 6.0
5+
Tested up to: 6.1
6+
Requires PHP: 5.6
7+
Stable tag: 1.0.0
8+
License: GPLv2 or later
9+
License URI: https://www.gnu.org/licenses/gpl-2.0.html
10+
Donate Link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&[email protected]&item_name=WordPress%20Plugin%20Donation&return=https://wordpress.org/plugins/my-plugin/
11+
Tags: tag1, testing, security
12+
13+
Here is a short description of the plugin.

tests/phpunit/tests/Checker/Checks/Plugin_Readme_Check_Tests.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,25 @@ public function test_run_with_discouraged_donate_link() {
652652
$this->assertCount( 1, wp_list_filter( $errors['readme.txt'][0][0], array( 'code' => 'readme_invalid_donate_link_domain' ) ) );
653653
}
654654

655+
public function test_run_with_valid_paypal_donate_link() {
656+
$check = new Plugin_Readme_Check();
657+
$check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-plugin-readme-valid-paypal-donate/load.php' );
658+
$check_result = new Check_Result( $check_context );
659+
660+
$check->run( $check_result );
661+
662+
$errors = $check_result->get_errors();
663+
664+
// Should not have invalid donate link error for PayPal URLs with complex query strings.
665+
if ( isset( $errors['readme.txt'] ) && isset( $errors['readme.txt'][0][0] ) ) {
666+
$invalid_donate_link_errors = wp_list_filter( $errors['readme.txt'][0][0], array( 'code' => 'readme_invalid_donate_link' ) );
667+
$this->assertEmpty( $invalid_donate_link_errors, 'PayPal donation URL with complex query string should be recognized as valid' );
668+
} else {
669+
// If no errors at all, that's also fine - the URL is valid.
670+
$this->assertTrue( true );
671+
}
672+
}
673+
655674
public function test_run_language_detection_with_non_english_content() {
656675
$check = new Plugin_Readme_Check();
657676
$check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-plugin-readme-errors-language/load.php' );

tests/phpunit/tests/Traits/URL_Utils_Tests.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public function data_url_items() {
2626
array( 'https://example.com/page.html', true ),
2727
array( 'https://http://example.com/', false ),
2828
array( 'ftp://example.com/file.txt', false ),
29+
// PayPal donation URLs with complex query strings.
30+
array( 'https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&[email protected]&item_name=WordPress%20Plugin%20Donation&return=https://wordpress.org/plugins/my-plugin/', true ),
31+
array( 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&[email protected]&item_name=Support%20My%20Plugin', true ),
32+
array( 'https://paypal.me/username/5USD', true ),
33+
array( 'https://www.paypal.com/donate/?hosted_button_id=123456', true ),
2934
);
3035
}
3136

0 commit comments

Comments
 (0)