Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F11725970
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/HTTP/Requests/Request.php b/src/HTTP/Requests/Request.php
index aea7a9d..509055b 100644
--- a/src/HTTP/Requests/Request.php
+++ b/src/HTTP/Requests/Request.php
@@ -1,11 +1,12 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\HTTP\Requests;
class Request {
use WithAcceptedLanguages;
use WithRemoteAddress;
+ use WithURL;
}
diff --git a/src/HTTP/Requests/WithURL.php b/src/HTTP/Requests/WithURL.php
new file mode 100644
index 0000000..fae1a50
--- /dev/null
+++ b/src/HTTP/Requests/WithURL.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Keruald\OmniTools\HTTP\Requests;
+
+use Keruald\OmniTools\Strings\Multibyte\StringUtilities;
+
+trait WithURL {
+
+ ///
+ /// Main methods
+ ///
+
+ public static function getServerURL () : string {
+ $scheme = self::getScheme();
+ $name = self::getServerName();
+ $port = self::getPort();
+
+ // If we forward for a proxy, trust the scheme instead of standard :80
+ $fixToHTTPS = $port === 80 && $scheme === "https";
+
+ if ($port === 443 || $fixToHTTPS) {
+ return "https://$name";
+ }
+
+ if ($port === 80) {
+ return "http://$name";
+ }
+
+ return "$scheme://$name:$port";
+ }
+
+ ///
+ /// Helper methods
+ ///
+
+ public static function getPort () : int {
+ return (int)($_SERVER['SERVER_PORT'] ?? 80);
+ }
+
+ public static function getServerName () : string {
+ return $_SERVER['SERVER_NAME'] ?? "localhost";
+ }
+
+ public static function getScheme () : string {
+ return $_SERVER['REQUEST_SCHEME']
+ ?? $_SERVER['HTTP_X_FORWARDED_PROTO']
+ ?? $_SERVER['HTTP_X_FORWARDED_PROTOCOL']
+ ?? $_SERVER['HTTP_X_URL_SCHEME']
+ ?? self::guessScheme();
+ }
+
+ private static function guessScheme () : string {
+ return self::isHTTPS() ? "https" : "http";
+ }
+
+ public static function isHTTPS () : bool {
+ // Legacy headers have been documented at MDN:
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
+
+ $headers = self::getHTTPSHeadersTable();
+ foreach ($headers as $header => $value) {
+ if (isset($_SERVER[$header]) && $_SERVER[$header] === $value) {
+ return true;
+ }
+ }
+
+ if (isset($_SERVER['HTTP_FORWARDED'])) {
+ return StringUtilities::contains($_SERVER['HTTP_FORWARDED'], "proto=https");
+ }
+
+ return false;
+ }
+
+ private static function getHTTPSHeadersTable () : array {
+ return [
+ "HTTPS" => "on",
+ "REQUEST_SCHEME" => "https",
+ "SERVER_PORT" => "443",
+ "HTTP_X_FORWARDED_PROTO" => "https",
+ "HTTP_FRONT_END_HTTPS" => "on",
+ "HTTP_X_FORWARDED_PROTOCOL" => "https",
+ "HTTP_X_FORWARDED_SSL" => "on",
+ "HTTP_X_URL_SCHEME" => "https",
+ ];
+ }
+
+}
diff --git a/src/Strings/Multibyte/StringUtilities.php b/src/Strings/Multibyte/StringUtilities.php
index 15fd5cb..c06d9f2 100644
--- a/src/Strings/Multibyte/StringUtilities.php
+++ b/src/Strings/Multibyte/StringUtilities.php
@@ -1,56 +1,60 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Strings\Multibyte;
class StringUtilities {
/**
* Pads a multibyte string to a certain length with another string
*
* @param string $input the input string
* @param int $padLength the target string size
* @param string $padString the padding characters (optional, default is space)
* @param int $padType STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH (optional, default is STR_PAD_RIGHT)
* @param string $encoding the character encoding (optional)
*
* @return string the padded string
*
*/
public static function pad (
string $input,
int $padLength,
string $padString = ' ',
int $padType = STR_PAD_RIGHT,
string $encoding = ''
) : string {
return (new StringPad)
->setInput($input)
->setPadLength($padLength)
->setPadString($padString)
->setPadType($padType)
->setEncoding($encoding ?: mb_internal_encoding())
->pad();
}
public static function isSupportedEncoding (string $encoding) : bool {
foreach (mb_list_encodings() as $supportedEncoding) {
if ($encoding === $supportedEncoding) {
return true;
}
}
return false;
}
public static function startsWith (string $string, string $start) {
$length = mb_strlen($start);
return mb_substr($string, 0, $length) === $start;
}
public static function endsWith (string $string, string $end) {
$length = mb_strlen($end);
return $length === 0 || mb_substr($string, -$length) === $end;
}
+ public static function contains (string $string, string $needle) : bool {
+ return strpos($string, $needle) !== false;
+ }
+
}
diff --git a/tests/HTTP/Requests/RequestTest.php b/tests/HTTP/Requests/RequestTest.php
index f55338e..95d448c 100644
--- a/tests/HTTP/Requests/RequestTest.php
+++ b/tests/HTTP/Requests/RequestTest.php
@@ -1,48 +1,117 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\HTTP\Requests;
use Keruald\OmniTools\HTTP\Requests\Request;
use PHPUnit\Framework\TestCase;
class RequestTest extends TestCase {
+ ///
+ /// Tests
+ ///
+
/**
* @covers \Keruald\OmniTools\HTTP\Requests\Request::getRemoteAddress
* @backupGlobals enabled
*/
public function testGetRemoteAddress () : void {
$this->assertEmpty(Request::getRemoteAddress());
$_SERVER = [
'REMOTE_ADDR' => '10.0.0.2',
];
$this->assertEquals('10.0.0.2', Request::getRemoteAddress());
$_SERVER += [
'HTTP_X_FORWARDED_FOR' => '10.0.0.3',
'HTTP_CLIENT_IP' => '10.0.0.4',
];
$this->assertEquals(
'10.0.0.3', Request::getRemoteAddress(),
"HTTP_X_FORWARDED_FOR must be prioritized."
);
}
/**
* @covers \Keruald\OmniTools\HTTP\Requests\Request::getAcceptedLanguages
* @backupGlobals enabled
*/
public function testGetAcceptedLanguages () : void {
$_SERVER = [
'HTTP_ACCEPT_LANGUAGE' => 'fr,en-US;q=0.7,en;q=0.3',
];
$this->assertEquals(
["fr", "en-US", "en"],
Request::getAcceptedLanguages()
);
}
+ /**
+ * @backupGlobals enabled
+ * @dataProvider provideServerURLs
+ */
+ public function testGetServerURL (array $server, string $url) : void {
+ $_SERVER = $server;
+
+ $this->assertEquals($url, Request::getServerURL());
+ }
+
+ ///
+ /// Data providers
+ ///
+
+ public function provideServerURLs () : iterable {
+ yield [[], "http://localhost"];
+ yield [["UNRELATED" => "ANYTHING"], "http://localhost"];
+
+ yield [
+ [
+ "SERVER_PORT" => "80",
+ "SERVER_NAME" => "acme.tld",
+ ],
+ "http://acme.tld"
+ ];
+
+ yield [
+ [
+ "SERVER_PORT" => "443",
+ "SERVER_NAME" => "acme.tld",
+ ],
+ "https://acme.tld"
+ ];
+
+ yield [
+ [
+ "SERVER_PORT" => "80",
+ "SERVER_NAME" => "acme.tld",
+ "HTTP_X_FORWARDED_PROTO" => "https",
+ ],
+ "https://acme.tld"
+ ];
+
+ yield [
+ [
+ "SERVER_PORT" => "80",
+ "SERVER_NAME" => "acme.tld",
+ "HTTP_FORWARDED" => "for=192.0.2.43, for=\"[2001:db8:cafe::17]\", proto=https, by=203.0.113.43",
+ ],
+ "https://acme.tld"
+ ];
+
+ yield [
+ [
+ "SERVER_PORT" => "8443",
+ "SERVER_NAME" => "acme.tld",
+ "HTTPS" => "on",
+ ],
+ "https://acme.tld:8443"
+ ];
+
+
+ }
+
+
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Sep 18, 23:00 (6 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2991896
Default Alt Text
(8 KB)
Attached To
Mode
rKOT Keruald OmniTools
Attached
Detach File
Event Timeline
Log In to Comment