ディレクトリ構成と規約 - ha1t/php-gm-server GitHub Wiki

ディレクトリ構成と規約

php-gm-server プロジェクトのディレクトリ構成は、REACTPHPによるイベント駆動型Geminiサーバーを実装するため、機能別に整理されています。本ページはプロジェクトディレクトリ構成(bin/、src/、tests/、content/、certs/)、各ディレクトリの役割、ファイル配置規約、PSR-4オートロード規約、および.gitignoreでの除外ファイルについて説明します。本ページの内容は、プロジェクト概要およびアーキテクチャ設計と関連しています。

プロジェクトディレクトリ構造

php-gm-serverプロジェクトのトップレベルディレクトリ構成は、以下のとおりです。

php-gm-server/
├── bin/                    # 実行可能なエントリーポイント
├── src/                    # メインコンポーネント(GeminiServer、RequestParser等)
├── tests/                  # ユニットテスト
├── content/                # Geminiコンテンツ(.gmi ファイル)
├── certs/                  # TLS/SSL証明書
├── composer.json           # PHP依存パッケージ定義
├── phpunit.xml             # PHPUnit テスト設定
├── README.md               # プロジェクト説明
└── .gitignore              # Git除外ファイル定義

以下、各ディレクトリの詳細な役割と配置規約を説明します。

bin/ ディレクトリ

役割

bin/ディレクトリは、プロジェクトの実行可能なエントリーポイント(CLIスクリプト)を格納します。このディレクトリに配置されたPHPスクリプトは、コマンドラインから直接実行されます。

ファイル構成

ファイル 役割
server.php Geminiサーバーの起動スクリプト。環境変数を読み込み、証明書生成、サーバー初期化、実行ループ起動を行う。

コード例

