{"id":35190471,"url":"https://github.com/phrenotype/crane","last_synced_at":"2025-12-29T05:38:47.541Z","repository":{"id":56958674,"uuid":"445921972","full_name":"phrenotype/crane","owner":"phrenotype","description":"Crane - Slim and secure","archived":false,"fork":false,"pushed_at":"2025-08-30T20:46:56.000Z","size":42,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-04T17:17:34.079Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/phrenotype.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-08T20:32:02.000Z","updated_at":"2025-08-30T20:45:48.000Z","dependencies_parsed_at":"2024-06-29T17:39:56.308Z","dependency_job_id":"5db48363-0b6b-4634-a70c-361c4bd81324","html_url":"https://github.com/phrenotype/crane","commit_stats":{"total_commits":13,"total_committers":1,"mean_commits":13.0,"dds":0.0,"last_synced_commit":"c25b02a5281f5816b3c01b05d79a262e2e9fffe5"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/phrenotype/crane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrenotype%2Fcrane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrenotype%2Fcrane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrenotype%2Fcrane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrenotype%2Fcrane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phrenotype","download_url":"https://codeload.github.com/phrenotype/crane/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrenotype%2Fcrane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28111192,"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-29T02:00:07.021Z","response_time":58,"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":[],"created_at":"2025-12-29T05:38:40.492Z","updated_at":"2025-12-29T05:38:47.535Z","avatar_url":"https://github.com/phrenotype.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Crane\r\n![github stars](https://img.shields.io/github/stars/phrenotype/crane?style=social)\r\n![packagist stars](https://img.shields.io/packagist/stars/crane/crane)\r\n![license](https://img.shields.io/github/license/phrenotype/crane)\r\n![contributors](https://img.shields.io/github/contributors/phrenotype/crane)\r\n![contributors](https://img.shields.io/github/languages/code-size/phrenotype/crane)\r\n![downloads](https://img.shields.io/packagist/dm/crane/crane)\r\n\r\n# Quick Start Guide: Routing HTTP Requests in Crane PHP Framework\r\n\r\n## Introduction\r\n\r\nCrane is a lightweight and secure PHP framework designed for minimalists who prioritize security. It can run in any hosting environment and provides a simple way to route HTTP requests. This guide will walk you through the basics of setting up routes, handling requests and responses, and using middleware.\r\n\r\n## Installation\r\n\r\nFirst, install Crane via Composer:\r\n\r\n```bash\r\ncomposer require crane/crane\r\n```\r\n\r\n## Configuration\r\n\r\nCreate a `config.php` file in your project root to store environment variables (optional but recommended):\r\n\r\n```php\r\n\u003c?php\r\nreturn [\r\n    'app_name' =\u003e 'My Crane App',\r\n    'debug' =\u003e true,\r\n    // Add your configuration here\r\n];\r\n```\r\n\r\n## Basic Setup\r\n\r\nCreate an `index.php` file in your project root. This will be your entry point.\r\n\r\n```php\r\n\u003c?php\r\n\r\nrequire_once 'vendor/autoload.php';\r\n\r\nuse Crane\\Router\\App;\r\n\r\n// Create a new App instance (parameters are for custom request/server data, but createFromGlobals() is used internally)\r\n$app = new App([], []);\r\n\r\n// Define your routes here (see examples below)\r\n\r\n// Run the app with the current request URI\r\n$app-\u003erun($_SERVER['REQUEST_URI']);\r\n```\r\n\r\n## Defining Routes\r\n\r\nRoutes are defined using methods like `get()`, `post()`, and `all()`. Each route takes a path and a handler function or class method.\r\n\r\nHandlers can be:\r\n- Anonymous functions: `function($request, $response) { ... }`\r\n- Class methods: `[MyClass::class, 'methodName']`\r\n\r\n### Simple GET Route\r\n\r\n```php\r\n$app-\u003eget('/', function($request, $response) {\r\n    return $response-\u003erespond('\u003ch1\u003eHello, World!\u003c/h1\u003e');\r\n});\r\n```\r\n\r\nThis creates a route for the root path that responds with HTML.\r\n\r\n### Route with Parameters\r\n\r\n```php\r\n$app-\u003eget('/user/(?\u003cid\u003e\\d+)', function($request, $response) {\r\n    $userId = $request-\u003eparams-\u003eget('id');\r\n    return $response-\u003erespond(\"\u003ch1\u003eUser ID: $userId\u003c/h1\u003e\");\r\n});\r\n```\r\n\r\nParameters are defined using named regex groups (?\u003cname\u003epattern) and are captured and available via `$request-\u003eparams`.\r\n\r\n### POST Route\r\n\r\n```php\r\n$app-\u003epost('/submit', function($request, $response) {\r\n    $data = $request-\u003erequest-\u003eall(); // Get POST data\r\n    // Process data...\r\n    return $response-\u003ejson(['status' =\u003e 'success']);\r\n});\r\n```\r\n\r\n### Handling All Methods\r\n\r\n```php\r\n$app-\u003eall('/api/data', function($request, $response) {\r\n    // Handle any HTTP method\r\n    return $response-\u003ejson(['method' =\u003e $request-\u003egetMethod()]);\r\n});\r\n```\r\n\r\n## Chaining Routes\r\n\r\nYou can chain methods for the same path:\r\n\r\n```php\r\n$app-\u003eroute('/user')\r\n    -\u003eget(function($request, $response) {\r\n        // Handle GET /user\r\n    })\r\n    -\u003epost(function($request, $response) {\r\n        // Handle POST /user\r\n    });\r\n```\r\n\r\n## Using Middleware\r\n\r\nMiddleware runs before your route handlers. Use `middleware()` to add them.\r\n\r\n### Global Middleware (runs on all routes)\r\n\r\n```php\r\n$app-\u003emiddleware(function($request, $response) {\r\n    // Global middleware logic, e.g., authentication\r\n    if (!$request-\u003esession('user')) {\r\n        return $response-\u003eredirect('/login');\r\n    }\r\n});\r\n```\r\n\r\n### Route-Specific Middleware\r\n\r\n```php\r\n$app-\u003emiddleware('/admin/*', function($request, $response) {\r\n    // Only for /admin/* paths\r\n    if (!$request-\u003esession('admin')) {\r\n        return $response-\u003eredirect('/login');\r\n    }\r\n});\r\n```\r\n\r\n## Response Methods\r\n\r\nCrane provides convenient methods for different response types:\r\n\r\n- `$response-\u003erespond($html)`: Send HTML\r\n- `$response-\u003ejson($data)`: Send JSON\r\n- `$response-\u003erender($template, $context)`: Render a template\r\n- `$response-\u003eredirect($url)`: Redirect\r\n- `$response-\u003edownload($file)`: Download a file\r\n\r\n## Request Handling\r\n\r\nAccess request data easily:\r\n\r\n- `$request-\u003eparams`: Route parameters\r\n- `$request-\u003equery`: Query string parameters\r\n- `$request-\u003erequest`: POST data\r\n- `$request-\u003esession($key)`: Session data\r\n- `$request-\u003ecookie($key)`: Cookies\r\n\r\n## Serving Static Files\r\n\r\nCreate a `public/` directory in your project root for static assets. Configure static file serving:\r\n\r\n```php\r\n$app-\u003estatic('/assets', 'public/assets');\r\n```\r\n\r\nThis maps `/assets` URLs to the `public/assets` directory.\r\n\r\n## Complete Example\r\n\r\n```php\r\n\u003c?php\r\n\r\nrequire_once 'vendor/autoload.php';\r\n\r\nuse Crane\\Router\\App;\r\n\r\n$app = new App([], []);\r\n\r\n// Global middleware\r\n$app-\u003emiddleware(function($request, $response) {\r\n    // Add security headers\r\n    $response-\u003eheaders-\u003eset('X-Frame-Options', 'DENY');\r\n});\r\n\r\n// Routes\r\n$app-\u003eget('/', function($request, $response) {\r\n    return $response-\u003erespond('\u003ch1\u003eWelcome to Crane!\u003c/h1\u003e');\r\n});\r\n\r\n$app-\u003eget('/user/(?\u003cid\u003e\\d+)', function($request, $response) {\r\n    $id = $request-\u003eparams-\u003eget('id');\r\n    return $response-\u003ejson(['user_id' =\u003e $id]);\r\n});\r\n\r\n$app-\u003epost('/login', function($request, $response) {\r\n    $username = $request-\u003erequest-\u003eget('username');\r\n    $password = $request-\u003erequest-\u003eget('password');\r\n    // Authenticate...\r\n    $request-\u003esession('user', $username);\r\n    return $response-\u003eredirect('/dashboard');\r\n});\r\n\r\n$app-\u003eget('/admin/users/(?\u003cid\u003e\\d+)', [AdminController::class, 'showUser']);\r\n\r\n// Static files (ensure public/css and public/js directories exist)\r\n$app-\u003estatic('/css', 'public/css');\r\n$app-\u003estatic('/js', 'public/js');\r\n\r\n// Run the app\r\n$app-\u003erun($_SERVER['REQUEST_URI']);\r\n```\r\n\r\n## Running Your App\r\n\r\n1. Ensure your web server (Apache/Nginx) points to `index.php` for all requests.\r\n2. For Apache, add a `.htaccess` file:\r\n\r\n```\r\nRewriteEngine On\r\nRewriteCond %{REQUEST_FILENAME} !-f\r\nRewriteCond %{REQUEST_FILENAME} !-d\r\nRewriteRule . index.php [L]\r\n```\r\n\r\n3. Access your app in the browser!\r\n\r\n## Template Rendering\r\n\r\nCrane provides a powerful template engine for rendering dynamic HTML. Create a `views/` directory in your project root to store templates. Templates use a syntax similar to other templating engines.\r\n\r\n### Basic Usage\r\n\r\nUse `$response-\u003erender($template, $context)` to render a template:\r\n\r\n```php\r\n$app-\u003eget('/profile', function($request, $response) {\r\n    $user = ['name' =\u003e 'John', 'age' =\u003e 30];\r\n    return $response-\u003erender('profile.html', ['user' =\u003e $user]);\r\n});\r\n```\r\n\r\n### Template Syntax\r\n\r\n#### Variables\r\n\r\nUse `{{ variable }}` to output variables:\r\n\r\n```html\r\n\u003ch1\u003eHello, {{ user.name }}!\u003c/h1\u003e\r\n\u003cp\u003eAge: {{ user.age }}\u003c/p\u003e\r\n```\r\n\r\n#### Paths\r\n\r\nAccess nested properties with dot notation:\r\n\r\n```html\r\n{{ user.address.city }}\r\n```\r\n\r\n#### Functions\r\n\r\nCall functions or static methods with `{% = function %}`:\r\n\r\n```html\r\n{% = strtoupper user.name %}\r\n{% = MyClass::helper user.age %}\r\n```\r\n\r\n#### Template Inheritance\r\n\r\nExtend base templates:\r\n\r\nBase template (base.html):\r\n\r\n```html\r\n\u003chtml\u003e\r\n\u003chead\u003e\u003ctitle\u003e{% block title %}Default Title{% endblock %}\u003c/title\u003e\u003c/head\u003e\r\n\u003cbody\u003e\r\n    {% block content %}{% endblock %}\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n```\r\n\r\nChild template:\r\n\r\n```html\r\n{% extends 'base.html' %}\r\n\r\n{% block title %}My Page{% endblock %}\r\n\r\n{% block content %}\r\n\u003ch1\u003eWelcome\u003c/h1\u003e\r\n\u003cp\u003eThis is my page.\u003c/p\u003e\r\n{% endblock %}\r\n```\r\n\r\n#### Includes\r\n\r\nInclude other templates:\r\n\r\n```html\r\n{% include 'header.html' %}\r\n```\r\n\r\n## Sessions\r\n\r\nCrane handles sessions using PHP's built-in session management.\r\n\r\n### Starting Sessions\r\n\r\nSessions are automatically started when accessing session data.\r\n\r\n### Setting Session Data\r\n\r\nUse `$response-\u003esession($key, $value)` to set session data:\r\n\r\n```php\r\n$app-\u003epost('/login', function($request, $response) {\r\n    // Authenticate user\r\n    $response-\u003esession('user_id', 123);\r\n    $response-\u003esession('username', 'john');\r\n    return $response-\u003eredirect('/dashboard');\r\n});\r\n```\r\n\r\n### Getting Session Data\r\n\r\nUse `$request-\u003esession($key)` to get session data:\r\n\r\n```php\r\n$app-\u003eget('/dashboard', function($request, $response) {\r\n    $userId = $request-\u003esession('user_id');\r\n    if (!$userId) {\r\n        return $response-\u003eredirect('/login');\r\n    }\r\n    return $response-\u003erender('dashboard.html', ['user_id' =\u003e $userId]);\r\n});\r\n```\r\n\r\n### Getting All Session Data\r\n\r\nUse `$request-\u003esession()` without parameters:\r\n\r\n```php\r\n$sessions = $request-\u003esession();\r\n```\r\n\r\n### Destroying Sessions\r\n\r\nTo destroy a session, use PHP's session_destroy():\r\n\r\n```php\r\nsession_destroy();\r\n```\r\n\r\n## Cookies\r\n\r\nCrane provides methods to set and get cookies.\r\n\r\n### Setting Cookies\r\n\r\nUse `$response-\u003ecookie($name, $value, $options)` to set a cookie:\r\n\r\n```php\r\n$app-\u003epost('/set-preference', function($request, $response) {\r\n    $response-\u003ecookie('theme', 'dark', time() + 3600, '/', '', false, true);\r\n    return $response-\u003ejson(['status' =\u003e 'preference set']);\r\n});\r\n```\r\n\r\nParameters:\r\n\r\n- $name: Cookie name\r\n- $value: Cookie value\r\n- $expires_or_options: Expiration time or options array\r\n- $path: Path\r\n- $domain: Domain\r\n- $secure: HTTPS only\r\n- $httponly: HTTP only\r\n\r\n### Getting Cookies\r\n\r\nUse `$request-\u003ecookie($key)` to get a cookie:\r\n\r\n```php\r\n$app-\u003eget('/profile', function($request, $response) {\r\n    $theme = $request-\u003ecookie('theme') ?? 'light';\r\n    return $response-\u003erender('profile.html', ['theme' =\u003e $theme]);\r\n});\r\n```\r\n\r\n### Getting All Cookies\r\n\r\nUse `$request-\u003ecookie()` without parameters:\r\n\r\n```php\r\n$cookies = $request-\u003ecookie();\r\n```\r\n\r\n\r\n## Contact  \r\n**Email** : paul@paulrobert.net","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrenotype%2Fcrane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphrenotype%2Fcrane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrenotype%2Fcrane/lists"}