D:\host\albaziltold\src\NetUtil.php
<?php
namespace Profis\util\NetUtil;
use ErrorException;
use stdClass;
/**
* Description of NetUtil
*/
class NetUtil {
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
const METHOD_DELETE = 'DELETE';
/** (type: boolean)*/
const OPT_VERIFY_SSL = 'VERIFY_SSL';
/** (type: boolean)*/
const OPT_FOLLOW_LOCATION = 'FOLLOW_LOCATION';
/** (type: string)*/
const OPT_USER_AGENT = 'USER_AGENT';
/** (type: boolean)*/
const OPT_IGNORE_STATUS_CODE = 'IGNORE_STATUS_CODE';
/** (type: int)*/
const OPT_CONNECTION_TIMEOUT = 'CONNECTION_TIMEOUT';
/** (type: int)*/
const OPT_TIMEOUT = 'OPT_TIMEOUT';
/** (type: string)*/
const OPT_TO_FILE = 'TO_FILE';
/** (type: resource)*/
const OPT_TO_FILE_HANDLE = 'TO_FILE_HANDLE';
/** (type: boolean)*/
const OPT_PARAMS_AS_ARRAY = 'PARAMS_AS_ARRAY';
/** (type: boolean)*/
const OPT_GET_HEADERS = 'GET_HEADERS';
/** (type: boolean)*/
const OPT_NOBODY = 'NOBODY';
/** (type: boolean)*/
const OPT_ALLOW_CUSTOM_METHOD = 'ALLOW_CUSTOM_METHOD';
/** (type: boolean)*/
const OPT_RESOLVE_IPV4 = 'RESOLVE_IPV4';
/** (type: int) */
const OPT_AUTH_METHOD = 'AUTH_METHOD';
/** (type: string) */
const OPT_AUTH_USER = 'AUTH_USER';
/** (type: string) */
const OPT_AUTH_PASSWORD = 'AUTH_PASSWORD';
const AUTH_METHOD_BASIC = CURLAUTH_BASIC;
/**
* Make HTTP request to URL
* @param string $url URL to request
* @param array|string $params query of form parameters depending on method.
* @param string $method request method (one of METHOD_* constants)
* @param string[] $headers custom headers for request
* @param array $options key value pair array of additional options (available keys are OPT_* constants)
* @return stdClass return format { statuCode: ..., url: ..., headers: ..., body: ... }
* @throws ErrorException
*/
public static function request($url, $params = array(), $method = self::METHOD_GET, array $headers = array(), array $options = array()) {
$finalUrl = ''.$url;
$ch = curl_init();
$opts = array();
if ($method == self::METHOD_GET) {
$opts[CURLOPT_HTTPGET] = 1;
if (!empty($params)) {
$urlInfo = parse_url($finalUrl);
$prms = array();
if (isset($urlInfo['query'])) parse_str($urlInfo['query'], $prms);
$userpass = ((isset($urlInfo['user']) && $urlInfo['user']) ? (
$urlInfo['user'].
((isset($urlInfo['pass']) && $urlInfo['pass']) ? (':'.$urlInfo['pass']) : '')
) : '');
$finalUrl = ((isset($urlInfo['scheme']) && $urlInfo['scheme']) ? $urlInfo['scheme'] : 'http').'://'.
($userpass ? ($userpass.'@') : '').
((isset($urlInfo['host']) && $urlInfo['host']) ? $urlInfo['host'] : 'localhost').
((isset($urlInfo['port']) && $urlInfo['port'] && $urlInfo['port'] != 80) ? (':'.$urlInfo['port']) : '').
((isset($urlInfo['path']) && $urlInfo['path']) ? $urlInfo['path'] : '/').
'?'.http_build_query(array_merge($prms, $params));
}
} else if ($method == self::METHOD_POST || $method == self::METHOD_PUT) {
if ($method == self::METHOD_POST) $opts[CURLOPT_POST] = 1;
if ($method == self::METHOD_PUT) $opts[CURLOPT_CUSTOMREQUEST] = $method;
$opts[CURLOPT_POSTFIELDS] = (isset($options[self::OPT_PARAMS_AS_ARRAY]) && $options[self::OPT_PARAMS_AS_ARRAY])
? $params : http_build_query($params);
} else if (isset($options[self::OPT_ALLOW_CUSTOM_METHOD]) && $options[self::OPT_ALLOW_CUSTOM_METHOD]) {
$opts[CURLOPT_CUSTOMREQUEST] = $method;
} else {
throw new ErrorException('Unrecognized method '.$method);
}
$getHeaders = isset($options[self::OPT_GET_HEADERS]) && $options[self::OPT_GET_HEADERS];
$noBody = isset($options[self::OPT_NOBODY]) && $options[self::OPT_NOBODY];
$opts[CURLOPT_URL] = str_replace(' ', '%20', $finalUrl);
$opts[CURLOPT_RETURNTRANSFER] = true;
if ($noBody) $opts[CURLOPT_NOBODY] = true;
if ($getHeaders) $opts[CURLOPT_HEADER] = true;
if (isset($options[self::OPT_TO_FILE_HANDLE]) && $options[self::OPT_TO_FILE_HANDLE] !== false) {
$opts[CURLOPT_FILE] = $options[self::OPT_TO_FILE_HANDLE];
} else if (isset($options[self::OPT_TO_FILE]) && $options[self::OPT_TO_FILE]) {
if ($options[self::OPT_TO_FILE] == 'php://output') {
// Note: using fopen on this stream fails with cURL.
unset($opts[CURLOPT_RETURNTRANSFER]);
} else if (($fileHandle = fopen($options[self::OPT_TO_FILE], 'wb')) !== false) {
$opts[CURLOPT_FILE] = $fileHandle;
}
}
if (isset($options[self::OPT_RESOLVE_IPV4]) && $options[self::OPT_RESOLVE_IPV4] && defined('CURLOPT_IPRESOLVE')) {
$opts[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
}
$opts[CURLOPT_CONNECTTIMEOUT] = (isset($options[self::OPT_CONNECTION_TIMEOUT]) ? intval($options[self::OPT_CONNECTION_TIMEOUT]) : 300);
if (isset($options[self::OPT_TIMEOUT])) $opts[CURLOPT_TIMEOUT] = intval($options[self::OPT_TIMEOUT]);
$opts[CURLOPT_USERAGENT] = (isset($options[self::OPT_USER_AGENT]) ? $options[self::OPT_USER_AGENT] : 'Mozilla/5.0 (compatible; cURL)');
$headerMap = array();
foreach ($headers as $header) {
list($headerName) = explode(': ', $header, 2);
if ($headerName) $headerMap[strtolower(trim($headerName))] = 1;
}
$headerArr = array();
if (!isset($headerMap['accept'])) $headerArr[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
if (!isset($headerMap['connection'])) $headerArr[] = 'Connection: Close';
$opts[CURLOPT_HTTPHEADER] = array_merge($headerArr, $headers);
$opts[CURLOPT_SSL_VERIFYPEER] = (isset($options[self::OPT_VERIFY_SSL]) ? ($options[self::OPT_VERIFY_SSL] ? true : false) : false);
$opts[CURLOPT_SSL_VERIFYHOST] = (isset($options[self::OPT_VERIFY_SSL]) ? ($options[self::OPT_VERIFY_SSL] ? 2 : false) : false);
if (isset($options[self::OPT_FOLLOW_LOCATION]) && $options[self::OPT_FOLLOW_LOCATION]) {
$opts[CURLOPT_FOLLOWLOCATION] = true;
$opts[CURLOPT_AUTOREFERER] = true;
$opts[CURLOPT_MAXREDIRS] = 3;
} else {
$opts[CURLOPT_FOLLOWLOCATION] = false;
$opts[CURLOPT_AUTOREFERER] = false;
}
if (isset($options[self::OPT_AUTH_METHOD]))
$opts[CURLOPT_HTTPAUTH] = $options[self::OPT_AUTH_METHOD];
if (isset($options[self::OPT_AUTH_USER]) || isset($options[self::OPT_AUTH_PASSWORD]))
$opts[CURLOPT_USERPWD] = (isset($options[self::OPT_AUTH_USER]) ?$options[self::OPT_AUTH_USER] : "") . ":" . (isset($options[self::OPT_AUTH_PASSWORD]) ?$options[self::OPT_AUTH_PASSWORD] : "");
curl_setopt_array($ch, $opts);
$rdata = curl_exec($ch);
if ($getHeaders) {
if ($noBody) {
$headersRaw = $rdata; $r = null;
} else {
$parts = explode("\r\n\r\n", $rdata, 2);
if (count($parts) > 1) {
$headersRaw = $parts[0];
$r = $parts[1];
} else {
$headersRaw = '';
$r = $parts[0];
}
}
$h = array(); $headerFirst = true;
$headersList = explode("\r\n", $headersRaw);
foreach ($headersList as $headerRaw) {
if (!$headerRaw) continue;
if ($headerFirst) {
$headerFirst = false;
list($hProto, $hStatus) = explode(' ', $headerRaw, 3);
$h['_proto_'] = $hProto;
$h['_status_'] = intval($hStatus);
continue;
}
list($headerKey, $headerVal) = explode(': ', $headerRaw, 2);
if (!$headerKey) continue;
$h[strtolower($headerKey)] = $headerVal;
}
} else {
$h = null; $r = $rdata;
}
$errNo = curl_errno($ch);
$errMsg = curl_error($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if (isset($fileHandle) && $fileHandle !== false) fclose($fileHandle);
if ($errNo) throw new ErrorException($errMsg, $errNo);
if (!isset($options[self::OPT_IGNORE_STATUS_CODE]) || !$options[self::OPT_IGNORE_STATUS_CODE]) {
if ($status != 200) throw new ErrorException('Status code '.$status);
}
return (object) array('statusCode' => $status, 'url' => $finalUrl, 'headers' => $h, 'body' => $r);
}
/**
* Download file from URL and save to file.
* @param string $url URL to download from.
* @param string $targetPath path to save downloaded file.
* @param array $params query of form parameters depending on method.
* @param string $method request method (one of METHOD_* constants).
* @param string[] $headers custom headers for request.
* @param array $options key value pair array of additional options (available keys are OPT_* constants).
* @return stdClass return format { statuCode: ..., url: ..., headers: ..., body: ... }
* @throws ErrorException
*/
public static function download($url, $targetPath, array $params = array(), $method = self::METHOD_GET, array $headers = array(), array $options = array()) {
if (!is_array($options)) $options = array();
if ($targetPath) $options[self::OPT_TO_FILE] = $targetPath;
return self::request($url, $params, $method, $headers, $options);
}
/**
* Get contents from URL.
* @param string $url URL to get contents from.
* @param array $params query of form parameters depending on method.
* @param string $method request method (one of METHOD_* constants).
* @param string[] $headers custom headers for request.
* @param array $options key value pair array of additional options (available keys are OPT_* constants).
* @return string|null contents as string or null on error.
*/
public static function getContents($url, array $params = array(), $method = self::METHOD_GET, array $headers = array(), array $options = array()) {
try {
$res = self::request($url, $params, $method, $headers, $options);
if (isset($res->body)) return $res->body;
} catch (ErrorException $ex) {}
return null;
}
/**
* Get headers from URL.
* @param string $url URL to get headers from.
* @param array $params query of form parameters depending on method.
* @param string $method request method (one of METHOD_* constants).
* @param string[] $headers custom headers for request.
* @param array $options key value pair array of additional options (available keys are OPT_* constants).
* @return array|null headers as key value pair array or null on error.
*/
public static function getHeaders($url, array $params = array(), $method = self::METHOD_GET, array $headers = array(), array $options = array()) {
try {
if (!is_array($options)) $options = array();
$options[self::OPT_GET_HEADERS] = true;
$options[self::OPT_NOBODY] = true;
$options[self::OPT_IGNORE_STATUS_CODE] = true;
$res = self::request($url, $params, $method, $headers, $options);
if (isset($res->headers)) return $res->headers;
} catch (ErrorException $ex) {}
return null;
}
/**
* Checks if IP is local (192.168.*.* or 10.*.*.* or 100.[64-127].*.* or 172.[16-32].*.* or fc00::/7 or fe80::/10
* @return boolean
*/
public static function isIpLocal($ip) {
return preg_match('#^(?:192\.168\.|10\.|100\.(?:6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.|172\.(?:1[6-9]|2[0-9]|3[01])\.|f[cd][0-9a-f]{2}:|fe[89ab][0-9a-f]:)#i', $ip);
}
/**
* Checks if IP is loopback (127.* or ::1)
* @return boolean
*/
public static function isIpLoopBack($ip) {
return preg_match('#^(?:127\\..*|::1)$#', $ip);
}
private static function isIpBetween($ip, $ipStart, $ipEnd) {
$ipP = explode('.', $ip);
$ipSP = explode('.', $ipStart);
$ipEP = explode('.', $ipEnd);
if (count($ipP) != 4 || count($ipSP) != 4 || count($ipEP) != 4)
return false;
return ($ipP[0] > $ipSP[0]
|| $ipP[0] == $ipSP[0] && $ipP[1] > $ipSP[1]
|| $ipP[0] == $ipSP[0] && $ipP[1] == $ipSP[1] && $ipP[2] > $ipSP[2]
|| $ipP[0] == $ipSP[0] && $ipP[1] == $ipSP[1] && $ipP[2] == $ipSP[2] && $ipP[3] > $ipSP[3])
&& ($ipP[0] < $ipEP[0]
|| $ipP[0] == $ipEP[0] && $ipP[1] < $ipEP[1]
|| $ipP[0] == $ipEP[0] && $ipP[1] == $ipEP[1] && $ipP[2] < $ipEP[2]
|| $ipP[0] == $ipEP[0] && $ipP[1] == $ipEP[1] && $ipP[2] == $ipEP[2] && $ipP[3] < $ipEP[3]);
}
/**
* Checks if IP belongs to CloudFlare
* @see https://www.cloudflare.com/ips/
* @return boolean
*/
public static function isIpCloudflare($ip) {
return self::isIpBetween($ip, '173.245.48.0', '173.245.63.255') // 173.245.48.0/20
|| self::isIpBetween($ip, '103.21.244.0', '103.21.247.255') // 103.21.244.0/22
|| self::isIpBetween($ip, '103.22.200.0', '103.22.203.255') // 103.22.200.0/22
|| self::isIpBetween($ip, '103.31.4.0', '103.31.7.255') // 103.31.4.0/22
|| self::isIpBetween($ip, '141.101.64.0', '141.101.127.255') // 141.101.64.0/18
|| self::isIpBetween($ip, '108.162.192.0', '108.162.255.255') // 108.162.192.0/18
|| self::isIpBetween($ip, '190.93.240.0', '190.93.255.255') // 190.93.240.0/20
|| self::isIpBetween($ip, '188.114.96.0', '188.114.111.255') // 188.114.96.0/20
|| self::isIpBetween($ip, '197.234.240.0', '197.234.243.255') // 197.234.240.0/22
|| self::isIpBetween($ip, '198.41.128.0', '198.41.255.255') // 198.41.128.0/17
|| self::isIpBetween($ip, '162.158.0.0', '162.159.255.255') // 162.158.0.0/15
|| self::isIpBetween($ip, '104.16.0.0', '104.31.255.255') // 104.16.0.0/12
|| self::isIpBetween($ip, '172.64.0.0', '172.71.255.255') // 172.64.0.0/13
|| self::isIpBetween($ip, '131.0.72.0', '131.0.75.255'); // 131.0.72.0/22
}
}