{"id":13453416,"url":"https://github.com/klein/klein.php","last_synced_at":"2025-12-16T17:47:10.329Z","repository":{"id":48411806,"uuid":"1566536","full_name":"klein/klein.php","owner":"klein","description":"A fast \u0026 flexible router","archived":false,"fork":false,"pushed_at":"2024-01-30T11:16:48.000Z","size":1792,"stargazers_count":2663,"open_issues_count":97,"forks_count":288,"subscribers_count":112,"default_branch":"master","last_synced_at":"2025-12-08T17:57:31.051Z","etag":null,"topics":["http","php","request-uri","router","routing"],"latest_commit_sha":null,"homepage":"","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/klein.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-04-04T10:47:14.000Z","updated_at":"2025-11-08T07:27:45.000Z","dependencies_parsed_at":"2024-05-05T07:47:23.307Z","dependency_job_id":null,"html_url":"https://github.com/klein/klein.php","commit_stats":{"total_commits":630,"total_committers":41,"mean_commits":"15.365853658536585","dds":0.2571428571428571,"last_synced_commit":"43d6725370929ba1c2cf1b0fbb94aab83b84f961"},"previous_names":["chriso/klein.php"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/klein/klein.php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klein%2Fklein.php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klein%2Fklein.php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klein%2Fklein.php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klein%2Fklein.php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klein","download_url":"https://codeload.github.com/klein/klein.php/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klein%2Fklein.php/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27768951,"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","status":"online","status_checked_at":"2025-12-16T02:00:10.477Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["http","php","request-uri","router","routing"],"created_at":"2024-07-31T08:00:39.652Z","updated_at":"2025-12-16T17:47:10.312Z","avatar_url":"https://github.com/klein.png","language":"PHP","readme":"# Klein.php\n\n[![Build Status](https://travis-ci.org/klein/klein.php.png?branch=master)](https://travis-ci.org/klein/klein.php)\n\n**klein.php** is a fast \u0026 flexible router for PHP 5.3+\n\n* Flexible regular expression routing (inspired by [Sinatra](http://www.sinatrarb.com/))\n* A set of [boilerplate methods](#api) for rapidly building web apps\n* Almost no overhead =\u003e [2500+ requests/second](https://gist.github.com/878833)\n\n## Getting started\n\n1. PHP 5.3.x is required\n2. Install Klein using [Composer](#composer-installation) (recommended) or manually\n3. Setup [URL rewriting](https://gist.github.com/874000) so that all requests are handled by **index.php**\n4. (Optional) Throw in some [APC](http://pecl.php.net/package/APC) for good measure\n\n## Composer Installation\n\n1. Get [Composer](http://getcomposer.org/)\n2. Require Klein with `php composer.phar require klein/klein`\n3. Add the following to your application's main PHP file: `require 'vendor/autoload.php';`\n\n## Example\n\n*Hello World* - Obligatory hello world example\n\n```php\n\u003c?php\nrequire_once __DIR__ . '/vendor/autoload.php';\n\n$klein = new \\Klein\\Klein();\n\n$klein-\u003erespond('GET', '/hello-world', function () {\n    return 'Hello World!';\n});\n\n$klein-\u003edispatch();\n```\n\n*Example 1* - Respond to all requests\n\n```php\n$klein-\u003erespond(function () {\n    return 'All the things';\n});\n```\n\n*Example 2* - Named parameters\n\n```php\n$klein-\u003erespond('/[:name]', function ($request) {\n    return 'Hello ' . $request-\u003ename;\n});\n```\n\n*Example 3* - [So RESTful](http://bit.ly/g93B1s)\n\n```php\n$klein-\u003erespond('GET', '/posts', $callback);\n$klein-\u003erespond('POST', '/posts', $callback);\n$klein-\u003erespond('PUT', '/posts/[i:id]', $callback);\n$klein-\u003erespond('DELETE', '/posts/[i:id]', $callback);\n$klein-\u003erespond('OPTIONS', null, $callback);\n\n// To match multiple request methods:\n$klein-\u003erespond(array('POST','GET'), $route, $callback);\n\n// Or you might want to handle the requests in the same place\n$klein-\u003erespond('/posts/[create|edit:action]?/[i:id]?', function ($request, $response) {\n    switch ($request-\u003eaction) {\n        //\n    }\n});\n```\n\n*Example 4* - Sending objects / files\n\n```php\n$klein-\u003erespond(function ($request, $response, $service) {\n    $service-\u003exml = function ($object) {\n        // Custom xml output function\n    }\n    $service-\u003ecsv = function ($object) {\n        // Custom csv output function\n    }\n});\n\n$klein-\u003erespond('/report.[xml|csv|json:format]?', function ($request, $response, $service) {\n    // Get the format or fallback to JSON as the default\n    $send = $request-\u003eparam('format', 'json');\n    $response-\u003e$send($report);\n});\n\n$klein-\u003erespond('/report/latest', function ($request, $response, $service) {\n    $response-\u003efile('/tmp/cached_report.zip');\n});\n```\n\n*Example 5* - All together\n\n```php\n$klein-\u003erespond(function ($request, $response, $service, $app) use ($klein) {\n    // Handle exceptions =\u003e flash the message and redirect to the referrer\n    $klein-\u003eonError(function ($klein, $err_msg) {\n        $klein-\u003eservice()-\u003eflash($err_msg);\n        $klein-\u003eservice()-\u003eback();\n    });\n\n    // The fourth parameter can be used to share scope and global objects\n    $app-\u003edb = new PDO(...);\n\n    // $app also can store lazy services, e.g. if you don't want to\n    // instantiate a database connection on every response\n    $app-\u003eregister('db', function() {\n        return new PDO(...);\n    });\n});\n\n$klein-\u003erespond('POST', '/users/[i:id]/edit', function ($request, $response, $service, $app) {\n    // Quickly validate input parameters\n    $service-\u003evalidateParam('username', 'Please enter a valid username')-\u003eisLen(5, 64)-\u003eisChars('a-zA-Z0-9-');\n    $service-\u003evalidateParam('password')-\u003enotNull();\n\n    $app-\u003edb-\u003equery(...); // etc.\n\n    // Add view properties and helper methods\n    $service-\u003etitle = 'foo';\n    $service-\u003eescape = function ($str) {\n        return htmlentities($str); // Assign view helpers\n    };\n\n    $service-\u003erender('myview.phtml');\n});\n\n// myview.phtml:\n\u003ctitle\u003e\u003c?php echo $this-\u003eescape($this-\u003etitle) ?\u003e\u003c/title\u003e\n```\n\n## Route namespaces\n\n```php\n$klein-\u003ewith('/users', function () use ($klein) {\n\n    $klein-\u003erespond('GET', '/?', function ($request, $response) {\n        // Show all users\n    });\n\n    $klein-\u003erespond('GET', '/[:id]', function ($request, $response) {\n        // Show a single user\n    });\n\n});\n\nforeach(array('projects', 'posts') as $controller) {\n    // Include all routes defined in a file under a given namespace\n    $klein-\u003ewith(\"/$controller\", \"controllers/$controller.php\");\n}\n```\n\nIncluded files are run in the scope of Klein (`$klein`) so all Klein\nmethods/properties can be accessed with `$this`\n\n_Example file for: \"controllers/projects.php\"_\n```php\n// Routes to \"/projects/?\"\n$this-\u003erespond('GET', '/?', function ($request, $response) {\n    // Show all projects\n});\n```\n\n## Lazy services\n\nServices can be stored **lazily**, meaning that they are only instantiated on\nfirst use.\n\n``` php\n\u003c?php\n$klein-\u003erespond(function ($request, $response, $service, $app) {\n    $app-\u003eregister('lazyDb', function() {\n        $db = new stdClass();\n        $db-\u003ename = 'foo';\n        return $db;\n    });\n});\n\n//Later\n\n$klein-\u003erespond('GET', '/posts', function ($request, $response, $service, $app) {\n    // $db is initialised on first request\n    // all subsequent calls will use the same instance\n    return $app-\u003elazyDb-\u003ename;\n});\n```\n\n## Validators\n\nTo add a custom validator use `addValidator($method, $callback)`\n\n```php\n$service-\u003eaddValidator('hex', function ($str) {\n    return preg_match('/^[0-9a-f]++$/i', $str);\n});\n```\n\nYou can validate parameters using `is\u003c$method\u003e()` or `not\u003c$method\u003e()`, e.g.\n\n```php\n$service-\u003evalidateParam('key')-\u003eisHex();\n```\n\nOr you can validate any string using the same flow..\n\n```php\n$service-\u003evalidate($username)-\u003eisLen(4,16);\n```\n\nValidation methods are chainable, and a custom exception message can be specified for if/when validation fails\n\n```php\n$service-\u003evalidateParam('key', 'The key was invalid')-\u003eisHex()-\u003eisLen(32);\n```\n\n## Routing\n\n**[** *match_type* **:** *param_name* **]**\n\nSome examples\n\n    *                    // Match all request URIs\n    [i]                  // Match an integer\n    [i:id]               // Match an integer as 'id'\n    [a:action]           // Match alphanumeric characters as 'action'\n    [h:key]              // Match hexadecimal characters as 'key'\n    [:action]            // Match anything up to the next / or end of the URI as 'action'\n    [create|edit:action] // Match either 'create' or 'edit' as 'action'\n    [*]                  // Catch all (lazy)\n    [*:trailing]         // Catch all as 'trailing' (lazy)\n    [**:trailing]        // Catch all (possessive - will match the rest of the URI)\n    .[:format]?          // Match an optional parameter 'format' - a / or . before the block is also optional\n\nSome more complicated examples\n\n    /posts/[*:title][i:id]     // Matches \"/posts/this-is-a-title-123\"\n    /output.[xml|json:format]? // Matches \"/output\", \"output.xml\", \"output.json\"\n    /[:controller]?/[:action]? // Matches the typical /controller/action format\n\n**Note** - *all* routes that match the request URI are called - this\nallows you to incorporate complex conditional logic such as user\nauthentication or view layouts. e.g. as a basic example, the following\ncode will wrap other routes with a header and footer\n\n```php\n$klein-\u003erespond('*', function ($request, $response, $service) { $service-\u003erender('header.phtml'); });\n//other routes\n$klein-\u003erespond('*', function ($request, $response, $service) { $service-\u003erender('footer.phtml'); });\n```\n\nRoutes automatically match the entire request URI. If you need to match\nonly a part of the request URI or use a custom regular expression, use the `@` operator. If you need to\nnegate a route, use the `!` operator\n\n```php\n// Match all requests that end with '.json' or '.csv'\n$klein-\u003erespond('@\\.(json|csv)$', ...\n\n// Match all requests that _don't_ start with /admin\n$klein-\u003erespond('!@^/admin/', ...\n```\n\n## Views\n\nYou can send properties or helpers to the view by assigning them\nto the `$service` object, or by using the second arg of `$service-\u003erender()`\n\n```php\n$service-\u003eescape = function ($str) {\n    return htmlentities($str);\n};\n\n$service-\u003erender('myview.phtml', array('title' =\u003e 'My View'));\n\n// Or just: $service-\u003etitle = 'My View';\n```\n\n*myview.phtml*\n\n```html\n\u003ctitle\u003e\u003c?php echo $this-\u003eescape($this-\u003etitle) ?\u003e\u003c/title\u003e\n```\n\nViews are compiled and run in the scope of `$service` so all service methods can be accessed with `$this`\n\n```php\n$this-\u003erender('partial.html')           // Render partials\n$this-\u003esharedData()-\u003eget('myvar')       // Access stored service variables\necho $this-\u003equery(array('page' =\u003e 2))   // Modify the current query string\n```\n\n## API\n\nBelow is a list of the public methods in the common classes you will most likely use. For a more formal source\nof class/method documentation, please see the [PHPdoc generated documentation](http://klein.github.io/klein.php/docs/).\n\n```php\n$request-\u003e\n    id($hash = true)                    // Get a unique ID for the request\n    paramsGet()                         // Return the GET parameter collection\n    paramsPost()                        // Return the POST parameter collection\n    paramsNamed()                       // Return the named parameter collection\n    cookies()                           // Return the cookies collection\n    server()                            // Return the server collection\n    headers()                           // Return the headers collection\n    files()                             // Return the files collection\n    body()                              // Get the request body\n    params()                            // Return all parameters\n    params($mask = null)                // Return all parameters that match the mask array - extract() friendly\n    param($key, $default = null)        // Get a request parameter (get, post, named)\n    isSecure()                          // Was the request sent via HTTPS?\n    ip()                                // Get the request IP\n    userAgent()                         // Get the request user agent\n    uri()                               // Get the request URI\n    pathname()                          // Get the request pathname\n    method()                            // Get the request method\n    method($method)                     // Check if the request method is $method, i.e. method('post') =\u003e true\n    query($key, $value = null)          // Get, add to, or modify the current query string\n    \u003cparam\u003e                             // Get / Set (if assigned a value) a request parameter\n\n$response-\u003e\n    protocolVersion($protocol_version = null)       // Get the protocol version, or set it to the passed value\n    body($body = null)                              // Get the response body's content, or set it to the passed value\n    status()                                        // Get the response's status object\n    headers()                                       // Return the headers collection\n    cookies()                                       // Return the cookies collection\n    code($code = null)                              // Return the HTTP response code, or set it to the passed value\n    prepend($content)                               // Prepend a string to the response body\n    append($content)                                // Append a string to the response body\n    isLocked()                                      // Check if the response is locked\n    requireUnlocked()                               // Require that a response is unlocked\n    lock()                                          // Lock the response from further modification\n    unlock()                                        // Unlock the response\n    sendHeaders($override = false)                  // Send the HTTP response headers\n    sendCookies($override = false)                  // Send the HTTP response cookies\n    sendBody()                                      // Send the response body's content\n    send()                                          // Send the response and lock it\n    isSent()                                        // Check if the response has been sent\n    chunk($str = null)                              // Enable response chunking (see the wiki)\n    header($key, $value = null)                     // Set a response header\n    cookie($key, $value = null, $expiry = null)     // Set a cookie\n    cookie($key, null)                              // Remove a cookie\n    noCache()                                       // Tell the browser not to cache the response\n    redirect($url, $code = 302)                     // Redirect to the specified URL\n    dump($obj)                                      // Dump an object\n    file($path, $filename = null)                   // Send a file\n    json($object, $jsonp_prefix = null)             // Send an object as JSON or JSONP by providing padding prefix\n\n$service-\u003e\n    sharedData()                                    // Return the shared data collection\n    startSession()                                  // Start a session and return its ID\n    flash($msg, $type = 'info', $params = array()   // Set a flash message\n    flashes($type = null)                           // Retrieve and clears all flashes of $type\n    markdown($str, $args, ...)                      // Return a string formatted with markdown\n    escape($str)                                    // Escape a string\n    refresh()                                       // Redirect to the current URL\n    back()                                          // Redirect to the referer\n    query($key, $value = null)                      // Modify the current query string\n    query($arr)\n    layout($layout)                                 // Set the view layout\n    yieldView()                                     // Call inside the layout to render the view content\n    render($view, $data = array())                  // Render a view or partial (in the scope of $response)\n    partial($view, $data = array())                 // Render a partial without a layout (in the scope of $response)\n    addValidator($method, $callback)                // Add a custom validator method\n    validate($string, $err = null)                  // Validate a string (with a custom error message)\n    validateParam($param, $err = null)                  // Validate a param\n    \u003ccallback\u003e($arg1, ...)                          // Call a user-defined helper\n    \u003cproperty\u003e                                      // Get a user-defined property\n\n$app-\u003e\n    \u003ccallback\u003e($arg1, ...)                          //Call a user-defined helper\n\n$validator-\u003e\n    notNull()                           // The string must not be null\n    isLen($length)                      // The string must be the exact length\n    isLen($min, $max)                   // The string must be between $min and $max length (inclusive)\n    isInt()                             // Check for a valid integer\n    isFloat()                           // Check for a valid float/decimal\n    isEmail()                           // Check for a valid email\n    isUrl()                             // Check for a valid URL\n    isIp()                              // Check for a valid IP\n    isAlpha()                           // Check for a-z (case insensitive)\n    isAlnum()                           // Check for alphanumeric characters\n    contains($needle)                   // Check if the string contains $needle\n    isChars($chars)                     // Validate against a character list\n    isRegex($pattern, $modifiers = '')  // Validate against a regular expression\n    notRegex($pattern, $modifiers ='')\n    is\u003cValidator\u003e()                     // Validate against a custom validator\n    not\u003cValidator\u003e()                    // The validator can't match\n    \u003cValidator\u003e()                       // Alias for is\u003cValidator\u003e()\n```\n\n## Unit Testing\n\nUnit tests are a crucial part of developing a routing engine such as Klein.\nAdded features or bug-fixes can have adverse effects that are hard to find\nwithout a lot of testing, hence the importance of unit testing.\n\nThis project uses [PHPUnit](https://github.com/sebastianbergmann/phpunit/) as\nits unit testing framework.\n\nThe tests all live in `/tests` and each test extends an abstract class\n`AbstractKleinTest`\n\nTo test the project, simply run `php composer.phar install --dev` to download\na common version of PHPUnit with composer and run the tests from the main\ndirectory with `./vendor/bin/phpunit`\n\n## Contributing\n\nSee the [contributing guide](CONTRIBUTING.md) for more info\n\n## More information\n\nSee the [wiki](https://github.com/klein/klein.php/wiki) for more information\n\n## Contributors\n\n- [Trevor N. Suarez](https://github.com/Rican7)\n\n## License\n\n(MIT License)\n\nCopyright (c) 2010 Chris O'Hara \u003ccohara87@gmail.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","funding_links":[],"categories":["PHP","路由 Routers","Table of Contents","目录","类库"],"sub_categories":["Routers","路由 Routers","路由"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklein%2Fklein.php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklein%2Fklein.php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklein%2Fklein.php/lists"}