getBody(); } $ip = self::getURL("http://checkip.dyndns.org/"); if($ip !== null && preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', trim(strip_tags($ip->getBody())), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://www.checkip.org/"); if($ip !== null && preg_match('#">([0-9a-fA-F\:\.]*)#', $ip->getBody(), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://checkmyip.org/"); if($ip !== null && preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip->getBody(), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://ifconfig.me/ip"); if($ip !== null && ($addr = trim($ip->getBody())) != ""){ return self::$ip = $addr; } return false; } /** * Returns the machine's internal network IP address. If the machine is not behind a router, this may be the same * as the external IP. * * @throws InternetException */ public static function getInternalIP() : string{ $sock = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); if($sock === false){ throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error()))); } try{ if(!@socket_connect($sock, "8.8.8.8", 65534)){ throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error($sock)))); } if(!@socket_getsockname($sock, $name)){ throw new InternetException("Failed to get internal IP: " . trim(socket_strerror(socket_last_error($sock)))); } return $name; }finally{ socket_close($sock); } } /** * GETs an URL using cURL * NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread. * * @phpstan-template TErrorVar of mixed * * @param int $timeout default 10 * @param string[] $extraHeaders * @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation. * @phpstan-param list $extraHeaders * @phpstan-param TErrorVar $err * @phpstan-param-out TErrorVar|string $err */ public static function getURL(string $page, int $timeout = 10, array $extraHeaders = [], &$err = null) : ?InternetRequestResult{ try{ return self::simpleCurl($page, $timeout, $extraHeaders); }catch(InternetException $ex){ $err = $ex->getMessage(); return null; } } /** * POSTs data to an URL * NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread. * * @phpstan-template TErrorVar of mixed * * @param string[]|string $args * @param string[] $extraHeaders * @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occurred during the operation. * @phpstan-param string|array $args * @phpstan-param list $extraHeaders * @phpstan-param TErrorVar $err * @phpstan-param-out TErrorVar|string $err */ public static function postURL(string $page, array|string $args, int $timeout = 10, array $extraHeaders = [], &$err = null) : ?InternetRequestResult{ try{ return self::simpleCurl($page, $timeout, $extraHeaders, [ CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $args ]); }catch(InternetException $ex){ $err = $ex->getMessage(); return null; } } /** * General cURL shorthand function. * NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread. * * @param float $timeout The maximum connect timeout and timeout in seconds, correct to ms. * @param string[] $extraHeaders extra headers to send as a plain string array * @param array $extraOpts extra CURLOPT_* to set as an [opt => value] map * @param \Closure|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle. * @phpstan-param array $extraOpts * @phpstan-param list $extraHeaders * @phpstan-param (\Closure(\CurlHandle) : void)|null $onSuccess * * @throws InternetException if a cURL error occurs */ public static function simpleCurl(string $page, float $timeout = 10, array $extraHeaders = [], array $extraOpts = [], ?\Closure $onSuccess = null) : InternetRequestResult{ if(!self::$online){ throw new InternetException("Cannot execute web request while offline"); } $ch = curl_init($page); if($ch === false){ throw new InternetException("Unable to create new cURL session"); } curl_setopt_array($ch, $extraOpts + [ CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_FORBID_REUSE => 1, CURLOPT_FRESH_CONNECT => 1, CURLOPT_AUTOREFERER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT_MS => (int) ($timeout * 1000), CURLOPT_TIMEOUT_MS => (int) ($timeout * 1000), CURLOPT_HTTPHEADER => array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 " . VersionInfo::NAME . "/" . VersionInfo::VERSION()->getFullVersion(true)], $extraHeaders), CURLOPT_HEADER => true ]); try{ $raw = curl_exec($ch); if($raw === false){ throw new InternetException(curl_error($ch)); } if(!is_string($raw)) throw new AssumptionFailedError("curl_exec() should return string|false when CURLOPT_RETURNTRANSFER is set"); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $rawHeaders = substr($raw, 0, $headerSize); $body = substr($raw, $headerSize); $headers = []; foreach(explode("\r\n\r\n", $rawHeaders) as $rawHeaderGroup){ $headerGroup = []; foreach(explode("\r\n", $rawHeaderGroup) as $line){ $nameValue = explode(":", $line, 2); if(isset($nameValue[1])){ $headerGroup[trim(strtolower($nameValue[0]))] = trim($nameValue[1]); } } $headers[] = $headerGroup; } if($onSuccess !== null){ $onSuccess($ch); } return new InternetRequestResult($headers, $body, $httpCode); }finally{ curl_close($ch); } } }