• Stars
    star
    171
  • Rank 222,266 (Top 5 %)
  • Language
    PHP
  • License
    MIT License
  • Created about 8 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Finally a sane way to register available commands and arguments and match your command line in PHP

clue/commander

CI status installs on Packagist

Finally a sane way to register available commands and arguments and match your command line in PHP.

You want to build a command line interface (CLI) tool in PHP which accepts additional arguments and you now want to route these to individual functions? Then this library is for you!

This is also useful for interactive CLI tools or anywhere where you can break up a command line string into an array of command line arguments and you now want to execute individual functions depending on the arguments given.

Table of contents

Support us

We invest a lot of time developing, maintaining and updating our awesome open-source projects. You can help us sustain this high-quality of our work by becoming a sponsor on GitHub. Sponsors get numerous benefits in return, see our sponsoring page for details.

Let's take these projects to the next level together! 🚀

Quickstart example

The following example code demonstrates how this library can be used to build a very simple command line interface (CLI) tool that accepts command line arguments passed to this program:

$router = new Clue\Commander\Router();
$router->add('exit [<code:uint>]', function (array $args) {
    exit(isset($args['code']) ? $args['code'] : 0);
});
$router->add('sleep <seconds:uint>', function (array $args) {
    sleep($args['seconds']);
});
$router->add('echo <words>...', function (array $args) {
    echo join(' ', $args['words']) . PHP_EOL;
});
$router->add('[--help | -h]', function () use ($router) {
    echo 'Usage:' . PHP_EOL;
    foreach ($router->getRoutes() as $route) {
        echo '  ' .$route . PHP_EOL;
    }
});

$router->execArgv();

See also the examples.

Usage

Router

The Router is the main class in this package.

It is responsible for registering new Routes, matching the given args against these routes and then executing the registered route callback.

$router = new Router();

Advanced usage: The Router accepts an optional Tokenizer instance as the first parameter to the constructor.

add()

The add(string $route, callable $handler): Route method can be used to register a new Route with this Router.

It accepts a route expression to match and a route callback that will be executed when this route expression matches.

This is very similar to how common PHP (micro-)frameworks offer "HTTP routers" to route incoming HTTP requests to the corresponding "controller functions":

$route = $router->add($path, $fn);

The route expression uses a custom domain-specific language (DSL) which aims to be so simple that both consumers of this library (i.e. developers) and users of your resulting tools should be able to understand them.

Note that this is a left-associative grammar (LAG) and all tokens are greedy. This means that the tokens will be processed from left to right and each token will try to match as many of the input arguments as possible. This implies that certain route expressions make little sense, such as having an optional argument after an argument with ellipses. For more details, see below.

You can use an empty string like this to match when no arguments have been given:

$router->add('', function() {
    echo 'No arguments given. Need help?' . PHP_EOL;
});
// matches: (empty string)
// does not match: hello (too many arguments)

You can use any number of static keywords like this:

$router->add('user list', function () {
    echo 'Here are all our users…' . PHP_EOL;
});
// matches: user list
// does not match: user (missing required keyword)
// does not match: user list hello (too many arguments)

You can use alternative blocks to support any of the static keywords like this:

$router->add('user (list | listing | ls)', function () {
    echo 'Here are all our users…' . PHP_EOL;
});
// matches: user list
// matches: user listing
// matches: user ls
// does not match: user (missing required keyword)
// does not match: user list hello (too many arguments)

Note that alternative blocks can be added to pretty much any token in your route expression. Note that alternative blocks do not require parentheses and the alternative mark (|) always works at the current block level, which may not always be obvious. Unless you add some parentheses, a b | c d will be be interpreted as (a b) | (c d) by default. Parentheses can be used to interpret this as a (b | c) d instead. In particular, you can also combine alternative blocks with optional blocks (see below) in order to optionally accept only one of the alternatives, but not multiple.

You can use any number of placeholders to mark required arguments like this:

$router->add('user add <name>', function (array $args) {
    assert(is_string($args['name']));
    var_dump($args['name']);
});
// matches: user add clue
// does not match: user add (missing required argument)
// does not match: user add hello world (too many arguments)
// does not match: user add --test (argument looks like an option)

