Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions frameworks/laravel/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM dunglas/frankenphp:latest

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

RUN install-php-extensions pcntl opcache zip

WORKDIR /app

COPY composer.json ./
RUN composer install --no-dev --optimize-autoloader --no-interaction --no-scripts

COPY . .
RUN mkdir -p storage/framework/cache storage/framework/sessions storage/framework/views storage/logs bootstrap/cache

# post_max_size unlimited so the 20 MB upload profile is not rejected, opcache
# with timestamp validation off as the Laravel deployment guide recommends.
COPY php.ini $PHP_INI_DIR/conf.d/99-httparena.ini

ENV APP_ENV=production \
APP_DEBUG=false \
APP_KEY=base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= \
LOG_CHANNEL=null \
SERVER_NAME=:8080

EXPOSE 8080
CMD ["php", "artisan", "octane:start", "--server=frankenphp", "--host=0.0.0.0", "--port=8080", "--admin-port=2019"]
27 changes: 27 additions & 0 deletions frameworks/laravel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# laravel

Laravel 13 served by Laravel Octane on FrankenPHP.

## Stack

- **Language:** PHP 8.5
- **Framework:** Laravel 13
- **Server:** Laravel Octane on FrankenPHP, one worker per core
- **Build:** `dunglas/frankenphp`

## Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/pipeline` | GET | Returns `ok` (plain text) |
| `/baseline11` | GET | Sums query parameter values |
| `/baseline11` | POST | Sums query parameters + request body |
| `/json/{count}?m=N` | GET | First `count` dataset items with `total = price * quantity * m` |
| `/upload` | POST | Reads the body stream and returns the byte count |

## Notes

- Routes are registered through the `api` group, so no session, no cookies and no CSRF token
- Octane is the runtime Laravel documents for production, so the framework boots once per worker
- Compression comes from the Caddy `encode` directive in the Caddyfile Octane generates
- `post_max_size=0` because PHP otherwise rejects the 20 MB upload profile with 413
14 changes: 14 additions & 0 deletions frameworks/laravel/artisan
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env php
<?php

use Illuminate\Foundation\Application;
use Symfony\Component\Console\Input\ArgvInput;

define('LARAVEL_START', microtime(true));

require __DIR__.'/vendor/autoload.php';

/** @var Application $app */
$app = require_once __DIR__.'/bootstrap/app.php';

exit($app->handleCommand(new ArgvInput));
19 changes: 19 additions & 0 deletions frameworks/laravel/bootstrap/app.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

// Routes are registered through the api group: no session, no cookies and no
// CSRF token, which the benchmark endpoints do not use.
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
api: __DIR__.'/../routes/api.php',
apiPrefix: '',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
20 changes: 20 additions & 0 deletions frameworks/laravel/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"type": "project",
"license": "MIT",
"require": {
"php": "^8.3",
"laravel/framework": "^13.0",
"laravel/octane": "^2.19"
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}
19 changes: 19 additions & 0 deletions frameworks/laravel/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"display_name": "laravel",
"language": "PHP",
"type": "flagship",
"mode": "standard",
"engine": "frankenphp",
"description": "Laravel 13 served by Laravel Octane on FrankenPHP, the first-party production runtime documented by Laravel. Routing and request handling through the Laravel API, responses via the response()/json() helpers, gzip and brotli through the Caddy encode directive Octane generates.",
"repo": "https://github.com/laravel/laravel",
"enabled": true,
"tests": [
"baseline",
"pipelined",
"limited-conn",
"json",
"json-comp",
"upload"
],
"maintainers": []
}
6 changes: 6 additions & 0 deletions frameworks/laravel/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
post_max_size=0
memory_limit=512M
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
11 changes: 11 additions & 0 deletions frameworks/laravel/public/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

use Illuminate\Foundation\Application;
use Illuminate\Http\Request;

require __DIR__.'/../vendor/autoload.php';

/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';

$app->handleRequest(Request::capture());
50 changes: 50 additions & 0 deletions frameworks/laravel/routes/api.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

$dataset = json_decode(file_get_contents(env('DATASET_PATH', '/data/dataset.json')), true) ?: [];

Route::get('/pipeline', function () {
return response('ok')->header('Content-Type', 'text/plain');
});

Route::match(['get', 'post'], '/baseline11', function (Request $request) {
$total = 0;
foreach ($request->query() as $value) {
if (is_numeric($value)) {
$total += (int) $value;
}
}
if ($request->isMethod('post')) {
$body = trim($request->getContent());
if (is_numeric($body)) {
$total += (int) $body;
}
}

return response((string) $total)->header('Content-Type', 'text/plain');
});

Route::get('/json/{count}', function (Request $request, int $count) use ($dataset) {
$count = max(0, min($count, count($dataset)));
$m = (int) $request->query('m', 1) ?: 1;

$items = [];
foreach (array_slice($dataset, 0, $count) as $item) {
$item['total'] = $item['price'] * $item['quantity'] * $m;
$items[] = $item;
}

return response()->json(['items' => $items, 'count' => count($items)]);
});

Route::post('/upload', function (Request $request) {
$size = 0;
$stream = $request->getContent(true);
while (! feof($stream)) {
$size += strlen(fread($stream, 262144));
}

return response((string) $size)->header('Content-Type', 'text/plain');
});
8 changes: 8 additions & 0 deletions site/data/frameworks.json
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,14 @@
"engine": "netty",
"mode": "standard"
},
"laravel": {
"dir": "laravel",
"description": "Laravel 13 served by Laravel Octane on FrankenPHP, the first-party production runtime documented by Laravel. Routing and request handling through the Laravel API, responses via the response()/json() helpers, gzip and brotli through the Caddy encode directive Octane generates.",
"repo": "https://github.com/laravel/laravel",
"type": "flagship",
"engine": "frankenphp",
"mode": "standard"
},
"libreactorng": {
"dir": "libreactorng",
"description": "libreactorng \u2014 Fredrik Widlund's io_uring-native event framework, the successor to the long-running epoll-based libreactor. Built directly on Linux io_uring syscalls with zero third-party runtime deps. Minimal server dispatches /pipeline, /baseline11, /baseline2 via the built-in HTTP parser; one reactor process per logical CPU via SO_REUSEPORT.",
Expand Down
Loading