Page MenuHomeDevCentral

No OneTemporary

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

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)

Event Timeline