You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.9 KiB
PHP
164 lines
4.9 KiB
PHP
<?php
|
|
$REGEX_JOIN_LINK = (function(){
|
|
// See https://github.com/oxen-io/session-pysogs/blob/dev/administration.md
|
|
$protocol = 'https?:';
|
|
$hostname = '[^\/]+';
|
|
$room_name = '[0-9A-Za-z-_]+';
|
|
$public_key = '[[:xdigit:]]{64}';
|
|
// Use pipe delimiter for regex to avoid escaping slashes.
|
|
return "|$protocol//$hostname/$room_name\?public_key=$public_key|i";
|
|
})();
|
|
|
|
/**
|
|
* @param CommunityServer[] $servers
|
|
*/
|
|
function count_rooms($servers) {
|
|
$rooms_total = 0;
|
|
foreach ($servers as $server) {
|
|
$rooms_total += count($server->rooms);
|
|
}
|
|
return $rooms_total;
|
|
}
|
|
|
|
function truncate($url, $len) {
|
|
return (strlen($url) > $len + 3)
|
|
? substr($url, 0, $len).'...'
|
|
: $url;
|
|
}
|
|
|
|
/*
|
|
* Helper function for reduce_servers
|
|
*/
|
|
function url_is_reachable($url, $retries = 4) {
|
|
$retcode = curl_get_response_downgrade(
|
|
$url, retries: $retries,
|
|
curlopts: [CURLOPT_NOBODY => true], stop_on_codes: [404]
|
|
)[0];
|
|
return $retcode != 0 && floor($retcode / 100) != 5 ;
|
|
}
|
|
|
|
|
|
function curl_get_contents_downgrade(string $url, $retries = 4, $stop_on_codes = [404]) {
|
|
list($retcode, $content, $downgrade) = curl_get_response_downgrade($url, $retries, $stop_on_codes);
|
|
return [$retcode == 200 ? $content : null, $downgrade];
|
|
}
|
|
|
|
/**
|
|
* file_get_contents alternative that circumvents flaky routing to Chinese servers
|
|
*/
|
|
function curl_get_contents(string $url, $retries = 4, $stop_on_codes = [404]) {
|
|
return curl_get_response($url, retries: $retries, stop_on_codes: $stop_on_codes)[1];
|
|
}
|
|
|
|
function curl_get_response_downgrade(
|
|
string $url, $retries = 4, $stop_on_codes = [404], $curlopts = []
|
|
) {
|
|
$scheme = parse_url($url, PHP_URL_SCHEME);
|
|
if ($scheme == "https") {
|
|
list($retcode, $content) = curl_get_response($url, floor($retries / 2), $stop_on_codes, $curlopts);
|
|
if ($retcode == 200) return [$retcode, $content, false];
|
|
log_debug("Downgrading to HTTP");
|
|
list($retcode, $content) = curl_get_response(
|
|
substr_replace($url, "http:", 0, strlen("https:")),
|
|
ceil($retries / 2),
|
|
$stop_on_codes, $curlopts
|
|
);
|
|
return [$retcode, $content, true];
|
|
} else {
|
|
list($retcode, $content) = curl_get_response($url, $retries, $stop_on_codes, $curlopts);
|
|
return [$retcode, $content, false];
|
|
}
|
|
}
|
|
|
|
// Low default retries value so this doesn't run for 30 minutes
|
|
// FIXME: Does not seem to handle 308's, behaviour not transparent.
|
|
// TODO: Parallelize & use in CommunityServer::poll_reachable()
|
|
function curl_get_response(string $url, $retries, $stop_on_codes = [404], $curlopts = []) {
|
|
// use separate timeouts to reliably get data from Chinese server with repeated tries
|
|
$connecttimeout = 2; // wait at most X seconds to connect
|
|
$timeout = 3; // can't take longer than X seconds for the whole curl process
|
|
$sleep = 2; // sleep between tries in seconds
|
|
// takes at most ($timeout + $sleep) * $retries seconds
|
|
|
|
$contents = false;
|
|
$retcode = -1;
|
|
|
|
for ($counter = 1; $counter <= $retries; $counter++) {
|
|
$curl = curl_init($url);
|
|
|
|
// curl_setopt($curl, CURLOPT_VERBOSE, true);
|
|
|
|
curl_setopt($curl, CURLOPT_AUTOREFERER, true);
|
|
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
|
|
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $connecttimeout);
|
|
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
|
|
|
foreach ($curlopts as $opt => $val) curl_setopt($curl, $opt, $val);
|
|
|
|
$contents = curl_exec($curl);
|
|
$retcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
|
|
curl_close($curl);
|
|
|
|
log_debug("Attempt #" . $counter . " for " . $url . " returned code " . $retcode . ".");
|
|
if ($contents != null || $retcode == 200 || in_array($retcode, $stop_on_codes)) break;
|
|
sleep($sleep);
|
|
}
|
|
|
|
return [$retcode, $retcode == 200 ? $contents : false];
|
|
}
|
|
|
|
/**
|
|
* Returns the scheme, hostname and optional port of a URL.
|
|
*/
|
|
function url_get_base(string $url, bool $include_scheme = true) {
|
|
$url_components = parse_url($url);
|
|
$scheme = $url_components['scheme'];
|
|
$host = $url_components['host'];
|
|
|
|
if (isset($url_components['port'])) {
|
|
$port = $url_components['port'];
|
|
$host .= ":$port";
|
|
}
|
|
|
|
return $include_scheme ? "$scheme://$host" : $host;
|
|
}
|
|
|
|
/**
|
|
* Extracts the room token from a join URL.
|
|
*/
|
|
function url_get_token(string $join_url) {
|
|
$token = parse_url($join_url)['path'];
|
|
return str_replace("/", "", $token);
|
|
}
|
|
|
|
|
|
/**
|
|
* Extracts join links that match $REGEX_JOIN_LINK.
|
|
* @return string[] Sorted array of unique server join links.
|
|
*/
|
|
function parse_join_links($html){
|
|
global $REGEX_JOIN_LINK;
|
|
preg_match_all($REGEX_JOIN_LINK, $html, $match_result);
|
|
$links = $match_result[0];
|
|
sort($links);
|
|
$links = array_unique($links);
|
|
return $links;
|
|
}
|
|
|
|
/**
|
|
* Convert special characters to html entities.
|
|
*/
|
|
function html_sanitize(
|
|
string $str, int $flags = ENT_QUOTES|ENT_SUBSTITUTE,
|
|
?string $encoding = null, bool $double_encode = true
|
|
) {
|
|
if ($str == "") {
|
|
return "";
|
|
}
|
|
return htmlspecialchars($str, $flags, $encoding, $double_encode);
|
|
}
|
|
?>
|