From 8c75763be861741e8aeb830b17a0dac49ad615dc Mon Sep 17 00:00:00 2001 From: Carl Alexander Date: Mon, 24 Aug 2020 07:29:04 -0400 Subject: [PATCH] feat: redirect to primary domain name if host is different --- .../EventManagementConfiguration.php | 1 + src/Configuration/WordPressConfiguration.php | 1 + src/Configuration/YmirConfiguration.php | 1 + src/Subscriber/RedirectSubscriber.php | 75 +++++++++++++++ .../Subscriber/RedirectSubscriberTest.php | 93 +++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 src/Subscriber/RedirectSubscriber.php create mode 100644 tests/Unit/Subscriber/RedirectSubscriberTest.php diff --git a/src/Configuration/EventManagementConfiguration.php b/src/Configuration/EventManagementConfiguration.php index f9a2b70..723160b 100644 --- a/src/Configuration/EventManagementConfiguration.php +++ b/src/Configuration/EventManagementConfiguration.php @@ -47,6 +47,7 @@ public function modify(Container $container) new Subscriber\HttpApiSubscriber(), new Subscriber\ImageEditorSubscriber($container['console_client'], $container['file_manager']), new Subscriber\PluploadSubscriber($container['plugin_relative_path'], $container['rest_namespace'], $container['assets_url'], $container['plupload_error_messages']), + new Subscriber\RedirectSubscriber($container['ymir_primary_domain_name'], $container['is_multisite']), new Subscriber\RestApiSubscriber($container['rest_namespace'], $container['rest_endpoints']), new Subscriber\SecurityHeadersSubscriber(), new Subscriber\WordPressSubscriber($container['server_software'], $container['site_url']), diff --git a/src/Configuration/WordPressConfiguration.php b/src/Configuration/WordPressConfiguration.php index 56a2f05..c83b586 100644 --- a/src/Configuration/WordPressConfiguration.php +++ b/src/Configuration/WordPressConfiguration.php @@ -40,6 +40,7 @@ public function modify(Container $container) return 'wordpress@'.$sitename; }); $container['http_transport'] = _wp_http_get_object(); + $container['is_multisite'] = is_multisite(); $container['phpmailer'] = function () { if (!class_exists(\PHPMailer::class)) { require_once ABSPATH.WPINC.'/class-phpmailer.php'; diff --git a/src/Configuration/YmirConfiguration.php b/src/Configuration/YmirConfiguration.php index b506340..c396dc4 100644 --- a/src/Configuration/YmirConfiguration.php +++ b/src/Configuration/YmirConfiguration.php @@ -27,6 +27,7 @@ class YmirConfiguration implements ContainerConfigurationInterface public function modify(Container $container) { $container['ymir_environment'] = getenv('YMIR_ENVIRONMENT') ?: ''; + $container['ymir_primary_domain_name'] = getenv('YMIR_PRIMARY_DOMAIN_NAME') ?: ''; $container['ymir_project_type'] = getenv('YMIR_PROJECT_TYPE') ?: 'wordpress'; } } diff --git a/src/Subscriber/RedirectSubscriber.php b/src/Subscriber/RedirectSubscriber.php new file mode 100644 index 0000000..f7b1867 --- /dev/null +++ b/src/Subscriber/RedirectSubscriber.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Ymir\Plugin\Subscriber; + +use Ymir\Plugin\EventManagement\SubscriberInterface; + +/** + * Subscriber that manages redirects that would have been handled by the web server. + */ +class RedirectSubscriber implements SubscriberInterface +{ + /** + * The primary domain name that we want to redirect requests to. + * + * @var string + */ + private $domainName; + + /** + * Flag whether this is a multisite installation or not. + * + * @var bool + */ + private $isMultisite; + + /** + * Constructor. + */ + public function __construct(string $domainName, bool $isMultisite) + { + $this->domainName = $domainName; + $this->isMultisite = $isMultisite; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array + { + return [ + 'init' => ['redirectToDomainName', 1], + ]; + } + + /** + * Redirect to the primary domain name if necessary. + */ + public function redirectToDomainName() + { + if ($this->isMultisite || empty($_SERVER['HTTP_HOST']) || $_SERVER['HTTP_HOST'] === $this->domainName) { + return; + } + + $url = 'https://'.$this->domainName; + + if (!empty($_SERVER['REQUEST_URI'])) { + $url .= $_SERVER['REQUEST_URI']; + } + + if (wp_redirect($url, 301)) { + exit; + } + } +} diff --git a/tests/Unit/Subscriber/RedirectSubscriberTest.php b/tests/Unit/Subscriber/RedirectSubscriberTest.php new file mode 100644 index 0000000..0591b24 --- /dev/null +++ b/tests/Unit/Subscriber/RedirectSubscriberTest.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Ymir\Plugin\Tests\Unit\Subscriber; + +use Ymir\Plugin\Subscriber\RedirectSubscriber; +use Ymir\Plugin\Tests\Mock\FunctionMockTrait; +use Ymir\Plugin\Tests\Unit\TestCase; + +/** + * @covers \Ymir\Plugin\Subscriber\RedirectSubscriber + */ +class RedirectSubscriberTest extends TestCase +{ + use FunctionMockTrait; + + public function testGetSubscribedEvents() + { + $callbacks = RedirectSubscriber::getSubscribedEvents(); + + foreach ($callbacks as $callback) { + $this->assertTrue(method_exists(RedirectSubscriber::class, is_array($callback) ? $callback[0] : $callback)); + } + + $subscribedEvents = [ + 'init' => ['redirectToDomainName', 1], + ]; + + $this->assertSame($subscribedEvents, $callbacks); + } + + /** + * @backupGlobals enabled + */ + public function testRedirectToDomainNameWithHttpHostDifferentThanDomainName() + { + $_SERVER['HTTP_HOST'] = 'another_domain_name'; + + $wp_redirect = $this->getFunctionMock($this->getNamespace(RedirectSubscriber::class), 'wp_redirect'); + $wp_redirect->expects($this->once()) + ->with($this->identicalTo('https://domain_name'), $this->identicalTo(301)) + ->willReturn(false); + + (new RedirectSubscriber('domain_name', false))->redirectToDomainName(); + } + + /** + * @backupGlobals enabled + */ + public function testRedirectToDomainNameWithHttpHostDifferentThanDomainNameAddsRequestUri() + { + $_SERVER['HTTP_HOST'] = 'another_domain_name'; + $_SERVER['REQUEST_URI'] = '/uri'; + + $wp_redirect = $this->getFunctionMock($this->getNamespace(RedirectSubscriber::class), 'wp_redirect'); + $wp_redirect->expects($this->once()) + ->with($this->identicalTo('https://domain_name/uri'), $this->identicalTo(301)) + ->willReturn(false); + + (new RedirectSubscriber('domain_name', false))->redirectToDomainName(); + } + + /** + * @backupGlobals enabled + */ + public function testRedirectToDomainNameWithHttpHostSameAsDomainName() + { + $_SERVER['HTTP_HOST'] = 'domain_name'; + + $wp_redirect = $this->getFunctionMock($this->getNamespace(RedirectSubscriber::class), 'wp_redirect'); + $wp_redirect->expects($this->never()); + + (new RedirectSubscriber('domain_name', false))->redirectToDomainName(); + } + + public function testRedirectToDomainNameWithMultisiteEnabled() + { + $wp_redirect = $this->getFunctionMock($this->getNamespace(RedirectSubscriber::class), 'wp_redirect'); + $wp_redirect->expects($this->never()); + + (new RedirectSubscriber('domain_name', true))->redirectToDomainName(); + } +}