diff --git a/http-server/Constrict/DownloadEmitter.php b/http-server/Constrict/DownloadEmitter.php deleted file mode 100644 index d3c10ae1..00000000 --- a/http-server/Constrict/DownloadEmitter.php +++ /dev/null @@ -1,81 +0,0 @@ - 'image/png', - 'jpeg' => 'image/jpeg', - 'gif' => 'image/gif', - 'bmp' => 'image/bmp', - 'ico' => 'image/vnd.microsoft.icon', - 'tiff' => 'image/tiff', - 'svg' => 'image/svg+xml', - ]; - - - /** - * @param mixed $response - * @param ResponseInterface $emitter - * @throws NotFindClassException - * @throws ReflectionException - */ - public function sender(mixed $response, ResponseInterface $emitter): void - { - $content = $emitter->getContent()->getData(); - - $explode = explode('/', $content['path']); - - $response->header('Pragma', 'public'); - $response->header('Expires', '0'); - $response->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); - $response->header('Content-Disposition', 'attachment;filename=' . end($explode)); - $response->header('Content-Type', $type = get_file_extension($content['path'])); - if (!in_array($type, self::IMAGES)) { - $response->header('Content-Transfer-Encoding', 'binary'); - } else { - $response->end(file_get_contents($content['path'])); - return; - } - if ($content['isChunk'] === false) { - $response->sendfile($content['path']); - } else { - $this->chunk($content, $response); - } - } - - - /** - * @param $content - * @param $response - */ - private function chunk($content, $response): void - { - $resource = fopen($content['path'], 'r'); - - $state = fstat($resource); - - $offset = $content['offset']; - - $response->header('Content-length', $state['size']); - while ($file = fread($resource, $content['limit'])) { - $response->write($file); - fseek($resource, $offset); - if ($offset >= $state['size']) { - break; - } - $offset += $content['limit']; - } - $response->end(); - } -} diff --git a/http-server/Constrict/Request.php b/http-server/Constrict/Request.php index cc86b726..295edd23 100644 --- a/http-server/Constrict/Request.php +++ b/http-server/Constrict/Request.php @@ -50,7 +50,7 @@ class Request implements RequestInterface /** * @param \Swoole\Http\Request $request - * @return array + * @return array */ public static function create(\Swoole\Http\Request $request): array { diff --git a/http-server/Constrict/ResponseEmitter.php b/http-server/Constrict/ResponseEmitter.php index d64aa164..f6d57b1f 100644 --- a/http-server/Constrict/ResponseEmitter.php +++ b/http-server/Constrict/ResponseEmitter.php @@ -5,6 +5,7 @@ namespace Server\Constrict; use Annotation\Inject; use Psr\Http\Message\ResponseInterface; use Server\RequestInterface; +use Server\SInterface\DownloadInterface; use Swoole\Server; @@ -41,7 +42,12 @@ class ResponseEmitter implements Emitter $response->setStatusCode($emitter->getStatusCode()); $response->header('Server', 'swoole'); $response->header('Swoole-Version', swoole_version()); - $response->end($emitter->getBody()); + + if (!($emitter instanceof DownloadInterface)) { + $response->end($emitter->getBody()); + } else { + $emitter->dispatch($response); + } } } diff --git a/http-server/Message/Download.php b/http-server/Message/Download.php new file mode 100644 index 00000000..e2ae8ba8 --- /dev/null +++ b/http-server/Message/Download.php @@ -0,0 +1,105 @@ + 'image/png', + 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'svg' => 'image/svg+xml', + ]; + + + /** + * @param string $path + * @param false $isChunk + * @param int $size + * @param int $offset + * @return $this + */ + public function path(string $path, bool $isChunk = false, int $size = -1, int $offset = 0): Download + { + $this->path = $path; + $this->isChunk = $isChunk; + $this->size = $size; + $this->offset = $offset; + return $this->emitter(); + } + + + /** + * @return $this + */ + public function emitter(): static + { + $explode = explode('/', $this->path); + $this->withHeader('Pragma', 'public'); + $this->withHeader('Expires', '0'); + $this->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); + $this->withHeader('Content-Disposition', 'attachment;filename=' . end($explode)); + $this->withHeader('Content-Type', $type = get_file_extension($this->path)); + if (!in_array($type, self::IMAGES)) { + $this->withHeader('Content-Transfer-Encoding', 'binary'); + } + if ($this->isChunk) { + $resource = fopen($this->path, 'r'); + + $state = fstat($resource); + + $this->withHeader('Content-length', $state['size']); + } + return $this; + } + + + /** + * @param \Swoole\Http\Response $response + */ + public function dispatch(mixed $response) + { + if (!$this->isChunk) { + $response->sendfile($this->path); + } else { + $this->chunk($response); + } + } + + + /** + * @param \Swoole\Http\Response $response + */ + private function chunk(\Swoole\Http\Response $response): void + { + $resource = fopen($this->path, 'r'); + + $state = fstat($resource); + + $offset = $this->offset; + while ($file = fread($resource, $this->size)) { + $response->write($file); + fseek($resource, $offset); + if ($offset >= $state['size']) { + break; + } + $offset += $this->size; + } + $response->end(); + } +} diff --git a/http-server/Message/Response.php b/http-server/Message/Response.php index 5c8f2c99..dc3bca97 100644 --- a/http-server/Message/Response.php +++ b/http-server/Message/Response.php @@ -7,6 +7,7 @@ use JetBrains\PhpStorm\Pure; use Kiri\Core\Help; use Kiri\ToArray; use Psr\Http\Message\ResponseInterface; +use Server\SInterface\DownloadInterface; /** @@ -174,6 +175,24 @@ class Response implements ResponseInterface, \Server\ResponseInterface } + /** + * @param $path + * @param bool $isChunk + * @param int $size + * @param int $offset + * @return DownloadInterface + * @throws Exception + */ + public function file($path, bool $isChunk = false, int $size = -1, int $offset = 0): DownloadInterface + { + $path = realpath($path); + if (!file_exists($path) || !is_readable($path)) { + throw new Exception('Cannot read file "' . $path . '", no permission'); + } + return (new Download())->path($path, $isChunk, $size, $offset); + } + + /** * @param $responseData * @return string|array|bool|int|null diff --git a/http-server/SInterface/DownloadInterface.php b/http-server/SInterface/DownloadInterface.php new file mode 100644 index 00000000..6c753ca4 --- /dev/null +++ b/http-server/SInterface/DownloadInterface.php @@ -0,0 +1,12 @@ +router->Branch_search($request);