// matches: user add -- clue     (value: clue)
// matches: user add -- --test   (value: --test)
// matches: user add -- -nobody- (value: -nobody-)
// matches: user add -- --       (value: --)

Note that arguments that start with a dash (-) are not simply accepted in the user input, because they may be confused with (optional) options (see below). If users wish to process arguments that start with a dash (-), they either have to use filters (see below) or may use a double dash separator (--), as everything after this separator will be processed as-is. See also the last examples above that demonstrate this behavior.

You can use one the predefined filters to limit what values are accepted like this:

$router->add('user ban <id:int> <force:bool>', function (array $args) {
    assert(is_int($args['id']));
    assert(is_bool($args['force']));
});
// matches: user ban 10 true
// matches: user ban 10 0
// matches: user ban -10 yes
// matches: user ban -- -10 no
// does not match: user ban 10 (missing required argument)
// does not match: user ban hello true (invalid value does not validate)

Note that the filters also return the value casted to the correct data type. Also note how using the double dash separator (--) is optional when matching a filtered value. The following predefined filters are currently available:

  • int accepts any positive or negative integer value, such as 10 or -4
  • uint accepts any positive (unsigned) integer value, such 10 or 0
  • float accepts any positive or negative float value, such as 1.5 or -2.3
  • ufloat accepts any positive (unsigned) float value, such as 1.5 or 0
  • bool accepts any boolean value, such as yes/true/1 or no/false/0

If you want to add a custom filter function, see also Tokenizer for advanced usage below.

You can mark arguments as optional by enclosing them in square brackets like this:

