Skip to content
Toro is a PHP router for developing RESTful web applications and APIs.
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.


Type Name Latest commit message Commit time
Failed to load latest commit information.
examples long tags in templates Feb 9, 2013
src Made code more PSR-1 compliant Apr 8, 2015
.gitignore Adding a .gitignore. Aug 14, 2012
LICENSE Explicitly noting the MIT License. Aug 14, 2012 Update Apr 15, 2015
composer.json Set minimum version of PHP required to 5.3+. Dec 28, 2012


Toro is a PHP router for developing RESTful web applications and APIs. It is designed for minimalists who want to get work done.

Quick Links


  • RESTful routing using strings, regular expressions, and defined types (number, string, alpha)
  • Flexible error handling and callbacks via ToroHook
  • Intuitive and self-documented core (Toro.php)
  • Tested with PHP 5.3 and above

"Hello, world"

The canonical "Hello, world" example:


class HelloHandler {
    function get() {
        echo "Hello, world";

    "/" => "HelloHandler",

Routing Basics

Routing with Toro is simple:


    "/" => "SplashHandler",
    "/catalog/page/:number" => "CatalogHandler",
    "/product/:alpha" => "ProductHandler",
    "/manufacturer/:string" => "ManufacturerHandler"

An application's route table is expressed as an associative array (route_pattern => handler). This is closely modeled after Tornado (Python). Routes are not expressed as anonymous functions to prevent unnecessary code duplication for RESTful dispatching.

From the above example, route stubs, such as :number, :string, and :alpha can be conveniently used instead of common regular expressions. Of course, regular expressions are still welcome. The previous example could also be expressed as:


    "/" => "SplashHandler",
    "/catalog/page/([0-9]+)" => "CatalogHandler",
    "/product/([a-zA-Z0-9-_]+)" => "ProductHandler",
    "/manufacturer/([a-zA-Z]+)" => "ManufacturerHandler"

Pattern matches are passed in order as arguments to the handler's request method. In the case of ProductHandler above:


class ProductHandler {
    function get($name) {
        echo "You want to see product: $name";

RESTful Handlers


class ExampleHandler {
    function get() {}
    function post() {}
    function get_xhr() {}
    function post_xhr() {}

From the above, you can see two emergent patterns.

  1. Methods named after the HTTP request method (GET, POST, PUT, DELETE) are automatically called.

  2. Appending _xhr to a handler method automatically matches JSON/XMLHTTPRequest requests. If the _xhr method is not implemented, then the given HTTP request method is called as a fallback.

ToroHook (Callbacks)

As of v2.0.0, there are a total of five Toro-specific hooks (callbacks):


// Fired for 404 errors; must be defined before Toro::serve() call
ToroHook::add("404",  function() {});

// Before/After callbacks in order
ToroHook::add("before_request", function() {});
ToroHook::add("before_handler", function() {});
ToroHook::add("after_handler", function() {});
ToroHook::add("after_request",  function() {});

before_handler and after_handler are defined within handler's constructor:


class SomeHandler {
    function __construct() {
        ToroHook::add("before_handler", function() { echo "Before"; });
        ToroHook::add("after_handler", function() { echo "After"; });

    function get() {
        echo "I am some handler.";

Hooks can also be stacked. Adding a hook pushes the provided anonymous function into an array. When a hook is fired, all of the functions are called sequentially.


Grab a copy of the repository and move Toro.php to your project root.

Using Composer

Install composer in your project:

$ curl -s | php

Caution: The above command requires you to place a lot of trust in the composer team to not get hacked and have a backdoor installed in their installer script. If secuity is a concern, consider doing the following:

$ curl -s > installer.php
$ less installer.php
$ # When you're certain it's safe...
$ php installer.php

Create a composer.json file in your project root:

    "require": {
        "torophp/torophp": "dev-master"

Install via composer:

$ php composer.phar install

Server Configuration


You may need to add the following snippet in your Apache HTTP server virtual host configuration or .htaccess file.

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ /index.php/$1 [L]

Alternatively, if you’re lucky enough to be using a version of Apache greater than 2.2.15, then you can instead just use this one, single line:

FallbackResource /index.php


For IIS you will need to install URL Rewrite for IIS and then add the following rule to your web.config:

<?xml version="1.0" encoding="UTF-8"?>
          <rule name="Toro" stopProcessing="true">
            <match url="^(.*)$" ignoreCase="false" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                <add input="{R:1}" pattern="^(index\.php)" ignoreCase="false" negate="true" />
            <action type="Rewrite" url="/index.php/{R:1}" />


Under the server block of your virtual host configuration, you only need to add three lines.

location / {
  try_files $uri $uri/ /index.php?$args;


Contributions to Toro are welcome via pull requests.


ToroPHP was created by Kunal Anand and released under the MIT License.

You can’t perform that action at this time.