max_image_size; if (!$max_size == 0) # unlimited $max_size = null; # Decode data: URLs. if (preg_match('/^data:([^;]{1,100})(;[^;]{1,100})?,(.*)$/', $source, $m)) { $data = base64_decode($m[3]); return $data; } $redirections_limit = 4; $timeout = (int)CONFIG()->http_streaming_timeout; $file = ''; $write_function = function($handle, $data) use (&$file, $max_size) { $file .= $data; if ($max_size && strlen($file) > $max_size) return 0; return strlen($data); }; while (true) { $file = ''; $url = parse_url($source); // $url['host'] = url.normalized_host if ($url['scheme'] != 'http' && $url['scheme'] != 'https') throw new Danbooru\Exception\RuntimeException('SocketError: URL must be HTTP or HTTPS'); # check if the request uri is not percent-encoded // if url.request_uri.match "/[^!*'();:@&=+$,\/?#\[\]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\-_.~%]/" // url.path = Addressable::URI.encode(url.path) // url.query = Addressable::URI.encode(url.query) // end # Addressable doesn't fill in port data if not explicitly given. if (!isset($url['port'])) $url['port'] = $url['scheme'] == 'https' ? 443 : 80; $opts = []; if ($url['scheme'] == 'https') { $opts[CURLOPT_SSL_VERIFYPEER] = false; $opts[CURLOPT_SSL_VERIFYHOST] = false; } if ($timeout) $opts[CURLOPT_TIMEOUT] = $timeout; $opts[CURLOPT_RETURNTRANSFER] = true; $opts[CURLINFO_HEADER_OUT] = true; $opts[CURLOPT_WRITEFUNCTION] = $write_function; $opts[CURLOPT_HTTPHEADER] = [ "User-Agent: " . CONFIG()->app_name . '/' . CONFIG()->version, "Referer: " . $source ]; if (preg_match('/pixiv\.net/', $source)) { $opts[CURLOPT_HTTPHEADER][] = "Referer: http://www.pixiv.net"; # Don't download the small version if (preg_match('~(/img/.+?/.+?)_m.+$~', $source, $m)) { $match = $m[1]; $source = str_replace($match . "_m", $match); } } $ch = curl_init($source); curl_setopt_array($ch, $opts); $res = curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); if ($timeout && $info['total_time'] === (float)$timeout) { throw new Danbooru\Exception\RuntimeException("Request timed out"); } elseif ($info['redirect_url']) { if ($info['redirect_count'] > $redirections_limit) throw new Danbooru\Exception\RuntimeException("Too many redirects"); $source = $info['redirect_url']; } elseif ($info['http_code'] == 200) { if ($max_size) { $len = $info['size_download']; if ($len > $max_size) throw new Danbooru\Exception\RuntimeException("File is too large ($len bytes)"); } if (!$file) throw new Danbooru\Exception\RuntimeException("Response is empty"); return $file; } else { throw new Danbooru\Exception\RuntimeException("HTTP error code: " . $info['http_code']); } } } }