PHPackages                             richarddern/php-gemini - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. richarddern/php-gemini

AbandonedArchivedLibrary[Utility &amp; Helpers](/categories/utility)

richarddern/php-gemini
======================

Project Gemini library for PHP

161PHP

Since Feb 26Pushed 5y ago1 watchersCompare

[ Source](https://github.com/RichardDern/php-gemini)[ Packagist](https://packagist.org/packages/richarddern/php-gemini)[ RSS](/packages/richarddern-php-gemini/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

> Project moved to  !

php-gemini
==========

[](#php-gemini)

php-gemini is a library implementing the [Project Gemini protocol](https://gemini.circumlunar.space), as both client and server-side.

Installation
------------

[](#installation)

```
composer require richarddern/php-gemini
```

Common features
---------------

[](#common-features)

- Supports TLS from both client and server-side, thanks to [react/socket](https://reactphp.org/socket/)
- A script is included to generate your own self-signed certificate in case you don't or can't use an official one
- URIs are parsed, validated, and resolved, so you can use relative URIs as well, thanks to [league/uri](https://uri.thephpleague.com)
- Extensive logging, thanks to [monolog](https://github.com/Seldaek/monolog)
- Filesystem abstraction provided by [league/flysystem](https://flysystem.thephpleague.com/v2/docs/)allowing you to serve files from various locations

Documentation
-------------

[](#documentation)

### Client

[](#client)

To query a remote server, you first need to instanciate the *Client* class:

```
use RichardDern\Gemini\Client;

// This will connect to a server running on the same computer
$client = new Client();

// This will connect to a remote server on default port
//$client = new Client('gemini.circumlunar.space');

// And this will connect to a server using a custom port
//$client = new Client('10.0.0.1', 1966);

// You can define the server and remote port after instanciating the class,
// or whenever you want before your query:
$client->setServer('127.0.0.1');
$client->setPort(1965);
```

You are ready to query the server:

```
// You can define the base URI that will be used to resolve subsequent
// relative queries
$client->setBaseUri('gemini://127.0.0.1:1965/absolute_path');

// This will then resolve to
// gemini://127.0.0.1:1965/absolute_path/relative_path/document
$client->request('relative_path/document');

// Or, you can request an absolute URI directly:
$client->request('gemini://127.0.0.1:1965/absolute_path/relative_path/document');
```

The result will be a *RichardDern\\Gemini\\Response* object which exposes the following properties:

- *$status*, a two-digits status code ; you can see the full list of status codes in [Gemini's specifications](https://gemini.circumlunar.space/docs/specification.html), Appendix 1
- *$meta*, containing various informations about the response such as MIME type, redirect URL or language, depending on server's response
- *$body*, the raw, unformated content of response body

### Server

[](#server)

This library also allows you to run a Gemini server with ease.

```
use RichardDern\Gemini\Server;

// This will create a server on 127.0.0.1 and listening on default port (1965)
$server = new Server();

// You can set the binding address and port when instanciating the class...
//$server = new Server('[::1]', 1966);

// ...or after
$server->setAddress('[::1]');
$server->setPort(1965);
```

You are required to provide the server with the path to a certificate file prior to actually start the server.

```
$server->setCertificatePath('./localhost.pem');
```

You can use the provided *bin/generate-self-signed-certificate.php* file.

```
php ./bin/generate-self-signed-certificate.php > localhost.pem
```

This implementation support basic directory indexing, but you need to enable it manually.

```
$server->enableDirectoryIndex(true);
```

This implementation allows you to serve files from various file systems, including the local file system as well as a FTP server, or even in-memory file system. Please look at the [league/flysystem](https://flysystem.thephpleague.com/v2/docs/)documentation to find out which adapters you can use.

Unless specified otherwise, the server will use the *LocalFilesystemAdapter*, and will look for files in a *www* folder located where you launched the server from.

However, you can use a different adapter if you want:

```
// Serving files on Gemini from a FTP site
$adapter = new League\Flysystem\Ftp\FtpAdapter(
    // Connection options
    League\Flysystem\Ftp\FtpConnectionOptions::fromArray([
        'host' => 'hostname', // required
        'root' => '/root/path/', // required
        'username' => 'username', // required
        'password' => 'password', // required
        'port' => 21
    ])
);

$server->setFileSystemAdapter($adapter);
```

You can then start your server:

```
$server->start();
```

You will need to use a process manager to ensure your server is kept running. You could use systemd or supervisor to do this. The documentation will soon be updated with some examples.

### Logging

[](#logging)

Both client and server use the same methods to configure logging. You should set up logging to fit your needs right after you instanciated the client or the server.

```
$client = new Client();

// You can define the log level
$client->setLogLevel(Logger::DEBUG);

// Here, we will define a simple StreamHandler, but we will choose where to log
$handler = new StreamHandler('/var/log/gemini.log', Logger::INFO);
$client->setLogHandler($handler);

// The channel will help you find your way into the logs
$client->setLogChannel('my-gemini-client');
```

Author
------

[](#author)

Richard Dern -

License
-------

[](#license)

MIT

Alternatives
------------

[](#alternatives)

- [Ergol](http://adele.work/code/ergol/ergol.gmi) - Can use one cert per vhost, supports HTTP delivery with CSS

###  Health Score

17

—

LowBetter than 6% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity30

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/6979477d9d81aa7da0b55c1a52dafcc1db763d8bf97105e54d6cad17afceec7a?d=identicon)[RichardDern](/maintainers/RichardDern)

---

Top Contributors

[![RichardDern](https://avatars.githubusercontent.com/u/52763458?v=4)](https://github.com/RichardDern "RichardDern (2 commits)")

### Embed Badge

![Health badge](/badges/richarddern-php-gemini/health.svg)

```
[![Health](https://phpackages.com/badges/richarddern-php-gemini/health.svg)](https://phpackages.com/packages/richarddern-php-gemini)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
