Move Internet-related functions from Utils into their own class (#2324)

- Added `Internet::getIP()`, `Internet::getURL()`, `Internet::postURL()`, and `Internet::simpleCurl()`.
- Deprecated the corresponding functions in `Utils`. Updating to the new functions is as simple as replacing `Utils` with `Internet`, since this doesn't break backwards compatibility.

The deprecations should be catered for by plugin developers. These deprecated redirects will be removed no later than 4.0.0.
This commit is contained in:
Dylan K. Taylor 2018-07-25 15:51:18 +01:00 committed by GitHub
parent 951870e6ec
commit 706c620d04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 211 additions and 117 deletions

View File

@ -99,6 +99,7 @@ use pocketmine\timings\TimingsHandler;
use pocketmine\updater\AutoUpdater; use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Config; use pocketmine\utils\Config;
use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger; use pocketmine\utils\MainLogger;
use pocketmine\utils\Terminal; use pocketmine\utils\Terminal;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
@ -2203,7 +2204,7 @@ class Server{
if($report){ if($report){
$url = ($this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api"; $url = ($this->getProperty("auto-report.use-https", true) ? "https" : "http") . "://" . $this->getProperty("auto-report.host", "crash.pmmp.io") . "/submit/api";
$reply = Utils::postURL($url, [ $reply = Internet::postURL($url, [
"report" => "yes", "report" => "yes",
"name" => $this->getName() . " " . $this->getPocketMineVersion(), "name" => $this->getName() . " " . $this->getPocketMineVersion(),
"email" => "crash@pocketmine.net", "email" => "crash@pocketmine.net",

View File

@ -26,12 +26,13 @@ declare(strict_types=1);
*/ */
namespace pocketmine\network\upnp; namespace pocketmine\network\upnp;
use pocketmine\utils\Internet;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
abstract class UPnP{ abstract class UPnP{
public static function PortForward(int $port) : void{ public static function PortForward(int $port) : void{
if(!Utils::$online){ if(!Internet::$online){
throw new \RuntimeException("Server is offline"); throw new \RuntimeException("Server is offline");
} }
if(Utils::getOS() !== "win"){ if(Utils::getOS() !== "win"){
@ -55,7 +56,7 @@ abstract class UPnP{
} }
public static function RemovePortForward(int $port) : bool{ public static function RemovePortForward(int $port) : bool{
if(!Utils::$online){ if(!Internet::$online){
return false; return false;
} }
if(Utils::getOS() != "win" or !class_exists("COM")){ if(Utils::getOS() != "win" or !class_exists("COM")){

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pocketmine\utils\Utils; use pocketmine\utils\Internet;
/** /**
* Executes a consecutive list of cURL operations. * Executes a consecutive list of cURL operations.
@ -55,7 +55,7 @@ class BulkCurlTask extends AsyncTask{
$results = []; $results = [];
foreach($operations as $op){ foreach($operations as $op){
try{ try{
$results[] = Utils::simpleCurl($op["page"], $op["timeout"] ?? 10, $op["extraHeaders"] ?? [], $op["extraOpts"] ?? []); $results[] = Internet::simpleCurl($op["page"], $op["timeout"] ?? 10, $op["extraHeaders"] ?? [], $op["extraOpts"] ?? []);
}catch(\RuntimeException $e){ }catch(\RuntimeException $e){
$results[] = $e; $results[] = $e;
} }

View File

@ -25,6 +25,7 @@ namespace pocketmine\scheduler;
use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\Internet;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\utils\UUID; use pocketmine\utils\UUID;
use pocketmine\utils\VersionString; use pocketmine\utils\VersionString;
@ -147,7 +148,7 @@ class SendUsageTask extends AsyncTask{
public function onRun(){ public function onRun(){
try{ try{
Utils::postURL($this->endpoint, $this->data, 5, [ Internet::postURL($this->endpoint, $this->data, 5, [
"Content-Type: application/json", "Content-Type: application/json",
"Content-Length: " . strlen($this->data) "Content-Length: " . strlen($this->data)
]); ]);

View File

@ -27,7 +27,7 @@ namespace pocketmine\updater;
use pocketmine\scheduler\AsyncTask; use pocketmine\scheduler\AsyncTask;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\Utils; use pocketmine\utils\Internet;
class UpdateCheckTask extends AsyncTask{ class UpdateCheckTask extends AsyncTask{
@ -45,7 +45,7 @@ class UpdateCheckTask extends AsyncTask{
public function onRun(){ public function onRun(){
$error = ""; $error = "";
$response = Utils::getURL($this->endpoint . "?channel=" . $this->channel, 4, [], $error); $response = Internet::getURL($this->endpoint . "?channel=" . $this->channel, 4, [], $error);
$this->error = $error; $this->error = $error;
if($response !== false){ if($response !== false){

View File

@ -0,0 +1,185 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\utils;
class Internet{
public static $ip = false;
public static $online = true;
/**
* Gets the External IP using an external service, it is cached
*
* @param bool $force default false, force IP check even when cached
*
* @return string|bool
*/
public static function getIP(bool $force = false){
if(!self::$online){
return false;
}elseif(self::$ip !== false and !$force){
return self::$ip;
}
$ip = self::getURL("http://api.ipify.org/");
if($ip !== false){
return self::$ip = $ip;
}
$ip = self::getURL("http://checkip.dyndns.org/");
if($ip !== false and preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', trim(strip_tags($ip)), $matches) > 0){
return self::$ip = $matches[1];
}
$ip = self::getURL("http://www.checkip.org/");
if($ip !== false and preg_match('#">([0-9a-fA-F\:\.]*)</span>#', $ip, $matches) > 0){
return self::$ip = $matches[1];
}
$ip = self::getURL("http://checkmyip.org/");
if($ip !== false and preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
return self::$ip = $matches[1];
}
$ip = self::getURL("http://ifconfig.me/ip");
if($ip !== false and trim($ip) != ""){
return self::$ip = trim($ip);
}
return false;
}
/**
* 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.
*
* @param string $page
* @param int $timeout default 10
* @param array $extraHeaders
* @param string &$err Will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
* @param array[] &$headers
* @param int &$httpCode
*
* @return bool|mixed false if an error occurred, mixed data if successful.
*/
public static function getURL(string $page, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
try{
list($ret, $headers, $httpCode) = self::simpleCurl($page, $timeout, $extraHeaders);
return $ret;
}catch(\RuntimeException $ex){
$err = $ex->getMessage();
return false;
}
}
/**
* 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.
*
* @param string $page
* @param array|string $args
* @param int $timeout
* @param array $extraHeaders
* @param string &$err Will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
* @param array[] &$headers
* @param int &$httpCode
*
* @return bool|mixed false if an error occurred, mixed data if successful.
*/
public static function postURL(string $page, $args, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
try{
list($ret, $headers, $httpCode) = self::simpleCurl($page, $timeout, $extraHeaders, [
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $args
]);
return $ret;
}catch(\RuntimeException $ex){
$err = $ex->getMessage();
return false;
}
}
/**
* 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 string $page
* @param float|int $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 callable|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle.
*
* @return array a plain array of three [result body : string, headers : array[], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values
*
* @throws \RuntimeException if a cURL error occurs
*/
public static function simpleCurl(string $page, $timeout = 10, array $extraHeaders = [], array $extraOpts = [], callable $onSuccess = null){
if(!self::$online){
throw new \RuntimeException("Cannot execute web request while offline");
}
$ch = curl_init($page);
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 " . \pocketmine\NAME], $extraHeaders),
CURLOPT_HEADER => true
]);
try{
$raw = curl_exec($ch);
$error = curl_error($ch);
if($error !== ""){
throw new \RuntimeException($error);
}
$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 [$body, $headers, $httpCode];
}finally{
curl_close($ch);
}
}
}

View File

@ -61,7 +61,7 @@ abstract class Timezone{
break; break;
} }
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value. if($response = Internet::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
and $ip_geolocation_data = json_decode($response, true) and $ip_geolocation_data = json_decode($response, true)
and $ip_geolocation_data['status'] !== 'fail' and $ip_geolocation_data['status'] !== 'fail'
and date_default_timezone_set($ip_geolocation_data['timezone']) and date_default_timezone_set($ip_geolocation_data['timezone'])

View File

@ -33,8 +33,6 @@ use pocketmine\ThreadManager;
* Big collection of functions * Big collection of functions
*/ */
class Utils{ class Utils{
public static $online = true;
public static $ip = false;
public static $os; public static $os;
/** @var UUID|null */ /** @var UUID|null */
private static $serverUniqueId = null; private static $serverUniqueId = null;
@ -123,45 +121,15 @@ class Utils{
} }
/** /**
* Gets the External IP using an external service, it is cached * @deprecated
* @see Internet::getIP()
* *
* @param bool $force default false, force IP check even when cached * @param bool $force default false, force IP check even when cached
* *
* @return string|bool * @return string|bool
*/ */
public static function getIP(bool $force = false){ public static function getIP(bool $force = false){
if(!Utils::$online){ return Internet::getIP($force);
return false;
}elseif(Utils::$ip !== false and !$force){
return Utils::$ip;
}
$ip = Utils::getURL("http://api.ipify.org/");
if($ip !== false){
return Utils::$ip = $ip;
}
$ip = Utils::getURL("http://checkip.dyndns.org/");
if($ip !== false and preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', trim(strip_tags($ip)), $matches) > 0){
return Utils::$ip = $matches[1];
}
$ip = Utils::getURL("http://www.checkip.org/");
if($ip !== false and preg_match('#">([0-9a-fA-F\:\.]*)</span>#', $ip, $matches) > 0){
return Utils::$ip = $matches[1];
}
$ip = Utils::getURL("http://checkmyip.org/");
if($ip !== false and preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
return Utils::$ip = $matches[1];
}
$ip = Utils::getURL("http://ifconfig.me/ip");
if($ip !== false and trim($ip) != ""){
return Utils::$ip = trim($ip);
}
return false;
} }
/** /**
@ -363,8 +331,8 @@ class Utils{
}*/ }*/
/** /**
* GETs an URL using cURL * @deprecated
* 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. * @see Internet::getURL()
* *
* @param string $page * @param string $page
* @param int $timeout default 10 * @param int $timeout default 10
@ -376,18 +344,12 @@ class Utils{
* @return bool|mixed false if an error occurred, mixed data if successful. * @return bool|mixed false if an error occurred, mixed data if successful.
*/ */
public static function getURL(string $page, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){ public static function getURL(string $page, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
try{ return Internet::getURL($page, $timeout, $extraHeaders, $err, $headers, $httpCode);
list($ret, $headers, $httpCode) = self::simpleCurl($page, $timeout, $extraHeaders);
return $ret;
}catch(\RuntimeException $ex){
$err = $ex->getMessage();
return false;
}
} }
/** /**
* POSTs data to an URL * @deprecated
* 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. * @see Internet::postURL()
* *
* @param string $page * @param string $page
* @param array|string $args * @param array|string $args
@ -400,22 +362,12 @@ class Utils{
* @return bool|mixed false if an error occurred, mixed data if successful. * @return bool|mixed false if an error occurred, mixed data if successful.
*/ */
public static function postURL(string $page, $args, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){ public static function postURL(string $page, $args, int $timeout = 10, array $extraHeaders = [], &$err = null, &$headers = null, &$httpCode = null){
try{ return Internet::postURL($page, $args, $timeout, $extraHeaders, $err, $headers, $httpCode);
list($ret, $headers, $httpCode) = self::simpleCurl($page, $timeout, $extraHeaders, [
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $args
]);
return $ret;
}catch(\RuntimeException $ex){
$err = $ex->getMessage();
return false;
}
} }
/** /**
* General cURL shorthand function. * @deprecated
* 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. * @see Internet::simpleCurl()
* *
* @param string $page * @param string $page
* @param float|int $timeout The maximum connect timeout and timeout in seconds, correct to ms. * @param float|int $timeout The maximum connect timeout and timeout in seconds, correct to ms.
@ -428,53 +380,7 @@ class Utils{
* @throws \RuntimeException if a cURL error occurs * @throws \RuntimeException if a cURL error occurs
*/ */
public static function simpleCurl(string $page, $timeout = 10, array $extraHeaders = [], array $extraOpts = [], callable $onSuccess = null){ public static function simpleCurl(string $page, $timeout = 10, array $extraHeaders = [], array $extraOpts = [], callable $onSuccess = null){
if(!Utils::$online){ return Internet::simpleCurl($page, $timeout, $extraHeaders, $extraOpts, $onSuccess);
throw new \RuntimeException("Server is offline");
}
$ch = curl_init($page);
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 " . \pocketmine\NAME], $extraHeaders),
CURLOPT_HEADER => true
]);
try{
$raw = curl_exec($ch);
$error = curl_error($ch);
if($error !== ""){
throw new \RuntimeException($error);
}
$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 [$body, $headers, $httpCode];
}finally{
curl_close($ch);
}
} }
public static function javaStringHash(string $string) : int{ public static function javaStringHash(string $string) : int{

View File

@ -29,7 +29,7 @@ namespace pocketmine\wizard;
use pocketmine\lang\BaseLang; use pocketmine\lang\BaseLang;
use pocketmine\utils\Config; use pocketmine\utils\Config;
use pocketmine\utils\Utils; use pocketmine\utils\Internet;
class SetupWizard{ class SetupWizard{
public const DEFAULT_NAME = \pocketmine\NAME . " Server"; public const DEFAULT_NAME = \pocketmine\NAME . " Server";
@ -205,7 +205,7 @@ LICENSE;
$this->message($this->lang->get("ip_get")); $this->message($this->lang->get("ip_get"));
$externalIP = Utils::getIP(); $externalIP = Internet::getIP();
if($externalIP === false){ if($externalIP === false){
$externalIP = "unknown (server offline)"; $externalIP = "unknown (server offline)";
} }