$router->add('user search [<query>]', function (array $args) {
    assert(!isset($args['query']) || is_string($args['query']));
    var_dump(isset($args['query']);
});
// matches: user search
// matches: user search clue
// does not match: user search hello world (too many arguments)

Note that square brackets can be added to pretty much any token in your route expression, however they are most commonly used for arguments as above or for optional options as below. Optional tokens can appear anywhere in the route expression, but keep in mind that the tokens will be matched from left to right, so if the optional token matches, then the remainder will be processed by the following tokens. As a rule of thumb, make sure optional tokens are near the end of your route expressions and you won't notice this subtle effect. Optional blocks accept alternative groups, so that [a | b] is actually equivalent to the longer form [(a | b)]. In particular, this is often used for alternative options as below.

You can accept any number of arguments by appending ellipses like this:

$router->add('user delete <names>...', function (array $args) {
    assert(is_array($args);
    assert(count($args) > 0);
    var_dump($args['names']);
});
// matches: user delete clue
// matches: user delete hello world
// does not match: user delete (missing required argument)

Note that trailing ellipses can be added to any argument, word or option token in your route expression. They are most commonly used for arguments as above. The above requires at least one argument, see the following if you want this to be completely optional. Technically, the ellipse tokens can appear anywhere in the route expression, but keep in mind that the tokens will be matched from the left to the right, so if the ellipse matches, it will consume all input arguments and not leave anything for following tokens. As a rule of thumb, make sure ellipse tokens are near the end of your route expression and you won't notice this subtle effect.

You can accept any number of optional arguments by appending ellipses within square brackets like this:

$router->add('user dump [<names>...]', function (array $args) {
    if (isset($args['names'])) {
        assert(is_array($args);
        assert(count($args) > 0);
        var_dump($args['names']);
    } else {
        var_dump('no names');
    }
});
// matches: user dump
// matches: user dump clue
// matches: user dump hello world

The above does not require any arguments, it works with zero or more arguments.

You can add any number of optional short or long options like this:

$router->add('user list [--json] [-f]', function (array $args) {
    assert(!isset($args['json']) || $args['json'] === false);
    assert(!isset($args['f']) || $args['f'] === false);
});
// matches: user list
// matches: user list --json
// matches: user list -f
// matches: user list -f --json
// matches: user -f list
// matches: --json user list

As seen in the example, options in the $args array can either be unset when they have not been passed in the user input or set to false when they have been passed (which is in line with how other parsers such as getopt() work). Note that options are accepted anywhere in the user input argument, regardless of where they have been defined. Note that the square brackets are in the route expression are required to mark this optional as optional, you can also omit these square brackets if you really want a required option.

You can combine short and long options in an alternative block like this:

$router->add('user setup [--help | -h]', function (array $args) {
    assert(!isset($args['help']) || $args['help'] === false);
    assert(!isset($args['h']) || $args['h'] === false);
    assert(!isset($args['help'], $args['h']); 
});
// matches: user setup
// matches: user setup --help
// matches: user setup -h
// does not match: user setup --help -h (only accept eithers, not both)

As seen in the example, this optionally accepts either the short or the long option anywhere in the user input, but never both at the same time.

You can optionally accept or require values for short and long options like this:

$router->add('[--sort[=<param>]] [-i=<start:int>] user list', function (array $args) {
    assert(!isset($args['sort']) || $args['sort'] === false || is_string($args['sort']));
    assert(!isset($args['i']) || is_int($args['i']));
});
// matches: user list
// matches: user list --sort
// matches: user list --sort=size
// matches: user list --sort size
// matches: user list -i=10
// matches: user list -i 10
// matches: user list -i10
// matches: user list -i=-10
// matches: user list -i -10
// matches: user list -i-10
// matches: user -i=10 list
// matches: --sort -- user list
// matches: --sort size user list
// matches: user list --sort -i=10
// does not match: user list -i (missing option value)
// does not match: user list -i --sort (missing option value)
// does not match: user list -i=a (invalid value does not validate)
// does not match: --sort user list (user will be interpreted as option value)
// does not match: user list --sort -2 (value looks like an option)

As seen in the example, option values in the $args array will be given as strings or their filtered and casted value if passed in the user input. Both short and long options can accept values with the recommended equation symbol syntax (-i=10 and --sort=size respectively) in the user input. Both short and long options can also accept values with the common space-separated syntax (-i 10 and --sort size respectively) in the user input. Short options can also accept values with the common concatenated syntax with no separator inbetween (-i10) in the user input. Note that it is highly recommended to always make sure any options that accept values are near the left side of your route expression. This is needed in order to make sure space-separated values are consumed as option values instead of being misinterpreted as keywords or arguments.

You can limit the values for short and long options to a given preset like this:

$router->add('[--ask=(yes | no)] [-l[=0]] user purge', function (array $args) {
    assert(!isset($args['ask']) || $args['sort'] === 'yes' || $args['sort'] === 'no');
    assert(!isset($args['l']) || $args['l'] === '0');
});
// matches: user purge
// matches: user purge --ask=yes
// matches: user purge --ask=no
// matches: user purge -l
// matches: user purge -l=0
// matches: user purge -l 0
// matches: user purge -l0
// matches: user purge -l --ask=no
// does not match: user purge --ask (missing option value)
// does not match: user purge --ask=maybe (invalid option value)
// does not match: user purge -l4 (invalid option value)

As seen in the example, option values can be restricted to a given preset of values by using any of the above tokens. Technically, it's valid to use any of the above tokens to restrict the option values. In practice, this is mostly used for static keyword tokens or alternative groups thereof. It's recommended to always use parentheses for optional groups, however they're not strictly required within options with optional values. This also helps making it more obvious [--ask=(yes | no)] would accept either option value, while the (less useful) expression [--ask=yes | no] would accept either the option --ask=yes or the static keyword no.

remove()

The remove(Route $route): void method can be used to remove the given Route object from the registered routes.

$route = $router->add('hello <name>', $fn);
$router->remove($route);

It will throw an UnderflowException if the given route does not exist.

getRoutes()

The getRoutes(): Route[] method can be used to return an array of all registered Route objects.

echo 'Usage help:' . PHP_EOL;
foreach ($router->getRoutes() as $route) {
    echo $route . PHP_EOL;
}

This array will be empty if you have not added any routes yet.

execArgv()

The execArgv(array $argv = null): void method can be used to execute by matching the argv against all registered routes and then exit.

You can explicitly pass in your $argv or it will automatically use the values from the $_SERVER superglobal. The argv is an array that will always start with the calling program as the first element. We simply ignore this first element and then process the remaining elements according to the registered routes.

This is a convenience method that will match and execute a route and then exit the program without returning.

If no route could be found or if the route callback throws an Exception, it will print out an error message to STDERR and set an appropriate non-zero exit code.

Note that this is for convenience only and only useful for the most simple of all programs. If you need more control, then consider using the underlying handleArgv() method and handle any error situations yourself.

handleArgv()

The handleArgv(array $argv = null): mixed method can be used to execute by matching the argv against all registered routes and then return.

You can explicitly pass in your $argv or it will automatically use the values from the $_SERVER superglobal. The argv is an array that will always start with the calling program as the first element. We simply ignore this first element and then process the remaining elements according to the registered routes.

Unlike execArgv() this method will try to execute the route callback and then return whatever the route callback returned.

$router->add('hello <name>', function (array $args) {
    return strlen($args[$name]);
});

$length = $router->handleArgv(array('program', 'hello', 'test'));

assert($length === 4);

If no route could be found, it will throw a NoRouteFoundException.

// throws NoRouteFoundException
$router->handleArgv(array('program', 'invalid'));

If the route callback throws an Exception, it will pass through this Exception.

$router->add('hello <name>', function (array $args) {
    if ($args['name'] === 'admin') {
        throw new InvalidArgumentException();
    }
    
    return strlen($args['name']);
});

// throws InvalidArgumentException
$router->handleArgv(array('program', 'hello', 'admin'));

handleArgs()

The handleArgs(array $args): mixed method can be used to execute by matching the given args against all registered routes and then return.

Unlike handleArgv() this method will use the complete $args array to match the registered routes (i.e. it will not ignore the first element). This is particularly useful if you build this array yourself or if you use an interactive command line interface (CLI) and ask your user to supply the arguments.

$router->add('hello <name>', function (array $args) {
    return strlen($args[$name]);
});

$length = $router->handleArgs(array('hello', 'test'));

assert($length === 4);

The arguments have to be given as an array of individual elements. If you only have a command line string that you want to split into an array of individual command line arguments, consider using clue/arguments.

$line = fgets(STDIN, 2048);
assert($line === 'hello "Christian Lück"');

$args = Clue\Arguments\split($line);
assert($args === array('hello', 'Christian Lück'));

$router->handleArgs($args);

If no route could be found, it will throw a NoRouteFoundException.

// throws NoRouteFoundException
$router->handleArgs(array('invalid'));

If the route callback throws an Exception, it will pass through this Exception.

$router->add('hello <name>', function (array $args) {
    if ($args['name'] === 'admin') {
        throw new InvalidArgumentException();
    }
    
    return strlen($args['name']);
});

// throws InvalidArgumentException
$router->handleArgs(array('hello', 'admin'));

Route

The Route represents a single registered route within the Router.

It holds the required route tokens to match and the route callback to execute if this route matches.

See Router.

NoRouteFoundException

The NoRouteFoundException will be raised by handleArgv() or handleArgs() if no matching route could be found. It extends PHP's built-in RuntimeException.

Tokenizer

The Tokenizer class is responsible for parsing a route expression into a valid token instance. This class is mostly used internally and not something you have to worry about in most cases.

If you need custom logic for your route expression, you may explicitly pass an instance of your Tokenizer to the constructor of the Router:

$tokenizer = new Tokenizer();

$router = new Router($tokenizer);

addFilter()

The addFilter(string $name, callable $filter): void method can be used to add a custom filter function.

The filter name can then be used in argument or option expressions such as add <name:lower> or --search=<address:ip>.

The filter function will be invoked with the filter value and MUST return a boolean success value if this filter accepts the given value. The filter value will be passed by reference, so it can be updated if the filtering was successful.

$tokenizer = new Tokenizer();
$tokenizer->addFilter('ip', function ($value) {
    return filter_var($ip, FILTER_VALIDATE_IP);
});
$tokenizer->addFilter('lower', function (&$value) {
    $value = strtolower($value);
    return true;
});

$router = new Router($tokenizer);
$router->add('add <name:lower>', function ($args) { });
$router->add('--search=<address:ip>', function ($args) { });

Install

The recommended way to install this library is through Composer. New to Composer?

This project follows SemVer. This will install the latest supported version:

$ composer require clue/commander:^1.4

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP extensions and supports running on legacy PHP 5.3 through current PHP 8+ and HHVM. It's highly recommended to use PHP 7+ for this project.

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

$ composer install

To run the test suite, go to the project root and run:

$ php vendor/bin/phpunit

License

This project is released under the permissive MIT license.

Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

More

  • If you want to build an interactive CLI tool, you may want to look into using clue/reactphp-stdio in order to react to commands from STDIN.
  • If you build an interactive CLI tool that reads a command line from STDIN, you may want to use clue/arguments in order to split this string up into its individual arguments.

More Repositories

1

stream-filter

A simple and modern approach to stream filtering in PHP
PHP
1,608
star
2

phar-composer

Simple phar creation for every PHP project managed via Composer
PHP
858
star
3

graph-composer

Dependency graph visualization for composer.json (PHP + Composer)
PHP
852
star
4

framework-x

Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.
PHP
718
star
5

reactphp-buzz

[Deprecated] Simple, async PSR-7 HTTP client for concurrently processing any number of HTTP requests, built on top of ReactPHP.
PHP
356
star
6

socket-raw

Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets)
PHP
325
star
7

docker-json-server

JSON Server docker image, REST API mocking based on plain JSON
Shell
297
star
8

reactphp-redis

Async Redis client implementation, built on top of ReactPHP.
PHP
245
star
9

docker-ttrss

Tiny Tiny RSS feed reader as a docker image.
PHP
200
star
10

reactphp-stdio

Async, event-driven and UTF-8 aware console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP.
PHP
193
star
11

php-redis-server

A Redis server implementation in pure PHP
PHP
181
star
12

reactphp-block

Lightweight library that eases using components built for ReactPHP in a traditional, blocking environment.
PHP
152
star
13

reactphp-mq

Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP.
PHP
127
star
14

reactphp-zenity

Zenity allows you to build graphical desktop (GUI) applications in PHP, built on top of ReactPHP.
PHP
120
star
15

reactphp-socks

Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.
PHP
116
star
16

reactphp-term

Streaming terminal emulator, built on top of ReactPHP
PHP
103
star
17

reactphp-docker

Async, event-driven access to the Docker Engine API, built on top of ReactPHP.
PHP
100
star
18

reactphp-ami

Streaming, event-driven access to the Asterisk Manager Interface (AMI), built on top of ReactPHP.
PHP
71
star
19

framework-x-placeholder

Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.
67
star
20

docker-adminer

Adminer docker image, a full-featured database management tool for the web
66
star
21

reactphp-utf8

Streaming UTF-8 parser, built on top of ReactPHP
PHP
66
star
22

reactphp-soap

Simple, async SOAP webservice client, built on top of ReactPHP.
PHP
62
star
23

php-socks

[maintenance] look at clue/socks-react instead
PHP
62
star
24

reactphp-ndjson

Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.
PHP
62
star
25

reactphp-flux

Flux, the lightweight stream processor to concurrently do many (but not too many) things at once, built on top of ReactPHP.
PHP
58
star
26

php-sse-react

Streaming, async HTML5 Server-Sent Events server (aka. SSE or EventSource), built on top of ReactPHP
PHP
54
star
27

psocksd

The SOCKS tunnel / proxy server daemon written in PHP
PHP
53
star
28

reactphp-csv

Streaming CSV (Comma-Separated Values or Character-Separated Values) parser and encoder for ReactPHP.
PHP
51
star
29

reactphp-eventsource

Instant real-time updates. Lightweight EventSource client receiving live messages via HTML5 Server-Sent Events (SSE). Fast stream processing built on top of ReactPHP's event-driven architecture.
PHP
48
star
30

reactphp-sqlite

Async SQLite database, lightweight non-blocking process wrapper around file-based database extension (ext-sqlite3), built on top of ReactPHP.
PHP
46
star
31

reactphp-http-proxy

Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP.
PHP
45
star
32

docker-phpvirtualbox

phpVirtualBox docker image, a modern webinterface mirroring the VirtualBox GUI to administer VirtualBox VMs in a headless environment
PHP
42
star
33

php-redis-protocol

A Redis protocol parser / serializer written in PHP
PHP
38
star
34

docker-h5ai

h5ai docker image, the modern web server index
34
star
35

reactphp-shell

Run async commands within any interactive shell command, built on top of ReactPHP.
PHP
32
star
36

arguments

The simple way to split your command line string into an array of command arguments in PHP.
PHP
31
star
37

php-json-query

The JSON query language implemented in PHP
PHP
30
star
38

reactphp-zlib

Streaming zlib compressor and decompressor for ReactPHP, supporting compression and decompression of GZIP, ZLIB and raw DEFLATE formats.
PHP
28
star
39

json-stream

Simple, lightweight, incremental parser for JSON streaming (concatenated JSON and newline-delimited JSON), in PHP
PHP
24
star
40

json-query-language

A structured query language for querying / filtering JSON documents, expressed in JSON
24
star
41

graph-uml

UML class diagrams in PHP
PHP
24
star
42

reactphp-ssh-proxy

Async SSH proxy connector and forwarder, tunnel any TCP/IP-based protocol through an SSH server, built on top of ReactPHP.
PHP
23
star
43

docker-streamripper

Streamripper docker image, an application that lets you record streaming mp3 to your hard drive
Shell
22
star
44

reactphp-multicast

Simple, event-driven multicast UDP message client and server for ReactPHP.
PHP
21
star
45

reactphp-pq

PQ ("peak"), automatically wrap blocking functions in an async child process and turn blocking functions into non-blocking promises, built on top of ReactPHP
20
star
46

php-socket-react

Binding for raw sockets (ext-sockets) in React PHP
PHP
20
star
47

reactphp-connection-manager-extra

Provides extra (in terms of "additional", "extraordinary", "special" and "unusual") decorators, built on top of ReactPHP's Socket
PHP
20
star
48

docker-frontroute

A docker image to automatically set up a front router (reverse proxy) for linked web containers
PHP
19
star
49

reactphp-ssdp

Async Simple Service Discovery Protocol (SSDP), built on top of ReactPHP.
PHP
19
star
50

reactphp-quassel

Streaming, event-driven access to your Quassel IRC core, built on top of ReactPHP
PHP
18
star
51

docker-webgrind

Webgrind docker image, a Xdebug profiling web frontend
Shell
18
star
52

php-wake-on-lan-react

Turn on your PC with Wake-On-LAN (WOL) requests via React PHP
PHP
18
star
53

docker-httpie

HTTpie docker image, a cURL-like tool for humans
Shell
17
star
54

make.php

A GNU Make clone written in pure PHP. Run your Makefiles no matter whether GNU make is available.
17
star
55

reactphp-packagist-api

Simple async access to packagist.org's API, like listing project details, number of downloads etc., built on top of ReactPHP.
PHP
16
star
56

reactphp-mdns

Simple, async multicast DNS (mDNS) resolver for zeroconf networking, built on top of ReactPHP.
PHP
14
star
57

reactphp-memoize

Automatically memoize async function calls by caching function results, built on top of ReactPHP.
13
star
58

docker-polipo

Docker image for Polipo, a caching web/http proxy
13
star
59

php-icmp-react

Simple async lowlevel ICMP (ping) messaging library built on top of React PHP
PHP
13
star
60

docker-apt-cacher

Dockerized apt-cacher container
Shell
13
star
61

php-hexdump

View any (binary) string as a hexdump in php
PHP
12
star
62

reactphp-tar

Streaming parser to extract tarballs with ReactPHP.
PHP
12
star
63

reactphp-s3

Async S3 filesystem API (supporting Amazon S3, Ceph, MiniIO, DigitalOcean Spaces and others), built on top of ReactPHP.
11
star
64

confgen

Configuration file generator (confgen) – an easy way to generate structured (configuration) files on the fly by processing a Twig template and an arbitrary input data structure.
PHP
10
star
65

reactphp-mailer

Async mailer using SMTP to send large number of emails concurrently, built on top of ReactPHP.
9
star
66

reactphp-clickhouse

Blazing fast access to your ClickHouse database, built on top of @ReactPHP.
8
star
67

docker-vboxwebsrv

Tunneled VirtualBox SOAP webserver docker image
Shell
8
star
68

php-solusvm-api-react

Simple async access to your VPS box through the SolusVM API, built on top of React PHP
PHP
7
star
69

php-readline-react

Experimental reactive binding for ext-readline, built on top of React PHP
PHP
6
star
70

php-json-merge-patch

JSON merge patch (RFC 7396) is a simple alternative to JSON patch (RFC 6902) – dead-simple PHP library
PHP
6
star
71

qdatastream

Lightweight PHP library that allows exchanging binary data with Qt programs (QDataStream)
PHP
5
star
72

reactphp-tsv

Streaming TSV (Tab-Separated Values) parser and encoder for ReactPHP.
5
star
73

docker-textract

textract docker image, allows you to extract text from any document. no muss. no fuss.
Shell
5
star
74

quasselio

Quassel I/O, the lightweight web interface for Quassel IRC in a single PHP file
5
star
75

fd

Access to low-level file desciptors (FDs) with PHP, provides close(), dup(), open() and family
5
star
76

docker-quassel-core

Quassel Core docker image, a modern, cross-platform, distributed IRC program
4
star
77

reactphp-ltsv

Streaming LTSV (Labeled Tab-Separated Values) parser and encoder for ReactPHP.
4
star
78

docker-archeologit

ArcheoloGit docker image, visualize the age and dev activity for git repositories
Shell
4
star
79

reactphp-dns-sd

Async DNS Service Discovery (DNS-SD) implementation for ReactPHP
4
star
80

clue.engineering

Source code for the https://clue.engineering/ website.
HTML
4
star
81

quassel-cli

A CLI Quassel client
4
star
82

reactphp-ftp

Streaming client for FTP servers (File Transfer Protocol), built on top of ReactPHP.
4
star
83

reactphp-rediscovered

A Redis server framework written in pure PHP. Create your own Redis server and your own custom commands without hassle.
3
star
84

docker-redis-benchmark

A minimal docker image to ease running the redis-benchmark
Shell
3
star
85

docker-sculpin

Sculpin Docker image, a static site generator
3
star
86

docker-php-redis-server

A docker image to easily test-drive the php-redis-server
Shell
2
star
87

phpmdoc

PHP + MarkDown + phpdoc = phpmdoc, because writing documentation for PHP projects shouldn't be hard. Parses your class files to create a simple and fully automated markdown document (such as a README.md).
2
star
88

framework-x-website

Source code for the Framework X website.
HTML
2
star
89

docker-kpcli

Minimal kpcli docker image, a command line interface for KeePass
Shell
2
star
90

clue

2
star
91

bitbake-react

Programatically control your bitbake build shell, built on top of React PHP
PHP
2
star
92

php-viewvc-api-react

Simple, async access to your ViewVC web interface, built on top of React PHP
PHP
2
star
93

reactphp-ping

Async, event-driven ping requests to check network connectivity, built on top of ReactPHP.
2
star
94

php-caret-notation

^B A dead-simple PHP library to add caret notation in order to safely show strings that contain ASCII control characters (unprintable characters)
PHP
2
star
95

reactphp-bencode

Streaming Bencode (B-encode) protocol parser and encoder for ReactPHP
1
star
96

docker-psocksd

A docker image for psocksd, the fast, extensible SOCKS tunnel / proxy server daemon written in PHP
Shell
1
star
97

docker-disco

Disco Docker image, a simple visual GitHub browser with pull request support
Shell
1
star
98

mdtoc

Automatic table of contents (TOC) for your markdown documents, with opinionated defaults to keep your README.md up to date without the fuss.
1
star
99

reactphp-netstring

Streaming netstring protocol parser and encoder for ReactPHP
1
star
100

reactphp-imap

Streaming client for IMAP mail servers using IMAP IDLE for instant email notifications, built on top of ReactPHP.
1
star