Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
+118
-97
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Http;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -28,20 +28,74 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _Url
|
||||
{
|
||||
/**
|
||||
* @brief Automatically determine the protocol
|
||||
*/
|
||||
const PROTOCOL_AUTOMATIC = 0;
|
||||
|
||||
/**
|
||||
* @brief Use https://
|
||||
*/
|
||||
const PROTOCOL_HTTPS = 1;
|
||||
|
||||
/**
|
||||
* @brief Use http://
|
||||
*/
|
||||
const PROTOCOL_HTTP = 2;
|
||||
|
||||
/**
|
||||
* @brief Use // (protoool-relative)
|
||||
*/
|
||||
const PROTOCOL_RELATIVE = 3;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Scheme component
|
||||
*/
|
||||
const COMPONENT_SCHEME = 'scheme';
|
||||
|
||||
/**
|
||||
* @brief Username component
|
||||
*/
|
||||
const COMPONENT_USERNAME = 'user';
|
||||
|
||||
/**
|
||||
* @brief Password component
|
||||
*/
|
||||
const COMPONENT_PASSWORD = 'pass';
|
||||
|
||||
/**
|
||||
* @brief Host component
|
||||
*/
|
||||
const COMPONENT_HOST = 'host';
|
||||
|
||||
/**
|
||||
* @brief Port component
|
||||
*/
|
||||
const COMPONENT_PORT = 'port';
|
||||
|
||||
/**
|
||||
* @brief Path component
|
||||
*/
|
||||
const COMPONENT_PATH = 'path';
|
||||
|
||||
/**
|
||||
* @brief Querystring component
|
||||
*/
|
||||
const COMPONENT_QUERY = 'query';
|
||||
|
||||
/**
|
||||
* @brief Query string key
|
||||
*/
|
||||
const COMPONENT_QUERY_KEY = 'queryKey';
|
||||
|
||||
/**
|
||||
* @brief Query string value
|
||||
*/
|
||||
const COMPONENT_QUERY_VALUE = 'queryValue';
|
||||
|
||||
/**
|
||||
* @brief Fragment component
|
||||
*/
|
||||
const COMPONENT_FRAGMENT = 'fragment';
|
||||
|
||||
/* !Factory Methods */
|
||||
@@ -89,36 +143,14 @@ class _Url
|
||||
return \IPS\Http\Url\Internal::createInternalFromComponents( 'front', $protocol, $queryString ? 'index.php' : '', $queryString );
|
||||
}
|
||||
/* Admin */
|
||||
elseif ( $base === 'admin' )
|
||||
elseif ( $base === 'admin' or $base === 'admin_redirect' )
|
||||
{
|
||||
/* Front: Never disclose adsess in front pages */
|
||||
if ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation !== 'admin' )
|
||||
{
|
||||
/* If there is a query string (like a link from an error page, pass through the redirector so we don't disclose the location */
|
||||
if ( $queryString )
|
||||
{
|
||||
return \IPS\Http\Url\Internal::createInternalFromComponents( 'front', $protocol, 'index.php', 'app=core&module=system&controller=redirect&do=admin&_data=' . base64_encode( $queryString ) );
|
||||
}
|
||||
/* Or if it's just a normal link like in the user bar, show that */
|
||||
else
|
||||
{
|
||||
return \IPS\Http\Url\Internal::createInternalFromComponents(
|
||||
'admin',
|
||||
$protocol,
|
||||
\IPS\CP_DIRECTORY . '/'
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Within ACP */
|
||||
else
|
||||
{
|
||||
return \IPS\Http\Url\Internal::createInternalFromComponents(
|
||||
'admin',
|
||||
$protocol,
|
||||
\IPS\CP_DIRECTORY . '/',
|
||||
array( 'adsess' => session_id() ) + static::convertQueryAsStringToArray( $queryString )
|
||||
);
|
||||
}
|
||||
return \IPS\Http\Url\Internal::createInternalFromComponents(
|
||||
'admin',
|
||||
$protocol,
|
||||
\IPS\CP_DIRECTORY . '/',
|
||||
static::convertQueryAsStringToArray( $queryString )
|
||||
);
|
||||
}
|
||||
/* None */
|
||||
else
|
||||
@@ -145,7 +177,7 @@ class _Url
|
||||
* @param string $url
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public static function ips( $url )
|
||||
final public static function ips( $url )
|
||||
{
|
||||
return new static( "https://remoteservices.invisionpower.com/{$url}/?version=" . \IPS\Application::getAvailableVersion('core') );
|
||||
}
|
||||
@@ -175,12 +207,12 @@ class _Url
|
||||
$obj->data[ static::COMPONENT_PATH ] = $path;
|
||||
$obj->data[ static::COMPONENT_FRAGMENT ] = $fragment;
|
||||
|
||||
if ( is_array( $query ) )
|
||||
if ( \is_array( $query ) )
|
||||
{
|
||||
$obj->data[ static::COMPONENT_QUERY ] = static::convertQueryAsArrayToString( $query );
|
||||
$obj->queryString = $query;
|
||||
}
|
||||
elseif ( is_string( $query ) )
|
||||
elseif ( \is_string( $query ) )
|
||||
{
|
||||
$obj->data[ static::COMPONENT_QUERY ] = $query;
|
||||
$obj->queryString = static::convertQueryAsStringToArray( $query );
|
||||
@@ -298,10 +330,10 @@ class _Url
|
||||
* @li INVALID_SCHEME The scheme was invalid
|
||||
* @li INVALID_USERNAME The username was invalid
|
||||
* @li INVALID_PASSWORD The password was invalid
|
||||
* @LI INVALID_HOST The host name was invalid
|
||||
* @LI INVALID_PATH The path was invalid
|
||||
* @LI INVALID_QUERY The query was invalid
|
||||
* @LI INVALID_FRAGMENT The fragment was invalid
|
||||
* @li INVALID_HOST The host name was invalid
|
||||
* @li INVALID_PATH The path was invalid
|
||||
* @li INVALID_QUERY The query was invalid
|
||||
* @li INVALID_FRAGMENT The fragment was invalid
|
||||
*/
|
||||
public function __construct( $url = NULL, $autoEncode = FALSE )
|
||||
{
|
||||
@@ -370,7 +402,7 @@ class _Url
|
||||
{
|
||||
$newQueryArray = $this->queryString;
|
||||
|
||||
if ( is_array( $keyOrArray ) )
|
||||
if ( \is_array( $keyOrArray ) )
|
||||
{
|
||||
foreach ( $keyOrArray as $k => $v )
|
||||
{
|
||||
@@ -440,7 +472,7 @@ class _Url
|
||||
$port = '';
|
||||
if ( $this->data[ static::COMPONENT_PORT ] )
|
||||
{
|
||||
$port = ':' . intval( $this->data[ static::COMPONENT_PORT ] );
|
||||
$port = ':' . \intval( $this->data[ static::COMPONENT_PORT ] );
|
||||
}
|
||||
|
||||
/* Path */
|
||||
@@ -485,7 +517,7 @@ class _Url
|
||||
|
||||
if( $keys !== NULL )
|
||||
{
|
||||
if( !is_array( $keys ) )
|
||||
if( !\is_array( $keys ) )
|
||||
{
|
||||
$keys = array( $keys => $keys );
|
||||
}
|
||||
@@ -510,58 +542,36 @@ class _Url
|
||||
/**
|
||||
* Make safe for ACP
|
||||
*
|
||||
* @param bool $resource If TRUE, will redirect silently
|
||||
* @deprecated No longer needed as of 4.5, ACP URLs no longer have the session ID in the URL
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function makeSafeForAcp( $resource=FALSE )
|
||||
{
|
||||
return static::internal( "app=core&module=system&controller=redirect", 'front' )->setQueryString( array(
|
||||
'url' => (string) $this,
|
||||
'key' => hash_hmac( "sha256", (string) $this, \IPS\Settings::i()->site_secret_key ),
|
||||
'resource' => $resource
|
||||
) );
|
||||
}
|
||||
return $this;
|
||||
|
||||
/**
|
||||
* Is this URL pointing to the local server?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocalhost()
|
||||
{
|
||||
$baseUrlHostname = static::internal('')->data['host'];
|
||||
|
||||
return (
|
||||
isset( $this->data['host'] )
|
||||
and
|
||||
(
|
||||
(
|
||||
$this->data['host'] == 'localhost' or
|
||||
preg_match( "#\." . preg_quote( $baseUrlHostname ) . "$#", '.' . $this->data['host'] ) or
|
||||
preg_match( "#\." . preg_quote( $this->data['host'] ) . "$#", '.' . $baseUrlHostname )
|
||||
)
|
||||
or
|
||||
(
|
||||
filter_var( $this->data['host'], FILTER_VALIDATE_IP ) and
|
||||
filter_var( $this->data['host'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === FALSE
|
||||
)
|
||||
)
|
||||
);
|
||||
//return static::internal( "app=core&module=system&controller=redirect", 'front' )->setQueryString( array(
|
||||
// 'url' => (string) $this,
|
||||
// 'key' => hash_hmac( "sha256", (string) $this, \IPS\Settings::i()->site_secret_key . 'r' ),
|
||||
// 'resource' => $resource
|
||||
//) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a HTTP Request
|
||||
*
|
||||
* @param int|null $timeout Timeout
|
||||
* @param string $httpVersion HTTP Version
|
||||
* @param bool|int $followRedirects Automatically follow redirects? If a number is provided, will follow up to that number of redirects
|
||||
* @param int|null $timeout Timeout
|
||||
* @param string $httpVersion HTTP Version
|
||||
* @param bool|int $followRedirects Automatically follow redirects? If a number is provided, will follow up to that number of redirects
|
||||
* @param array|null $allowedProtocols Protocols allowed (if NULL we default to array( 'http', 'https', 'ftp', 'scp', 'sftp', 'ftps' ))
|
||||
* @return \IPS\Http\Request
|
||||
*/
|
||||
public function request( $timeout=null, $httpVersion=null, $followRedirects=5 )
|
||||
public function request( $timeout=null, $httpVersion=null, $followRedirects=5, $allowedProtocols=NULL )
|
||||
{
|
||||
$allowedProtocols = $allowedProtocols ?: array( 'http', 'https', 'ftp', 'scp', 'sftp', 'ftps' );
|
||||
|
||||
/* Check the scheme is valid. Some areas accept user-submitted information to create a Url object. To avoid
|
||||
security issues from using file:// telnet:// etc. We reject everything not used by the suite here */
|
||||
if( isset( $this->data['scheme'] ) AND !in_array( $this->data['scheme'], array( 'http', 'https', 'ftp', 'scp', 'sftp', 'ftps' ) ) )
|
||||
if( isset( $this->data['scheme'] ) AND !\in_array( $this->data['scheme'], $allowedProtocols ) )
|
||||
{
|
||||
throw new \RuntimeException( mb_strtoupper( $this->data['scheme'] ) . '_SCHEME_NOT_PERMITTED' );
|
||||
}
|
||||
@@ -573,20 +583,20 @@ class _Url
|
||||
}
|
||||
|
||||
/* Use cURL if we can. BYPASS_CURL constant can be set to TRUE to force us to fallback to Sockets */
|
||||
if ( function_exists( 'curl_init' ) and function_exists( 'curl_exec' ) and \IPS\BYPASS_CURL === false )
|
||||
if ( \function_exists( 'curl_init' ) and \function_exists( 'curl_exec' ) and \IPS\BYPASS_CURL === false )
|
||||
{
|
||||
/* We require 7.36 or higher because older versions can't handle chunked encoding properly - FORCE_CURL constant can be set to override this and use it anyway */
|
||||
$version = curl_version();
|
||||
if( \IPS\FORCE_CURL or version_compare( $version['version'], '7.36', '>=' ) )
|
||||
{
|
||||
$requestObj = new \IPS\Http\Request\Curl( $this, $timeout, $httpVersion, $followRedirects );
|
||||
$requestObj = new \IPS\Http\Request\Curl( $this, $timeout, $httpVersion, $followRedirects, $allowedProtocols );
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback to Sockets if we can't use cURL */
|
||||
if( !isset( $requestObj ) )
|
||||
{
|
||||
$requestObj = new \IPS\Http\Request\Sockets( $this, $timeout, $httpVersion, $followRedirects );
|
||||
$requestObj = new \IPS\Http\Request\Sockets( $this, $timeout, $httpVersion, $followRedirects, $allowedProtocols );
|
||||
}
|
||||
|
||||
/* Set a default user-agent (some services, e.g. spotify, block requests without one but it's good to do so anyway) */
|
||||
@@ -671,7 +681,7 @@ class _Url
|
||||
$allowedCharacters = static::$allowedCharacters[ $component ];
|
||||
|
||||
/* These ones can also include percent-encoded characters and non-latin characters */
|
||||
if ( !in_array( $component, array( static::COMPONENT_SCHEME, static::COMPONENT_PORT ) ) )
|
||||
if ( !\in_array( $component, array( static::COMPONENT_SCHEME, static::COMPONENT_PORT ) ) )
|
||||
{
|
||||
$regex = '(' . '(%[A-Fa-z0-9]{2})|' . '[' . $allowedCharacters . ']\X*' . ')*';
|
||||
}
|
||||
@@ -701,7 +711,7 @@ class _Url
|
||||
public static function encodeComponent( $component, $value )
|
||||
{
|
||||
/* These ones cannot be percent-encoded */
|
||||
if ( in_array( $component, array( static::COMPONENT_SCHEME, static::COMPONENT_PORT ) ) )
|
||||
if ( \in_array( $component, array( static::COMPONENT_SCHEME, static::COMPONENT_PORT ) ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
@@ -720,7 +730,7 @@ class _Url
|
||||
a Google+ profile - when that hits PHP, it will convert it to a space, making the URL invalid.
|
||||
There is no downside to percent-encoding any particular character even if it doesn't technically
|
||||
need to be, so to avoid this issue, we'll just encode it */
|
||||
if ( in_array( $component, array( static::COMPONENT_QUERY, static::COMPONENT_QUERY_KEY, static::COMPONENT_QUERY_VALUE ) ) )
|
||||
if ( \in_array( $component, array( static::COMPONENT_QUERY, static::COMPONENT_QUERY_KEY, static::COMPONENT_QUERY_VALUE ) ) )
|
||||
{
|
||||
$return = str_replace( '+', '%2B', $return );
|
||||
}
|
||||
@@ -784,6 +794,17 @@ class _Url
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a referrer to the URL
|
||||
*
|
||||
* @param string $url The URL.
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function addRef( string $url ): \IPS\Http\Url
|
||||
{
|
||||
return $this->setQueryString( 'ref', base64_encode( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Punycode object
|
||||
*/
|
||||
@@ -800,10 +821,10 @@ class _Url
|
||||
* @li INVALID_SCHEME The scheme was invalid
|
||||
* @li INVALID_USERNAME The username was invalid
|
||||
* @li INVALID_PASSWORD The password was invalid
|
||||
* @LI INVALID_HOST The host name was invalid
|
||||
* @LI INVALID_PATH The path was invalid
|
||||
* @LI INVALID_QUERY The query was invalid
|
||||
* @LI INVALID_FRAGMENT The fragment was invalid
|
||||
* @li INVALID_HOST The host name was invalid
|
||||
* @li INVALID_PATH The path was invalid
|
||||
* @li INVALID_QUERY The query was invalid
|
||||
* @li INVALID_FRAGMENT The fragment was invalid
|
||||
*/
|
||||
protected static function componentsFromUrlString( $url, $autoEncode = FALSE )
|
||||
{
|
||||
@@ -935,7 +956,7 @@ class _Url
|
||||
/* If the authority ends in a : followed by a number, that's the port */
|
||||
if ( preg_match( '/:(\d*)$/', $authority, $matches ) )
|
||||
{
|
||||
$return[ static::COMPONENT_PORT ] = intval( $matches[1] );
|
||||
$return[ static::COMPONENT_PORT ] = \intval( $matches[1] );
|
||||
$authority = mb_substr( $authority, 0, -mb_strlen( $matches[0] ) );
|
||||
}
|
||||
|
||||
@@ -1075,7 +1096,7 @@ class _Url
|
||||
$k = static::encodeComponent( static::COMPONENT_QUERY_KEY, $k );
|
||||
}
|
||||
|
||||
if ( is_array( $v ) )
|
||||
if ( \is_array( $v ) )
|
||||
{
|
||||
$return[] = static::squashQueryStringArray( $k, $v );
|
||||
}
|
||||
@@ -1113,7 +1134,7 @@ class _Url
|
||||
$k = static::encodeComponent( static::COMPONENT_QUERY_KEY, $k );
|
||||
}
|
||||
|
||||
if ( is_array( $v ) )
|
||||
if ( \is_array( $v ) )
|
||||
{
|
||||
$return[] = static::squashQueryStringArray( "{$key}[{$k}]", $v, $encode );
|
||||
}
|
||||
@@ -1127,7 +1148,7 @@ class _Url
|
||||
$return[] = "{$key}[{$k}]={$v}";
|
||||
}
|
||||
}
|
||||
return count( $return ) ? implode( '&', $return ) : '';
|
||||
return \count( $return ) ? implode( '&', $return ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1184,6 +1205,7 @@ class _Url
|
||||
* @param string $mainKey The main key, for example, if parsing "foo[x][y]=bar", the value will be "foo"
|
||||
* @param string $subKeyNames The sub keys in square brackets, for example, if parsing "foo[x][y]=bar", the value will be "[x][y]"
|
||||
* @param string $value The value, for example, if parsing "foo[x][y]=bar", the value will be "bar"
|
||||
* @return void
|
||||
*/
|
||||
protected static function _pushQueryStringPartIntoArray( &$return, $mainKey, $subKeyNames, $value )
|
||||
{
|
||||
@@ -1194,7 +1216,7 @@ class _Url
|
||||
$return[ $mainKey ] = array();
|
||||
}
|
||||
|
||||
if ( is_array( $return[ $mainKey ] ) )
|
||||
if ( \is_array( $return[ $mainKey ] ) )
|
||||
{
|
||||
$workingArray =& $return[ $mainKey ];
|
||||
}
|
||||
@@ -1209,7 +1231,7 @@ class _Url
|
||||
if ( $k === '' )
|
||||
{
|
||||
$workingArray[] = array();
|
||||
$workingArray =& $workingArray[ count( $workingArray ) - 1 ];
|
||||
$workingArray =& $workingArray[ \count( $workingArray ) - 1 ];
|
||||
}
|
||||
elseif ( !isset( $workingArray[ $k ] ) )
|
||||
{
|
||||
@@ -1291,7 +1313,6 @@ class _Url
|
||||
public function acpQueryString()
|
||||
{
|
||||
$queryString = $this->queryString;
|
||||
unset( $queryString['adsess'] );
|
||||
unset( $queryString['csrf'] );
|
||||
return static::convertQueryAsArrayToString( $queryString );
|
||||
}
|
||||
@@ -1375,7 +1396,7 @@ class _Url
|
||||
* Get friendly URL data
|
||||
*
|
||||
* @return array Parameters
|
||||
* @deprecared
|
||||
* @deprecated
|
||||
*/
|
||||
public function getFriendlyUrlData()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user