PHPackages                             inphinit/teeny - 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. [Framework](/categories/framework)
4. /
5. inphinit/teeny

ActiveProject[Framework](/categories/framework)

inphinit/teeny
==============

A ready-to-use route system

0.4.0(11mo ago)93961MITPHPPHP &gt;=5.3.0CI passing

Since Apr 25Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/inphinit/teeny)[ Packagist](https://packagist.org/packages/inphinit/teeny)[ RSS](/packages/inphinit-teeny/feed)WikiDiscussions master Synced today

READMEChangelog (10)DependenciesVersions (16)Used By (0)

 [ ![Teeny route system for PHP](./badges/php.png) ](https://github.com/inphinit/teeny/) [ ![Teeny route system for JavaScript (Node.js)](./badges/javascript.png) ](https://github.com/inphinit/teeny.js/) [ ![Teeny route system for Golang](./badges/golang.png) ](https://github.com/inphinit/teeny.go/) [ ![Teeny route system for Python](./badges/python.png) ](https://github.com/inphinit/teeny.py/)

Teeny route system for PHP
==========================

[](#teeny-route-system-for-php)

Teeny is a micro-route system that is really micro, supports **PHP 5.3** to **PHP 8**, is extremely simple and ready to use.

Install using Composer
----------------------

[](#install-using-composer)

To create a new project, run:

```
composer create-project inphinit/teeny

```

Replace `` by your project name, example:

```
composer create-project inphinit/teeny blog

```

Download without Composer
-------------------------

[](#download-without-composer)

If you are not using Composer, you can download Teeny directly from

Apache (`.htaccess`)
--------------------

[](#apache-htaccess)

The `.htaccess` will only need some adjustment if you are using it in a subfolder, you will need to change all `ErrorDocument`. More details at .

If the address is something like `https:///`, then do:

```
ErrorDocument 403 /index.php/RESERVED.TEENY-403.html
ErrorDocument 500 /index.php/RESERVED.TEENY-500.html
```

If the address is something like `https:///foo/`, then do:

```
ErrorDocument 403 /foo/index.php/RESERVED.TEENY-403.html
ErrorDocument 500 /foo/index.php/RESERVED.TEENY-500.html
```

If the address is something like `https:///foo/bar/`, then do:

```
ErrorDocument 403 /foo/bar/index.php/RESERVED.TEENY-403.html
ErrorDocument 500 /foo/bar/index.php/RESERVED.TEENY-500.html
```

NGINX
-----

[](#nginx)

For NGINX you can use [`try_files`](https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files), example:

```
location / {
    root /home/foo/bar/teeny;

    # Redirect page errors to route system
    error_page 403 /index.php/RESERVED.TEENY-403.html;
    error_page 500 /index.php/RESERVED.TEENY-500.html;

    try_files /public$uri /index.php?$query_string;

    location = / {
        try_files $uri /index.php?$query_string;
    }

    location ~ /\. {
        try_files /index.php$uri /index.php?$query_string;
    }

    location ~ \.php$ {
        # Replace with your FPM or FastCGI address
        fastcgi_pass 127.0.0.1:9000;

        fastcgi_index index.php;
        include fastcgi_params;

        set $teeny_suffix "";

        if ($uri != "/index.php") {
            set $teeny_suffix "/public";
        }

        fastcgi_param SCRIPT_FILENAME $realpath_root$teeny_suffix$fastcgi_script_name;
    }
}

```

> **Note:** For FPM use `fastcgi_pass unix:/var/run/php/php-fpm.sock` (replace `` by PHP version in your server)

Built-in web server
-------------------

[](#built-in-web-server)

You can use [built-in server](https://www.php.net/manual/en/features.commandline.webserver.php) to facilitate the development, Teeny provides the relative static files, which will facilitate the use, example of use (navigate to project folder using `cd` command):

```
php -S localhost:8080 -t public index.php
```

You can edit the `server.bat` (Windows) or `server` (Linux or macOS) files to make it easier to start the project with a simple command

### Windows (server.bat file)

[](#windows-serverbat-file)

Configure the `server.bat` variables according to your environment:

```
rem Setup PHP, php.ini and variable order
set PHP_BIN=C:\php\php.exe
set PHP_INI=C:\php\php.ini
set PHP_VAR=GPCS

rem Setup host and port
set HOST_ADDR=localhost
set HOST_PORT=9000
```

Once configured, you can navigate to the project folder and run the command that will start the *built-in web server*, example:

```
cd c:\projets\blog
server
```

### Linux and macOS (server file)

[](#linux-and-macos-server-file)

Configure the `./server` variables according to your environment:

```
# Setup PHP, php.ini and variable order
PHP_BIN=/usr/bin/php
PHP_INI=/etc/php.ini
PHP_VAR=EGPCS

# Setup host and port
HOST_ADDR=localhost
HOST_PORT=9000
```

Once configured, you can navigate to the project folder and run the command that will start built-in server, example:

```
cd ~/projets/blog
./server
```

API
---

[](#api)

Methods from `Teeny` class

MethodDescription`Teeny::path(): string`Get current path from URL (ignores subfolders if it is located in a subfolder on your webserver)`Teeny::status([int $code]): int`Get or set HTTP status code`Teeny::action($methods, string $path, mixed $callback): void`Register a callback or script for a route`Teeny::setPattern(string $pattern, string $regex): void`Add or replace a pattern for custom routes, like `/foo/``Teeny::handlerCodes(array $codes, mixed $callback): void`Handler HTTP status code`Teeny::exec(): bool`Execute applicationAdd and remove routes
---------------------

[](#add-and-remove-routes)

To create a new route in `index.php` put like this:

```
$app->action('GET', '/myroute', function () {
    echo 'Test!';
});
```

You can use `return`:

```
$app->action('GET', '/myroute', function () {
    return 'Test!';
});
```

To remove a route use `null` value, like this:

```
$app->action('GET', '/myroute', null);
```

Route include file
------------------

[](#route-include-file)

To include a file uses like this:

```
$app->action('GET', '/myroute', 'foo/bar/test.php');
```

If is `foo/bar/test.php` not found in project will display the following error:

```
Warning: require(foo/bar/test.php): failed to open stream: No such file or directory in /home/user/blog/vendor/teeny.php on line 156

Fatal error: require(): Failed opening required 'foo/bar/test.php' (include_path='.') /home/user/blog/vendor/teeny.php on line 156

```

HTTP status
-----------

[](#http-status)

To retrieve HTTP status from SAPI (Apache, Ngnix, IIS) or previously defined in the script itself use it like this:

```
$var = $app->status();
```

To retrieve into a route use it like this:

```
$app->action('GET', '/myroute', function ($app) {
    echo 'HTTP status: ', $app->status();
});
```

To set a new HTTP status use it like this (eg.: emit 404 Not Found):

```
$app->status(404);
```

To set into route use it like this (a example with condition/if):

```
$app->action('GET', '/report', function ($app) {
    $file = 'data/foo.csv';

    if (is_file($file)) {
        header('Content-Type: text/csv');
        readfile($file);
        /**
         * Note: this is just an example, about sending a file,
         * if possible use "X-Sendfile" or equivalent
         */
    } else {
        $app->status(404);

        echo 'Report not found';
    }
});
```

Named params in route
---------------------

[](#named-params-in-route)

You can use params like this:

```
$app->action('GET', '/user/', function ($app, $params) {
    var_dump($params);
});
```

If you access a URL like this `http://mywebsite/user/mary` returns:

```
array(2) {
  ["user"]=>
  string(3) "mary"
}
```

Another example:

```
$app->action('GET', '/article/-', function ($app, $params) {
    // Only numeric IDs are valid
    if (ctype_digit($params['id'])) {
        echo 'Article ID: ', $params['id'], '';
        echo 'Article name: ', $params['name'];
    } else {
        $app->status(400);

        echo 'Invalid URL';
    }
});
```

If you access a URL like this `http://mywebsite/article/mary-1000` returns:

```
Article ID: 1000
Article name: mary

```

Supported types for named parameters in routes
----------------------------------------------

[](#supported-types-for-named-parameters-in-routes)

An example, only numeric id are valid:

```
$app->action('GET', '/article/-', function ($app, $params) {
    echo 'Article ID: ', $params['id'], '';
    echo 'Article name: ', $params['name'];
});
```

TypeExampleDescription`alnum``$app->action('GET', '/baz/', ...);`Only accepts parameters with alpha-numeric format and `$params` returns `array( video => ...)``alpha``$app->action('GET', '/foo/bar/', ...);`Only accepts parameters with alpha format and `$params` returns `array( name => ...)``decimal``$app->action('GET', '/baz/', ...);`Only accepts parameters with decimal format and `$params` returns `array( price => ...)``num``$app->action('GET', '/foo/', ...);`Only accepts parameters with integer format and `$params` returns `array( id => ...)``nospace``$app->action('GET', '/foo/', ...);`Accepts any characters except spaces, like white-spaces (`%20`), tabs (`%0A`) and others (see about `\S` in regex)`uuid``$app->action('GET', '/bar/', ...);`Only accepts parameters with UUID format and `$params` returns `array( barcode => ...)``version``$app->action('GET', '/baz/', ...);`Only accepts parameters with [semversion (v2)](https://semver.org/spec/v2.0.0.html) format and `$params` returns `array( api => ...)`For add new patterns use it like this `Teeny::setPattern()`, examples:

```
$app->setPattern('example', '[A-Z]\d+');

$app->action('GET', '/custom/', function ($app, $params) {
    echo 'custom pattern';
    echo '';
    print_r($params);
    echo '';
});
```

And to access this route exemple use `http://mysite/test/A00001` or `http://mysite/test/C02`, start with upper-case letter and after with an integer number

Dealing with large files
------------------------

[](#dealing-with-large-files)

To work with large files you can choose to use the following server modules:

ModuleServerDocumentation`X-Sendfile`Apache[https://tn123.org/mod\_xsendfile/](https://tn123.org/mod_xsendfile/)`X-Accel-Redirect`NGINX`X-LIGHTTPD-send-file` and `X-Sendfile2`LighttpdA simple example:

```
$software = $_SERVER['SERVER_SOFTWARE'];
$send = null;

if (stripos($software, 'apache') !== false) {
    $send = 'X-Sendfile';
} else if (stripos($software, 'nginx') !== false) {
    $send = 'X-Accel-Redirect';
} else if (stripos($software, 'lighttpd') !== false) {
    $send = 'X-LIGHTTPD-send-file';
}

$app->action('GET', '/download', function () use ($send) {
    $file = '/protected/iso.img';

    if ($send) {
        header($send . ': ' . $file);
        return;
    }

    $handle = fopen($file, 'rb');

    if ($handle === false) {
        $app->status(500);
        return 'Failed to read file';
    }

    // fallback (this is just an example)
    $length = 2097152;

    header('Content-Disposition: attachment; filename="iso.img"');
    header('Content-Length: ' . filesize($file));

    while (!feof($handle)) {
        echo fgets($handle, $length);
        flush();
    }

    fclose($handle);
});
```

Serving public files (and scripts)
----------------------------------

[](#serving-public-files-and-scripts)

To serve public files (or scripts) you must add them to the public folder. The `/public/*` prefix is removed from the final URL, for example, if there is a file like `public/foobar.html`, then the user will simply access the address `https:///foobar.html`.

Subfolders will also work, if it has a file like `public/foo/bar/baz/video.webm` then the user should go to `https:///foo/bar/baz/video.webm`.

You can add PHP scripts, and they will be executed normally, if you have a script like `public/sample/helloworld.php`, just access `https:///sample/helloworld.php`

If you want to make a blog available, such as Wordpress, you must also place it inside the folder, an example of structure:

```
├─── .htaccess
├─── index.php
├─── composer.json
├─── vendor/
└─── public/
     ├─── helloword.html
     └─── blog/
          ├─── .htaccess
          ├─── index.php
          ├─── wp-activate.php
          ├─── wp-blog-header.php
          ├─── wp-comments-post.php
          ├─── wp-config-sample.php
          ├─── wp-config.php
          ├─── wp-cron.php
          ├─── wp-links-opml.php
          ├─── wp-load.php
          ├─── wp-login.php
          ├─── wp-mail.php
          ├─── wp-settings.php
          ├─── wp-signup.php
          ├─── wp-trackback.php
          ├─── xmlrpc.php
          ├─── wp-admin/
          ├─── wp-content/
          └─── wp-includes/

```

You can then access the blog at `https:///blog/`. Other samples:

- `https:///blog/wp-admin/`
- `https:///blog/2021/03/24/astronomy-messier-87-black-hole/`
- `https:///blog/2023/04/17/researchers-discover-small-galaxy/`

---

If you need more features you can experience the **Inphinit PHP framework**:

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance61

Regular maintenance activity

Popularity19

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Every ~132 days

Recently: every ~301 days

Total

15

Last Release

356d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/59fe203ccf639d985a00f1ed5fabeb042e2a74829708d23d0fe02e95d6599821?d=identicon)[brcontainer](/maintainers/brcontainer)

---

Top Contributors

[![brcontainer](https://avatars.githubusercontent.com/u/4368952?v=4)](https://github.com/brcontainer "brcontainer (66 commits)")

---

Tags

composerhttp-routerphpphp7php8routingurlrouting

### Embed Badge

![Health badge](/badges/inphinit-teeny/health.svg)

```
[![Health](https://phpackages.com/badges/inphinit-teeny/health.svg)](https://phpackages.com/packages/inphinit-teeny)
```

###  Alternatives

[klein/klein

A lightning fast router for PHP

2.7k1.1M31](/packages/klein-klein)[nette/application

🏆 Nette Application: a full-stack component-based MVC kernel for PHP that helps you write powerful and modern web applications. Write less, have cleaner code and your work will bring you joy.

44615.4M982](/packages/nette-application)[laravel/folio

Page based routing for Laravel.

608453.9k27](/packages/laravel-folio)[pecee/simple-router

Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.

696214.6k17](/packages/pecee-simple-router)[luthier/luthier

Improved routing, middleware support, authentication tools and more for CodeIgniter 3 framework

150108.8k](/packages/luthier-luthier)[adamstipak/nette-rest-route

Rest route for Nette Framework

67150.8k](/packages/adamstipak-nette-rest-route)

PHPackages © 2026

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