bin/server.php(リポジトリ参照)は、以下の処理フローに従います。

  1. Composerオートローダーを読み込む(require __DIR__ . '/../vendor/autoload.php'
  2. 環境変数から設定値を取得する(GEMINI_HOST、GEMINI_PORT、GEMINI_DOC_ROOT、GEMINI_CERT_DIR、GEMINI_HOSTNAME)
  3. CertificateGeneratorで自己署名証明書を生成する
  4. StaticFileHandlerでドキュメントルートを初期化する
  5. GeminiServerを生成し、run()メソッドで実行ループを開始する
<?php
declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use GeminiServer\CertificateGenerator;
use GeminiServer\GeminiServer;
use GeminiServer\StaticFileHandler;

$host = getenv('GEMINI_HOST') ?: '0.0.0.0';
$port = (int) (getenv('GEMINI_PORT') ?: 1965);
$docRoot = getenv('GEMINI_DOC_ROOT') ?: __DIR__ . '/../content';
$certDir = getenv('GEMINI_CERT_DIR') ?: __DIR__ . '/../certs';
$hostname = getenv('GEMINI_HOSTNAME') ?: 'localhost';

$certGenerator = new CertificateGenerator($certDir);
$certPath = $certGenerator->generate($hostname);

$fileHandler = new StaticFileHandler($docRoot);
$server = new GeminiServer($host, $port, $fileHandler, $certPath);
$server->run();

出典: bin/server.php

src/ ディレクトリ

役割

src/ディレクトリは、Geminiサーバーの核となるコンポーネントクラスを格納します。REACTPHPベースのイベント駆動型実装により、非同期I/Oを実現しています。

ファイル構成と責務

ファイル クラス名 役割
GeminiServer.php GeminiServer TCP接続受け入れ、TLS/SSL化、リクエスト受信、バッファ管理、レスポンス送信を統括
RequestParser.php RequestParser Geminiリクエスト文字列(gemini://host/path\r\n)のパース、スキーム検証、ホスト名・パス抽出
ResponseBuilder.php ResponseBuilder Geminiプロトコル形式のレスポンス構築(STATUS SPACE META\r\n BODY)
StaticFileHandler.php StaticFileHandler ドキュメントルートに基づくファイル解決、ディレクトリハンドリング、MIMEタイプ判定、パストラバーサル防止
CertificateGenerator.php CertificateGenerator OpenSSL拡張を使用した自己署名TLS証明書生成、PEM形式での保存

PSR-4 オートロード規約

composer.jsonで以下のPSR-4マッピングが定義されています(composer.json参照)。

"autoload": {
    "psr-4": {
        "GeminiServer\\": "src/"
    }
}

PSR-4規約に従い、src/ディレクトリ内のクラスファイルは以下の命名規則で配置されます。

  • ファイル名 = クラス名 + .php

    • GeminiServer.phpGeminiServer クラス
    • RequestParser.phpRequestParser クラス
  • ネームスペース = ディレクトリ構造

    • src/GeminiServer\

例えば、src/GeminiServer.php内のクラス定義は以下のとおりです。

<?php
declare(strict_types=1);

namespace GeminiServer;

class GeminiServer
{
    // クラス実装
}

出典: src/GeminiServer.php:1-5

コンポーネント間の連携

各コンポーネント間の処理フローを以下のシーケンスダイアグラムで示します。

sequenceDiagram
    participant Client
    participant GeminiServer as GeminiServer
    participant RequestParser as RequestParser
    participant StaticFileHandler as FileHandler
    participant ResponseBuilder as ResponseBuilder
    
    Client ->> GeminiServer: TLSハンドシェイク
    GeminiServer ->> GeminiServer: バッファにデータ蓄積
    GeminiServer ->> RequestParser: リクエスト文字列をパース
    RequestParser -->> GeminiServer: ホスト・パス抽出結果
    GeminiServer ->> StaticFileHandler: ファイル解決要求
    StaticFileHandler -->> GeminiServer: (MIME, body)
    GeminiServer ->> ResponseBuilder: Geminiレスポンス構築
    ResponseBuilder -->> GeminiServer: ステータス・メタ・ボディ
    GeminiServer ->> Client: レスポンス送信
Loading

tests/ ディレクトリ

役割

tests/ディレクトリは、各コンポーネントのユニットテストを格納します。PHPUnitフレームワークを使用した自動テストで、実装の正確性を保証します。

ファイル構成

ファイル テスト対象クラス テスト対象
RequestParserTest.php RequestParser Geminiリクエストのパース処理、スキーム検証、ホスト名・パス抽出
ResponseBuilderTest.php ResponseBuilder Geminiレスポンス形式の構築、ステータスコード・メタ情報の正確性
StaticFileHandlerTest.php StaticFileHandler ファイル解決、ディレクトリハンドリング、MIMEタイプ判定、パストラバーサル防止検証
CertificateGeneratorTest.php CertificateGenerator 自己署名証明書の生成、PEM形式ファイルの作成、既存証明書の再利用

PSR-4 オートロード(テスト用)

composer.jsonで以下のPSR-4マッピングがテスト開発時に定義されています(composer.json参照)。

"autoload-dev": {
    "psr-4": {
        "GeminiServer\\Tests\\": "tests/"
    }
}

テストクラスはPSR-4規約に従い、以下の命名規則で配置されます。

  • ファイル名 = クラス名 + .php

    • RequestParserTest.phpRequestParserTest クラス
  • ネームスペース = GeminiServer\Tests + ディレクトリ構造

    • tests/GeminiServer\Tests\

テストクラスの例:

<?php
declare(strict_types=1);

namespace GeminiServer\Tests;

use GeminiServer\RequestParser;
use PHPUnit\Framework\TestCase;

class RequestParserTest extends TestCase
{
    public function testParseValidRequest(): void
    {
        $result = RequestParser::parse("gemini://example.com/hello.gmi\r\n");
        $this->assertSame('example.com', $result['host']);
        $this->assertSame('/hello.gmi', $result['path']);
    }
}

出典: tests/RequestParserTest.php:1-17

テスト実行

PHPUnitの実行設定はphpunit.xmlで定義されており、以下のコマンドでテストを実行します。

vendor/bin/phpunit

content/ ディレクトリ

役割

content/ディレクトリは、Geminiサーバーで配信するコンテンツファイルを格納します。デフォルトのドキュメントルート(GEMINI_DOC_ROOT)として機能します。環境変数で別のディレクトリに変更可能です。

ファイル構成

ファイル 用途
index.gmi ルートパス(/)へのアクセス時に配信されるメインページ。Gemini形式(text/gemini)のマークアップで記述。
sub.gmi サブディレクトリ内のコンテンツファイル。Gemini形式のページ。

Gemini形式(text/gemini)

Geminiコンテンツは.gmi拡張子を持つテキストファイルで、以下の形式に従います。

# Welcome to Gemini

This is a PHP Gemini server powered by ReactPHP.

## Links

=> gemini://geminiprotocol.net/ Gemini Protocol
=> gemini://geminiprotocol.net/docs/specification.gmi Gemini Specification

=> gemini://192.168.3.253/sub.gmi sub

## About

This server was built for a PHP study group presentation.

出典: content/index.gmi

ドキュメントルートの変更

環境変数GEMINI_DOC_ROOTで、ドキュメントルートを指定できます。指定しない場合、デフォルトは__DIR__ . '/../content'です。

export GEMINI_DOC_ROOT=/path/to/custom/content
php bin/server.php

certs/ ディレクトリ

役割

certs/ディレクトリは、GeminiサーバーのTLS/SSL証明書を格納します。CertificateGeneratorによって自動生成される自己署名証明書を保存します。

ファイル構成

ファイル 用途 権限
server.pem TLS/SSL証明書とRSA秘密鍵が格納されたPEM形式ファイル。GeminiServerが起動時に読み込む。 600(オーナー読み書き可のみ)

証明書の自動生成

CertificateGeneratorは、以下の条件で自動的に証明書を生成します。

  1. certs/ディレクトリが存在しない場合は、ディレクトリを作成する
  2. server.pemが存在しない場合は、新規に生成する
  3. 既存のserver.pemが存在する場合は、再利用する

環境変数により、証明書ディレクトリとホスト名を指定できます。

export GEMINI_CERT_DIR=/path/to/custom/certs
export GEMINI_HOSTNAME=example.com
php bin/server.php

出典: bin/server.php:14-15

.gitignore ファイル

役割と管理原則

.gitignoreファイルは、Gitレポジトリに追跡させないファイルを指定します。php-gm-serverでは、以下のファイル・ディレクトリをGit管理の対象外としています。

除外ファイル定義

/vendor/
/certs/
composer.lock

各除外定義の詳細:

除外対象 理由
/vendor/ Composerが管理する依存パッケージ。composer.jsonとcomposer.lockで復元可能なため、Gitレポジトリに含めない。
/certs/ サーバーの自己署名TLS証明書ディレクトリ。開発環境・本番環境ごとに異なる証明書が生成されるため、レポジトリに含めない。
composer.lock Composerの依存パッケージロックファイル。複数の開発環境での一貫性保証には有用だが、本プロジェクトではcomposer.jsonで十分とする設計判断。

出典: .gitignore

PSR-4 オートロード規約

PSR-4とは

PSR-4(PHP Standards Recommendation 4)は、PHPのクラスオートロード規約です。ファイルシステム上のディレクトリ構造とPHPのネームスペース構造を対応させることで、自動でクラスを読み込みます。

composer.jsonでの設定

php-gm-serverでは、composer.jsonで以下の2つのPSR-4マッピングを定義しています。

{
    "autoload": {
        "psr-4": {
            "GeminiServer\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "GeminiServer\\Tests\\": "tests/"
        }
    }
}

出典: composer.json:13-22

PSR-4命名規則

PSR-4規約に従い、以下の対応が成立します。

メインコンポーネント

ファイルパス ネームスペース\クラス名 説明
src/GeminiServer.php GeminiServer\GeminiServer メインサーバークラス
src/RequestParser.php GeminiServer\RequestParser リクエストパーサー
src/ResponseBuilder.php GeminiServer\ResponseBuilder レスポンスビルダー
src/StaticFileHandler.php GeminiServer\StaticFileHandler ファイルハンドラー
src/CertificateGenerator.php GeminiServer\CertificateGenerator 証明書ジェネレーター

テストクラス

ファイルパス ネームスペース\クラス名
tests/RequestParserTest.php GeminiServer\Tests\RequestParserTest
tests/ResponseBuilderTest.php GeminiServer\Tests\ResponseBuilderTest
tests/StaticFileHandlerTest.php GeminiServer\Tests\StaticFileHandlerTest
tests/CertificateGeneratorTest.php GeminiServer\Tests\CertificateGeneratorTest

オートロード機構

Composerのオートローダーは、スクリプト実行時にvendor/autoload.phpを読み込むことで機能します。bin/server.phpの例:

require __DIR__ . '/../vendor/autoload.php';

use GeminiServer\CertificateGenerator;
use GeminiServer\GeminiServer;
use GeminiServer\StaticFileHandler;

// 以降、クラス名でインスタンス化可能
$certGenerator = new CertificateGenerator($certDir);
$fileHandler = new StaticFileHandler($docRoot);
$server = new GeminiServer($host, $port, $fileHandler, $certPath);

出典: bin/server.php:5-22

ディレクトリ構成図

プロジェクト全体のディレクトリ構成と各要素の関係性を以下のダイアグラムで示します。

graph TD
    A["php-gm-server/"] --> B["bin/"]
    A --> C["src/"]
    A --> D["tests/"]
    A --> E["content/"]
    A --> F["certs/"]
    A --> G["composer.json<br/>phpunit.xml<br/>.gitignore"]
    
    B --> B1["server.php<br/>エントリーポイント"]
    
    C --> C1["GeminiServer.php<br/>接続管理"]
    C --> C2["RequestParser.php<br/>リクエスト解析"]
    C --> C3["ResponseBuilder.php<br/>レスポンス構築"]
    C --> C4["StaticFileHandler.php<br/>ファイル配信"]
    C --> C5["CertificateGenerator.php<br/>証明書生成"]
    
    D --> D1["RequestParserTest.php"]
    D --> D2["ResponseBuilderTest.php"]
    D --> D3["StaticFileHandlerTest.php"]
    D --> D4["CertificateGeneratorTest.php"]
    
    E --> E1["index.gmi<br/>Geminiコンテンツ"]
    E --> E2["sub.gmi"]
    
    F --> F1["server.pem<br/>TLS証明書"]
    
    G --> G1["設定ファイル"]
    
    style B1 fill:#e1f5ff
    style C1 fill:#f3e5f5
    style C2 fill:#f3e5f5
    style C3 fill:#f3e5f5
    style C4 fill:#f3e5f5
    style C5 fill:#f3e5f5
    style D1 fill:#f1f8e9
    style D2 fill:#f1f8e9
    style D3 fill:#f1f8e9
    style D4 fill:#f1f8e9
    style E1 fill:#fff3e0
    style E2 fill:#fff3e0
    style F1 fill:#fce4ec
Loading

ファイル配置規約のまとめ

以下のテーブルは、ファイル配置規約の全体像をまとめたものです。

階層 ディレクトリ ファイル形式 ネームスペース 用途
実行 bin/ .php N/A CLIエントリーポイント
コンポーネント src/ .php GeminiServer\ コアロジック実装
テスト tests/ .php GeminiServer\Tests\ ユニットテスト
コンテンツ content/ .gmi N/A Gemini形式ドキュメント
証明書 certs/ .pem N/A TLS/SSL証明書
設定 プロジェクトルート .json.xml.md N/A プロジェクト設定・ドキュメント

開発時の配置規約

新しいコンポーネントを追加する際は、以下の規約に従ってください。

  1. コアロジックsrc/ディレクトリに配置

    • ファイル名はクラス名と同一にする(例:MyComponent.php
    • ネームスペースはGeminiServer\として定義する
  2. ユニットテストtests/ディレクトリに配置

    • ファイル名はテスト対象クラス名にTestサフィックスを付ける(例:MyComponentTest.php
    • ネームスペースはGeminiServer\Tests\として定義する
    • テストクラス名はテスト対象クラス名にTestサフィックスを付ける(例:class MyComponentTest extends TestCase
  3. Geminiコンテンツcontent/ディレクトリに配置

    • ファイル拡張子は.gmiとする
    • テキスト形式のGeminiプロトコル仕様に準拠する

Related Pages

⚠️ **GitHub.com Fallback** ⚠️