diff --git a/adminer/include/adminer.inc.php b/adminer/include/adminer.inc.php
index 2e2c41f9..82315054 100644
--- a/adminer/include/adminer.inc.php
+++ b/adminer/include/adminer.inc.php
@@ -293,7 +293,7 @@ class Adminer {
if (preg_match('~json~', $field["type"])) {
$return = "$return
";
}
- return ($link ? "$return" : $return);
+ return ($link ? "$return" : $return);
}
/** Value conversion used in select and edit
diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php
index 5e12d44b..34617afa 100644
--- a/adminer/include/editing.inc.php
+++ b/adminer/include/editing.inc.php
@@ -72,7 +72,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
$link .= "&where" . urlencode("[" . bracket_escape($col) . "]") . "=" . urlencode($row[$j]);
}
}
- } elseif (is_url($val)) {
+ } elseif (is_web_url($val)) {
$link = $val;
}
if ($val === null) {
@@ -86,7 +86,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
}
}
if ($link) {
- $val = "$val";
+ $val = "$val";
}
echo "
$val";
}
diff --git a/adminer/include/functions.inc.php b/adminer/include/functions.inc.php
index aa3b3678..d259f761 100644
--- a/adminer/include/functions.inc.php
+++ b/adminer/include/functions.inc.php
@@ -1250,7 +1250,7 @@ function select_value($val, $link, $field, $text_length) {
if (is_mail($val)) {
$link = "mailto:$val";
}
- if (is_url($val)) {
+ if (is_web_url($val)) {
$link = $val; // IE 11 and all modern browsers hide referrer
}
}
@@ -1271,20 +1271,32 @@ function select_value($val, $link, $field, $text_length) {
* @param string
* @return bool
*/
-function is_mail($email) {
- $atom = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]'; // characters of local-name
- $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component
- $pattern = "$atom+(\\.$atom+)*@($domain?\\.)+$domain";
- return is_string($email) && preg_match("(^$pattern(,\\s*$pattern)*\$)i", $email);
+function is_mail($value) {
+ return is_string($value) && filter_var($value, FILTER_VALIDATE_EMAIL);
}
-/** Check whether the string is URL address
+/** Check whether the string is web URL address
* @param string
* @return bool
*/
-function is_url($string) {
- $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // one domain component //! IDN
- return preg_match("~^(https?)://($domain?\\.)+$domain(:\\d+)?(/.*)?(\\?.*)?(#.*)?\$~i", $string); //! restrict path, query and fragment characters
+function is_web_url($value) {
+ if (!is_string($value) || !preg_match('~^https?://~i', $value)) {
+ return false;
+ }
+
+ $components = parse_url($value);
+ if (!$components) {
+ return false;
+ }
+
+ // Encode URL path. If path was encoded already, it will be encoded twice, but we are OK with that.
+ $encodedParts = array_map('urlencode', explode('/', $components['path']));
+ $url = str_replace($components['path'], implode('/', $encodedParts), $value);
+
+ parse_str($components['query'], $params);
+ $url = str_replace($components['query'], http_build_query($params), $url);
+
+ return (bool)filter_var($url, FILTER_VALIDATE_URL);
}
/** Check if field should be shortened
diff --git a/changes.txt b/changes.txt
index 5bdfc672..997fd102 100644
--- a/changes.txt
+++ b/changes.txt
@@ -6,6 +6,7 @@ Adminer 4.9.0-dev:
- Elasticsearch 5: Make unusable driver usable again, move it to plugins.
- Add new Elasticsearch 7 driver.
- Set saving to file as a default export option.
+- Improve URL and email detection.
- Update composer.json.
Adminer 4.8.2 (released 2024-03-16):
diff --git a/editor/include/adminer.inc.php b/editor/include/adminer.inc.php
index e8fed7ac..1198f2f0 100644
--- a/editor/include/adminer.inc.php
+++ b/editor/include/adminer.inc.php
@@ -202,7 +202,7 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5
$return = (preg_match('~^(1|t|true|y|yes|on)$~i', $val) ? lang('yes') : lang('no'));
}
if ($link) {
- $return = "$return";
+ $return = "$return";
}
if (!$link && !like_bool($field) && preg_match(number_type(), $field["type"])) {
$return = " $return "; // Firefox doesn't support
|