From f18508049e57d5cc79cf5d4b0036ecbabd453bc0 Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Tue, 20 Sep 2022 21:48:18 -0300 Subject: [PATCH 1/3] Not ready yet --- src/Seeker/S3FileSeeker.php | 141 ++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/Seeker/S3FileSeeker.php diff --git a/src/Seeker/S3FileSeeker.php b/src/Seeker/S3FileSeeker.php new file mode 100644 index 0000000..9ea1596 --- /dev/null +++ b/src/Seeker/S3FileSeeker.php @@ -0,0 +1,141 @@ +path = $path; + try { + $this->stream = fopen($this->path, "r", FALSE); + if (!$this->stream) { + throw new InvalidArgumentException( + "The provided S3 Object could not be opened" + ); + } + } catch (Exception $e) { + throw new InvalidArgumentException( + "The provided S3 Object could not be opened: " . $e->getMessage() + ); + } + // We close it, that fopen was just to make sure it exists. + fclose($this->stream); + // Will fetch Content-length via a head request. + $this->size = filesize($path); + } + + /** + * Destructor function to ensure the file descriptor is closed. + */ + public function __destruct() { + if ($this->stream) { + fclose($this->stream); + } + } + + /** + * @inheritDoc + */ + public function retrieveStart(int $length, int $offset = 0): ?string { + // Bail out if the parameters are invalid + if ($length <= 0 || $offset < 0 || ($offset + $length) > $this->size) { + return NULL; + } + + try { + $context = stream_context_create( + [ + 's3' => [ + 'Range' => "bytes=" . $offset . "-" . ($offset + $length - 1), + 'seekable' => FALSE, + ], + ] + ); + + $this->stream = fopen($this->path, "r", FALSE, $context); + $data = fread($this->stream, $length); + if (!$data) { + return NULL; + } + return $data; + } catch (Exception $e) { + user_error("Caught exception: " . $e->getMessage(), E_USER_WARNING); + return NULL; + } + } + + /** + * @inheritDoc + */ + public function retrieveEnd(int $length, int $offset = 0): ?string { + if ($length <= 0 || ($offset + $length) > $this->size) { + return NULL; + } + + // Make sure we can handle both positive and negative expressions of the offset, just in case. + $offset = abs($offset); + + // Make sure we are not trying to seek past the start of the file. + if ($offset > $this->size) { + $offset = $this->size; + } + + try { + $context = stream_context_create( + [ + 's3' => [ + 'Range' => "bytes=" . ((int)$this->size - $offset) - $length - 1 + . "-" . ((int) $this->size - $offset) - 1, + 'seekable' => FALSE, + ], + ] + ); + + $this->stream = fopen($this->path, "r", FALSE, $context); + + // Get the data + $data = fread($this->stream, $length); + if (!$data) { + return NULL; + } + return $data; + } catch (Exception $e) { + user_error("Caught exception: " . $e->getMessage(), E_USER_WARNING); + return NULL; + } + } + +} \ No newline at end of file From d9d68683a6a2164d81ae9c92d11e3399e45c7b3b Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Tue, 20 Sep 2022 21:57:32 -0300 Subject: [PATCH 2/3] Refactor name. S3 files are Objects --- src/Seeker/{S3FileSeeker.php => S3ObjectSeeker.php} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/Seeker/{S3FileSeeker.php => S3ObjectSeeker.php} (97%) diff --git a/src/Seeker/S3FileSeeker.php b/src/Seeker/S3ObjectSeeker.php similarity index 97% rename from src/Seeker/S3FileSeeker.php rename to src/Seeker/S3ObjectSeeker.php index 9ea1596..e64be95 100644 --- a/src/Seeker/S3FileSeeker.php +++ b/src/Seeker/S3ObjectSeeker.php @@ -6,7 +6,7 @@ use InvalidArgumentException; use Mingulay\SeekerInterface; -class S3FileSeeker implements SeekerInterface { +class S3ObjectSeeker implements SeekerInterface { /** * The valid s3:// wrapper path to an S3 Object. @@ -31,7 +31,7 @@ class S3FileSeeker implements SeekerInterface { /** - * Create a new LocalFileSeeker object. + * Create a new S3ObjectSeeker object. * * @param string $path The streamwrapper prefixed path to an S3 Object. * From 07ec1c6e20f8172ab1f9b7da8f38baa371f782de Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Wed, 21 Sep 2022 17:09:40 -0300 Subject: [PATCH 3/3] refactor to have only head calls and iterate over the open remote stream --- src/Seeker/S3ObjectSeeker.php | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Seeker/S3ObjectSeeker.php b/src/Seeker/S3ObjectSeeker.php index e64be95..f6f44f2 100644 --- a/src/Seeker/S3ObjectSeeker.php +++ b/src/Seeker/S3ObjectSeeker.php @@ -40,8 +40,8 @@ class S3ObjectSeeker implements SeekerInterface { public function __construct(string $path) { $this->path = $path; try { - $this->stream = fopen($this->path, "r", FALSE); - if (!$this->stream) { + $this->size = filesize($path); + if ($this->size === FALSE) { throw new InvalidArgumentException( "The provided S3 Object could not be opened" ); @@ -51,10 +51,6 @@ public function __construct(string $path) { "The provided S3 Object could not be opened: " . $e->getMessage() ); } - // We close it, that fopen was just to make sure it exists. - fclose($this->stream); - // Will fetch Content-length via a head request. - $this->size = filesize($path); } /** @@ -86,8 +82,11 @@ public function retrieveStart(int $length, int $offset = 0): ?string { ); $this->stream = fopen($this->path, "r", FALSE, $context); - $data = fread($this->stream, $length); - if (!$data) { + $data = ''; + while (!feof( $this->stream)) { + $data .= fread($this->stream, 8192); + } + if (!$data or strlen($data)!= $length) { return NULL; } return $data; @@ -104,7 +103,6 @@ public function retrieveEnd(int $length, int $offset = 0): ?string { if ($length <= 0 || ($offset + $length) > $this->size) { return NULL; } - // Make sure we can handle both positive and negative expressions of the offset, just in case. $offset = abs($offset); @@ -114,21 +112,24 @@ public function retrieveEnd(int $length, int $offset = 0): ?string { } try { + $to = ($this->size - $offset - 1); + $from = $to - $length + 1; $context = stream_context_create( [ 's3' => [ - 'Range' => "bytes=" . ((int)$this->size - $offset) - $length - 1 - . "-" . ((int) $this->size - $offset) - 1, + 'Range' => "bytes=" . $from + . "-" . $to, 'seekable' => FALSE, ], ] ); - + $data = ''; $this->stream = fopen($this->path, "r", FALSE, $context); - - // Get the data - $data = fread($this->stream, $length); - if (!$data) { + while (!feof( $this->stream)) { + $data .= fread($this->stream, 8192); + } + // Be sure to close the stream resource when you're done with it + if (!$data || strlen($data)!= $length) { return NULL; } return $data; @@ -137,5 +138,4 @@ public function retrieveEnd(int $length, int $offset = 0): ?string { return NULL; } } - } \ No newline at end of file