From 5ef5642c19036866299767b733629348b618efcb Mon Sep 17 00:00:00 2001
From: Josh Bruce <josh@8fold.pro>
Date: Wed, 12 Apr 2023 17:50:56 -0400
Subject: [PATCH 1/2] add: Allow directory with no specified file name

---
 src/Errors/Environment.php |  1 +
 src/Image.php              | 21 +++++++++++++++++++++
 tests/ImageTest.php        | 17 +++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/src/Errors/Environment.php b/src/Errors/Environment.php
index 4834ce9..24718bc 100644
--- a/src/Errors/Environment.php
+++ b/src/Errors/Environment.php
@@ -8,4 +8,5 @@ enum Environment: string
     case AllowUrlFOpenNotEnabled = 'Tried to copy file from URL without allow_url_fopen in php_ini';
     case CopyDestinationMustBeLocal = 'Tried to copy file to URL';
     case FailedToCreateDestinationDirectory = 'Tried to copy file to directory that was not found';
+    case FailedToParseUrl = 'Tried to copy file from URL and could not parse url.'
 }
diff --git a/src/Image.php b/src/Image.php
index c719655..c51391d 100644
--- a/src/Image.php
+++ b/src/Image.php
@@ -29,6 +29,14 @@ public static function fromUrlToLocalPath(
         string $url,
         string $filename
     ): self|ImageError|EnvironmentError {
+        if (str_contains($filename, '.') === false) {
+            $file = self::filenameFromUrl($url);
+            if (is_string($file) === false) {
+                return $file;
+            }
+            $filename = $filename . '/' . $file;
+        }
+
         $copied = self::copiedUrlToLocalpath($url, $filename);
         if (is_bool($copied) === false) {
             return $copied;
@@ -98,6 +106,19 @@ public static function copiedUrlToLocalPath(
         return copy($from, $to);
     }
 
+    public static function filenameFromUrl(string $url): string|EnvironmentError
+    {
+        $url = parse_url($url);
+        if ($url === false) {
+            return EnvironmentError::FailedToParseUrl;
+        }
+
+        $path  = $url['path'];
+        $parts = explode('/', $path);
+
+        return array_pop($parts);
+    }
+
     private static function didMakeDirectoryFor(string $filename): bool
     {
         $dir = self::directoryFromFilename($filename);
diff --git a/tests/ImageTest.php b/tests/ImageTest.php
index 6d161c9..3bc1a1e 100644
--- a/tests/ImageTest.php
+++ b/tests/ImageTest.php
@@ -32,6 +32,23 @@ public function tearDown(): void
         parent::tearDown();
     }
 
+    /**
+     * @test
+     */
+    public function can_get_file_from_url(): void
+    {
+        $expected = 'image.png';
+
+        $result = Image::filenameFromUrl(
+            'https://ex.ample/some/path/image.png?query=1#text-fragment'
+        );
+
+        $this->assertSame(
+            $expected,
+            $result
+        );
+    }
+
     /**
      * @test
      */

From 27763fbb7eaec907605894717ef66c780b5c3c6f Mon Sep 17 00:00:00 2001
From: Josh Bruce <josh@8fold.pro>
Date: Wed, 12 Apr 2023 19:55:56 -0400
Subject: [PATCH 2/2] fix: Stan

---
 src/Errors/Environment.php | 3 ++-
 src/Image.php              | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/Errors/Environment.php b/src/Errors/Environment.php
index 24718bc..a7fcc81 100644
--- a/src/Errors/Environment.php
+++ b/src/Errors/Environment.php
@@ -8,5 +8,6 @@ enum Environment: string
     case AllowUrlFOpenNotEnabled = 'Tried to copy file from URL without allow_url_fopen in php_ini';
     case CopyDestinationMustBeLocal = 'Tried to copy file to URL';
     case FailedToCreateDestinationDirectory = 'Tried to copy file to directory that was not found';
-    case FailedToParseUrl = 'Tried to copy file from URL and could not parse url.'
+    case FailedToParseUrl = 'Tried to copy file from URL and could not parse url.';
+    case UrlPathNotFound = 'Tried to copy file from URL with no path.';
 }
diff --git a/src/Image.php b/src/Image.php
index c51391d..db26741 100644
--- a/src/Image.php
+++ b/src/Image.php
@@ -113,6 +113,10 @@ public static function filenameFromUrl(string $url): string|EnvironmentError
             return EnvironmentError::FailedToParseUrl;
         }
 
+        if (array_key_exists('path', $url) === false) {
+            return EnvironmentError::UrlPathNotFound;
+        }
+
         $path  = $url['path'];
         $parts = explode('/', $path);