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\utils\Binary;
use pocketmine\utils\Config;
use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Terminal;
use pocketmine\utils\TextFormat;
@ -2203,7 +2204,7 @@ class Server{
if($report){
$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",
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
"email" => "crash@pocketmine.net",

View File

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

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\scheduler;
use pocketmine\utils\Utils;
use pocketmine\utils\Internet;
/**
* Executes a consecutive list of cURL operations.
@ -55,7 +55,7 @@ class BulkCurlTask extends AsyncTask{
$results = [];
foreach($operations as $op){
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){
$results[] = $e;
}

View File

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

View File

@ -27,7 +27,7 @@ namespace pocketmine\updater;
use pocketmine\scheduler\AsyncTask;
use pocketmine\Server;
use pocketmine\utils\Utils;
use pocketmine\utils\Internet;
class UpdateCheckTask extends AsyncTask{
@ -45,7 +45,7 @@ class UpdateCheckTask extends AsyncTask{
public function onRun(){
$error = "";
$response = Utils::getURL($this->endpoint . "?channel=" . $this->channel, 4, [], $error);
$response = Internet::getURL($this->endpoint . "?channel=" . $this->channel, 4, [], $error);
$this->error = $error;
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;
}
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['status'] !== 'fail'
and date_default_timezone_set($ip_geolocation_data['timezone'])

View File

@ -33,8 +33,6 @@ use pocketmine\ThreadManager;
* Big collection of functions
*/
class Utils{
public static $online = true;
public static $ip = false;
public static $os;
/** @var UUID|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
*
* @return string|bool
*/
public static function getIP(bool $force = false){
if(!Utils::$online){
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;
return Internet::getIP($force);
}
/**
@ -363,8 +331,8 @@ class Utils{
}*/
/**
* 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.
* @deprecated
* @see Internet::getURL()
*
* @param string $page
* @param int $timeout default 10
@ -376,18 +344,12 @@ class Utils{
* @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;
}
return Internet::getURL($page, $timeout, $extraHeaders, $err, $headers, $httpCode);
}
/**
* 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.
* @deprecated
* @see Internet::postURL()
*
* @param string $page
* @param array|string $args
@ -400,22 +362,12 @@ class Utils{
* @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;
}
return Internet::postURL($page, $args, $timeout, $extraHeaders, $err, $headers, $httpCode);
}
/**
* 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.
* @deprecated
* @see Internet::simpleCurl()
*
* @param string $page
* @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
*/
public static function simpleCurl(string $page, $timeout = 10, array $extraHeaders = [], array $extraOpts = [], callable $onSuccess = null){
if(!Utils::$online){
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);
}
return Internet::simpleCurl($page, $timeout, $extraHeaders, $extraOpts, $onSuccess);
}
public static function javaStringHash(string $string) : int{

View File

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