rework validateUrl(), refs #1325

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann
2025-04-24 09:56:03 +02:00
parent 76793c8992
commit d9032f3790
2 changed files with 45 additions and 23 deletions

View File

@@ -28,7 +28,6 @@ namespace Froxlor\Validate;
use Exception; use Exception;
use Froxlor\Database\Database; use Froxlor\Database\Database;
use Froxlor\FroxlorLogger; use Froxlor\FroxlorLogger;
use Froxlor\Idna\IdnaWrapper;
use Froxlor\System\IPTools; use Froxlor\System\IPTools;
use Froxlor\UI\Response; use Froxlor\UI\Response;
@@ -63,10 +62,11 @@ class Validate
string $str, string $str,
string $fieldname, string $fieldname,
string $pattern = '', string $pattern = '',
$lng = '', $lng = '',
$emptydefault = [], $emptydefault = [],
bool $throw_exception = false bool $throw_exception = false
) { )
{
if (!is_array($emptydefault)) { if (!is_array($emptydefault)) {
$emptydefault_array = [ $emptydefault_array = [
$emptydefault $emptydefault
@@ -122,14 +122,15 @@ class Validate
*/ */
public static function validate_ip2( public static function validate_ip2(
string $ip, string $ip,
bool $return_bool = false, bool $return_bool = false,
string $lng = 'invalidip', string $lng = 'invalidip',
bool $allow_localhost = false, bool $allow_localhost = false,
bool $allow_priv = false, bool $allow_priv = false,
bool $allow_cidr = false, bool $allow_cidr = false,
bool $cidr_as_netmask = false, bool $cidr_as_netmask = false,
bool $throw_exception = false bool $throw_exception = false
) { )
{
$cidr = ""; $cidr = "";
if ($allow_cidr) { if ($allow_cidr) {
$org_ip = $ip; $org_ip = $ip;
@@ -200,20 +201,34 @@ class Validate
$url = 'http://' . $url; $url = 'http://' . $url;
} }
// needs converting // Parse parts
try { $parts = parse_url($url);
$idna_convert = new IdnaWrapper(); if ($parts === false || !isset($parts['scheme'], $parts['host'])) {
$url = $idna_convert->encode($url);
} catch (Exception $e) {
return false; return false;
} }
if ($allow_private_ip) { // Check allowed schemes
$pattern = '%^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$%iuS'; if (!in_array(strtolower($parts['scheme']), ['http', 'https'], true)) {
} else { return false;
$pattern = '%^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$%iuS';
} }
if (preg_match($pattern, $url)) {
// Check if host is valid domain or valid IP (v4 or v6)
$host = $parts['host'];
if (substr($host, 0, 1) == '[' && substr($host, -1) == ']') {
$host = substr($host, 1, -1);
}
$opts = FILTER_FLAG_IPV4 | FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE;
$opts6 = FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE;
if ($allow_private_ip) {
$opts = FILTER_FLAG_IPV4 | FILTER_FLAG_NO_RES_RANGE;
$opts6 = FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE;
}
if (filter_var($host, FILTER_VALIDATE_IP, $opts)) {
return true;
} elseif (substr($parts['host'], 0, 1) == '[' && substr($parts['host'], -1) == ']' && filter_var($host, FILTER_VALIDATE_IP, $opts6)) {
return true;
} elseif (!preg_match('/^([0-9]{1,3}\.)+[0-9]{1,3}$/', $host) && self::validateDomain($host) !== false) {
return true; return true;
} }
@@ -342,7 +357,8 @@ class Validate
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public static function validateBase64Image(string $base64string) { public static function validateBase64Image(string $base64string)
{
if (!extension_loaded('gd')) { if (!extension_loaded('gd')) {
Response::standardError('phpgdextensionnotavailable', null, true); Response::standardError('phpgdextensionnotavailable', null, true);

View File

@@ -142,6 +142,12 @@ class ValidateTest extends TestCase
$this->assertFalse($result); $this->assertFalse($result);
$result = Validate::validateUrl("172.16.0.1:8080", true); $result = Validate::validateUrl("172.16.0.1:8080", true);
$this->assertTrue($result); $this->assertTrue($result);
$result = Validate::validateUrl("https://xn--frxlr-kuac.de/", true);
$this->assertTrue($result);
$result = Validate::validateUrl("https://2a10:ec2::193:107:51:5/test");
$this->assertFalse($result);
$result = Validate::validateUrl("https://[2a10:ec2::193:107:51:5]");
$this->assertTrue($result);
} }
public function testValidateDomain() public function testValidateDomain()