summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2020-09-17 16:17:33 +0300
committerAndrew Dolgov <[email protected]>2020-09-17 16:17:33 +0300
commitc25edd00243893615b63994e761a05445f7b5fe7 (patch)
treeafac863729c8e5de5ca9ab03e616ba4b8aadb860 /include
parent27e695436fd7594b515a3d01babbf570f179cada (diff)
fetch_file_contents: validate effective URL (after redirects) without CURL
Diffstat (limited to 'include')
-rw-r--r--include/functions.php58
1 files changed, 57 insertions, 1 deletions
diff --git a/include/functions.php b/include/functions.php
index 122e86b3e..fc3a60f31 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -441,7 +441,21 @@
$old_error = error_get_last();
- $fetch_effective_url = $url;
+ $fetch_effective_url = resolve_redirects($url, $timeout ? $timeout : FILE_FETCH_CONNECT_TIMEOUT);
+
+ if (!validate_url($fetch_effective_url)) {
+ $fetch_last_error = "URL hostname received after redirection failed to validate.";
+
+ return false;
+ }
+
+ $fetch_effective_ip_addr = gethostbyname(parse_url($fetch_effective_url, PHP_URL_HOST));
+
+ if (!$fetch_effective_ip_addr || strpos($fetch_effective_ip_addr, "127.") === 0) {
+ $fetch_last_error = "URL hostname received after redirection failed to resolve or resolved to a loopback address ($fetch_effective_ip_addr)";
+
+ return false;
+ }
$data = @file_get_contents($url, false, $context);
@@ -1984,3 +1998,45 @@
return $url;
}
+
+ function resolve_redirects($url, $timeout, $nest = 0) {
+
+ // too many redirects
+ if ($nest > 10)
+ return false;
+
+ $context_options = array(
+ 'http' => array(
+ 'header' => array(
+ 'Connection: close'
+ ),
+ 'method' => 'HEAD',
+ 'timeout' => $timeout,
+ 'protocol_version'=> 1.1)
+ );
+
+ if (defined('_HTTP_PROXY')) {
+ $context_options['http']['request_fulluri'] = true;
+ $context_options['http']['proxy'] = _HTTP_PROXY;
+ }
+
+ $context = stream_context_create($context_options);
+ $headers = get_headers($url, 0, $context);
+
+ if (is_array($headers)) {
+ $headers = array_reverse($headers); // last one is the correct one
+
+ foreach($headers as $header) {
+ if (stripos($header, 'Location:') === 0) {
+ $url = rewrite_relative_url($url, trim(substr($header, strlen('Location:'))));
+
+ return resolve_redirects($url, $timeout, $nest + 1);
+ }
+ }
+
+ return $url;
+ }
+
+ // request failed?
+ return false;
+ }