summaryrefslogtreecommitdiff
path: root/src/Server/RequestHandlers/DocumentServer.php
blob: e55a8911a3d516906cb9513e9d3fed7cc09988ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

namespace GeminiFoundation\Server\RequestHandlers;

use GeminiFoundation\Request;
use GeminiFoundation\RequestHandlerInterface;
use GeminiFoundation\Response;
use GeminiFoundation\Status;
use function GeminiFoundation\mime_content_type;

class DocumentServer implements RequestHandlerInterface
{
  protected string $documentRoot;
  protected string $indexFile;
  protected bool $useDirectoryListing;

  public function __construct(
    string $documentRoot = '',
    string $indexFile = 'index.gmi',
    bool $useDirectoryListing = false
  )
  {
    $this->documentRoot = $documentRoot ?: getcwd();
    $this->indexFile = $indexFile;
    $this->useDirectoryListing = $useDirectoryListing;
  }

  public function __invoke(Response $response, Request $request): Response
  {
    $requestPath = $this->trim(urldecode($request->getPath()));
    $filePath = $this->documentRoot . $requestPath;

    $documentPath = $filePath;
    if (! is_file($documentPath)) {
      $documentPath = $filePath . '/' . $this->indexFile;
    }

    if (is_file($documentPath)) {
      $content = file_get_contents($documentPath);
      $response->setBody($content);

      $response->setStatusCode(Status::SUCCESS);
      $response->setMeta(mime_content_type($documentPath) . '; charset=utf-8');
    } else if ($this->useDirectoryListing && is_dir($filePath)) {
      $body = '';
      foreach (scandir($filePath) as $fileName) {
        $link = implode('/', array_map('urlencode', explode('/', "$requestPath/$fileName")));
        $body .= "=> $link $fileName \r\n";
      }

      $response->setBody($body);
      $response->setStatusCode(Status::SUCCESS);
      $response->setMeta('text/gemini; charset=utf-8');
    } else {
      $response->setStatusCode(Status::NOT_FOUND);
    }

    return $response;
  }

  private function trim(string $string)
  {
    return str_ends_with($string, '/') ? substr($string, offset: 0, length: -1) : $string;
  }
}