{"id":13792676,"url":"https://github.com/anandkunal/ToroPHP","last_synced_at":"2025-05-12T14:32:07.918Z","repository":{"id":696794,"uuid":"341695","full_name":"anandkunal/ToroPHP","owner":"anandkunal","description":"Toro is a PHP router for developing RESTful web applications and APIs.","archived":false,"fork":false,"pushed_at":"2021-12-31T21:49:47.000Z","size":643,"stargazers_count":1168,"open_issues_count":10,"forks_count":172,"subscribers_count":97,"default_branch":"master","last_synced_at":"2025-04-13T22:39:29.592Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://toroweb.org","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anandkunal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-10-18T23:49:58.000Z","updated_at":"2025-01-22T20:14:59.000Z","dependencies_parsed_at":"2022-08-16T10:45:17.404Z","dependency_job_id":null,"html_url":"https://github.com/anandkunal/ToroPHP","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anandkunal%2FToroPHP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anandkunal%2FToroPHP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anandkunal%2FToroPHP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anandkunal%2FToroPHP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anandkunal","download_url":"https://codeload.github.com/anandkunal/ToroPHP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253754982,"owners_count":21958935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T22:01:14.974Z","updated_at":"2025-05-12T14:32:07.530Z","avatar_url":"https://github.com/anandkunal.png","language":"PHP","funding_links":[],"categories":["类库"],"sub_categories":["路由"],"readme":"# Toro\n\nToro is a PHP router for developing RESTful web applications and APIs. It is\ndesigned for minimalists who want to get work done.\n\n## Quick Links\n\n- [Official Website](http://toroweb.org)\n- [Changelog](https://github.com/anandkunal/ToroPHP/wiki/Changelog)\n- [Design Goals](https://github.com/anandkunal/ToroPHP/wiki/Design-Goals)\n\n\n## Features\n\n- RESTful routing using strings, regular expressions, and defined types\n  (`number`, `string`, `alpha`)\n- Flexible error handling and callbacks via `ToroHook`\n- Intuitive and self-documented core (`Toro.php`)\n- Tested with PHP 5.3 and above\n\n\n## \"Hello, world\"\n\nThe canonical \"Hello, world\" example:\n\n```php\n\u003c?php\n\nclass HelloHandler {\n    function get() {\n        echo \"Hello, world\";\n    }\n}\n\nToro::serve(array(\n    \"/\" =\u003e \"HelloHandler\",\n));\n```\n\n\n## Routing Basics\n\nRouting with Toro is simple:\n\n```php\n\u003c?php\n\nToro::serve(array(\n    \"/\" =\u003e \"SplashHandler\",\n    \"/catalog/page/:number\" =\u003e \"CatalogHandler\",\n    \"/product/:alpha\" =\u003e \"ProductHandler\",\n    \"/manufacturer/:string\" =\u003e \"ManufacturerHandler\"\n));\n```\n\nAn application's route table is expressed as an associative array\n(`route_pattern =\u003e handler`). This is closely modeled after\n[Tornado](http://tornadoweb.org) (Python). Routes are not expressed as\nanonymous functions to prevent unnecessary code duplication for RESTful\ndispatching.\n\nFrom the above example, route stubs, such as `:number`, `:string`, and\n`:alpha` can be conveniently used instead of common regular expressions.\nOf course, regular expressions are still welcome. The previous example could\nalso be expressed as:\n\n```php\n\u003c?php\n\nToro::serve(array(\n    \"/\" =\u003e \"SplashHandler\",\n    \"/catalog/page/([0-9]+)\" =\u003e \"CatalogHandler\",\n    \"/product/([a-zA-Z0-9-_]+)\" =\u003e \"ProductHandler\",\n    \"/manufacturer/([a-zA-Z]+)\" =\u003e \"ManufacturerHandler\"\n));\n```\n\nPattern matches are passed in order as arguments to the handler's request\nmethod. In the case of `ProductHandler` above:\n\n```php\n\u003c?php\n\nclass ProductHandler {\n    function get($name) {\n        echo \"You want to see product: $name\";\n    }\n}\n```\n\n\n## RESTful Handlers\n\n```php\n\u003c?php\n\nclass ExampleHandler {\n    function get() {}\n    function post() {}\n    function get_xhr() {}\n    function post_xhr() {}\n}\n```\n\nFrom the above, you can see two emergent patterns.\n\n1. Methods named after the HTTP request method (`GET`, `POST`, `PUT`,\n   `DELETE`) are automatically called.\n\n2. Appending `_xhr` to a handler method automatically matches\n   JSON/`XMLHTTPRequest` requests. If the `_xhr` method is not implemented,\n   then the given HTTP request method is called as a fallback.\n\n\n## ToroHook (Callbacks)\n\nAs of v2.0.0, there are a total of five Toro-specific hooks (callbacks):\n\n```php\n\u003c?php\n\n// Fired for 404 errors; must be defined before Toro::serve() call\nToroHook::add(\"404\",  function() {});\n\n// Before/After callbacks in order\nToroHook::add(\"before_request\", function() {});\nToroHook::add(\"before_handler\", function() {});\nToroHook::add(\"after_handler\", function() {});\nToroHook::add(\"after_request\",  function() {});\n```\n\n`before_handler` and `after_handler` are defined within handler's constructor:\n\n```php\n\u003c?php\n\nclass SomeHandler {\n    function __construct() {\n        ToroHook::add(\"before_handler\", function() { echo \"Before\"; });\n        ToroHook::add(\"after_handler\", function() { echo \"After\"; });\n    }\n\n    function get() {\n        echo \"I am some handler.\";\n    }\n}\n```\n\nHooks can also be stacked. Adding a hook pushes the provided anonymous\nfunction into an array. When a hook is fired, all of the functions are called\nsequentially.\n\n\n## Installation\n\nGrab a copy of the repository and move `Toro.php` to your project root.\n\n### Using Composer\n\nInstall composer in your project:\n\n```sh\n$ curl -s https://getcomposer.org/installer | php\n```\n**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:\n\n```sh\n$ curl -s https://getcomposer.org/installer \u003e installer.php\n$ less installer.php\n$ # When you're certain it's safe...\n$ php installer.php\n```\n\n\nCreate a `composer.json` file in your project root:\n\n```js\n{\n    \"require\": {\n        \"torophp/torophp\": \"dev-master\"\n    }\n}\n```\n\nInstall via composer:\n\n```sh\n$ php composer.phar install\n```\n\n### Server Configuration\n\n#### Apache\n\nYou may need to add the following snippet in your Apache HTTP server virtual host configuration or **.htaccess** file.\n\n```apacheconf\nRewriteEngine on\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond $1 !^(index\\.php)\nRewriteRule ^(.*)$ /index.php/$1 [L]\n```\n\nAlternatively, 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:\n```apacheconf\nFallbackResource /index.php\n```\n\n#### IIS\n\nFor IIS you will need to install URL Rewrite for IIS and then add the following rule to your `web.config`:\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration\u003e\n    \u003csystem.webServer\u003e\n        \u003crewrite\u003e\n          \u003crule name=\"Toro\" stopProcessing=\"true\"\u003e\n            \u003cmatch url=\"^(.*)$\" ignoreCase=\"false\" /\u003e\n              \u003cconditions logicalGrouping=\"MatchAll\"\u003e\n                \u003cadd input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" ignoreCase=\"false\" negate=\"true\" /\u003e\n                \u003cadd input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" ignoreCase=\"false\" negate=\"true\" /\u003e\n                \u003cadd input=\"{R:1}\" pattern=\"^(index\\.php)\" ignoreCase=\"false\" negate=\"true\" /\u003e\n              \u003c/conditions\u003e\n            \u003caction type=\"Rewrite\" url=\"/index.php/{R:1}\" /\u003e\n          \u003c/rule\u003e\n        \u003c/rewrite\u003e\n    \u003c/system.webServer\u003e\n\u003c/configuration\u003e\n```\n\n#### Nginx\n\nUnder the `server` block of your virtual host configuration, you only need to add three lines.\n```conf\nlocation / {\n  try_files $uri $uri/ /index.php?$args;\n}\n```\n\n## Contributions\n\n- Toro was inspired by the [Tornado Web Server](http://www.tornadoweb.org)\n  (FriendFeed/Facebook)\n- [Berker Peksag](http://berkerpeksag.com),\n  [Martin Bean](http://www.martinbean.co.uk),\n  [Robbie Coleman](http://robbie.robnrob.com), and\n  [John Kurkowski](http://about.me/john.kurkowski) for bug fixes and patches\n- [Danillo César de O. Melo](https://github.com/danillos/fire_event/blob/master/Event.php) for `ToroHook`\n- [Jason Mooberry](http://jasonmooberry.com) for code optimizations and feedback\n\nContributions to Toro are welcome via pull requests.\n\n\n## License\n\nToroPHP was created by [Kunal Anand](http://kunalanand.com) and released under\nthe MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanandkunal%2FToroPHP","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanandkunal%2FToroPHP","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanandkunal%2FToroPHP/lists"}