From 0527115bbacc080c2be82da957a04c57170f3760 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 23 Jul 2024 14:12:12 +0000 Subject: [PATCH] Merge pull request #1882 from hydephp/normalize-protocol-relative-url-handling Normalize protocol relative URL handling https://github.com/hydephp/develop/commit/aa06e42f72fec3e08a4e6a936f2b0e6a0d519384 --- src/Foundation/Kernel/Hyperlinks.php | 12 ++++++-- .../Factories/FeaturedImageFactory.php | 3 +- .../Blogging/Models/FeaturedImage.php | 13 ++++++-- .../Features/Metadata/PageMetadataBag.php | 4 +-- tests/Feature/Foundation/HyperlinksTest.php | 30 +++++++++++++++++++ 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/Foundation/Kernel/Hyperlinks.php b/src/Foundation/Kernel/Hyperlinks.php index c73e3186..2a94165d 100644 --- a/src/Foundation/Kernel/Hyperlinks.php +++ b/src/Foundation/Kernel/Hyperlinks.php @@ -115,7 +115,7 @@ public function mediaLink(string $destination, bool $validate = false): string */ public function asset(string $name, bool $preferQualifiedUrl = false): string { - if (str_starts_with($name, 'http')) { + if (static::isRemote($name)) { return $name; } @@ -151,7 +151,7 @@ public function url(string $path = ''): string { $path = $this->formatLink(trim($path, '/')); - if (str_starts_with($path, 'http')) { + if (static::isRemote($path)) { return $path; } @@ -177,4 +177,12 @@ public function route(string $key): ?Route { return $this->kernel->routes()->get($key); } + + /** + * Determine if the given URL is a remote link. + */ + public static function isRemote(string $url): bool + { + return str_starts_with($url, 'http') || str_starts_with($url, '//'); + } } diff --git a/src/Framework/Factories/FeaturedImageFactory.php b/src/Framework/Factories/FeaturedImageFactory.php index 2ecbbf27..4c2fdb01 100644 --- a/src/Framework/Factories/FeaturedImageFactory.php +++ b/src/Framework/Factories/FeaturedImageFactory.php @@ -8,6 +8,7 @@ use RuntimeException; use Illuminate\Support\Str; use Hyde\Markdown\Models\FrontMatter; +use Hyde\Foundation\Kernel\Hyperlinks; use Hyde\Framework\Features\Blogging\Models\FeaturedImage; use Hyde\Markdown\Contracts\FrontMatter\SubSchemas\FeaturedImageSchema; @@ -72,7 +73,7 @@ protected function makeSource(): string throw new RuntimeException(sprintf('No featured image source was found in "%s"', $this->filePath ?? 'unknown file')); } - if (FeaturedImage::isRemote($value)) { + if (Hyperlinks::isRemote($value)) { return $value; } diff --git a/src/Framework/Features/Blogging/Models/FeaturedImage.php b/src/Framework/Features/Blogging/Models/FeaturedImage.php index a8dcb492..ebb3522c 100644 --- a/src/Framework/Features/Blogging/Models/FeaturedImage.php +++ b/src/Framework/Features/Blogging/Models/FeaturedImage.php @@ -9,7 +9,9 @@ use Hyde\Facades\Config; use Illuminate\Support\Str; use Hyde\Support\BuildWarnings; +use JetBrains\PhpStorm\Deprecated; use Illuminate\Support\Facades\Http; +use Hyde\Foundation\Kernel\Hyperlinks; use Hyde\Framework\Exceptions\FileNotFoundException; use Hyde\Markdown\Contracts\FrontMatter\SubSchemas\FeaturedImageSchema; @@ -19,7 +21,6 @@ use function filesize; use function sprintf; use function key; -use function str_starts_with; /** * Object representation of a blog post's featured image. @@ -63,7 +64,7 @@ public function __construct( protected readonly ?string $licenseUrl = null, protected readonly ?string $copyrightText = null ) { - $this->type = self::isRemote($source) ? self::TYPE_REMOTE : self::TYPE_LOCAL; + $this->type = Hyperlinks::isRemote($source) ? self::TYPE_REMOTE : self::TYPE_LOCAL; $this->source = $this->setSource($source); } @@ -241,8 +242,14 @@ protected function getContentLengthForRemoteImage(): int return 0; } + /** + * @codeCoverageIgnore Deprecated method. + * + * @deprecated This method will be removed in v2.0. Please use `Hyperlinks::isRemote` instead. + */ + #[Deprecated(reason: 'Replaced by the \Hyde\Foundation\Kernel\Hyperlinks::isRemote method', replacement: '\Hyde\Foundation\Kernel\Hyperlinks::isRemote(%parametersList%)', since: '1.8.0')] public static function isRemote(string $source): bool { - return str_starts_with($source, 'http') || str_starts_with($source, '//'); + return Hyperlinks::isRemote($source); } } diff --git a/src/Framework/Features/Metadata/PageMetadataBag.php b/src/Framework/Features/Metadata/PageMetadataBag.php index 3aad1667..efada5ec 100644 --- a/src/Framework/Features/Metadata/PageMetadataBag.php +++ b/src/Framework/Features/Metadata/PageMetadataBag.php @@ -7,8 +7,8 @@ use Hyde\Facades\Meta; use Hyde\Pages\Concerns\HydePage; use Hyde\Pages\MarkdownPost; +use Hyde\Foundation\Kernel\Hyperlinks; -use function str_starts_with; use function substr_count; use function str_repeat; @@ -77,7 +77,7 @@ protected function resolveImageLink(string $image): string { // Since this is run before the page is rendered, we don't have the currentPage property. // So we need to run some of the same calculations here to resolve the image path link. - return str_starts_with($image, 'http') ? $image + return Hyperlinks::isRemote($image) ? $image : str_repeat('../', substr_count(MarkdownPost::outputDirectory().'/'.$this->page->identifier, '/')).$image; } } diff --git a/tests/Feature/Foundation/HyperlinksTest.php b/tests/Feature/Foundation/HyperlinksTest.php index 390a383a..3234e7cd 100644 --- a/tests/Feature/Foundation/HyperlinksTest.php +++ b/tests/Feature/Foundation/HyperlinksTest.php @@ -127,4 +127,34 @@ public function testRouteHelperWithInvalidRoute() { $this->assertNull($this->class->route('foo')); } + + public function testIsRemoteWithHttpUrl() + { + $this->assertTrue(Hyperlinks::isRemote('http://example.com')); + } + + public function testIsRemoteWithHttpsUrl() + { + $this->assertTrue(Hyperlinks::isRemote('https://example.com')); + } + + public function testIsRemoteWithProtocolRelativeUrl() + { + $this->assertTrue(Hyperlinks::isRemote('//example.com')); + } + + public function testIsRemoteWithRelativeUrl() + { + $this->assertFalse(Hyperlinks::isRemote('/path/to/resource')); + } + + public function testIsRemoteWithAbsoluteLocalPath() + { + $this->assertFalse(Hyperlinks::isRemote('/var/www/html/index.php')); + } + + public function testIsRemoteWithEmptyString() + { + $this->assertFalse(Hyperlinks::isRemote('')); + } }