jasonhilder 5b2864c7d8 Added check for php server.
Added an if check that allows the built-in PHP server to serve existing files directly.
On a server it's handled by nginx, purely for ease of development.
2026-06-03 10:50:18 +02:00
2026-05-29 10:42:14 +02:00
2026-06-03 10:50:18 +02:00

miniPHP

A tiny PHP project template for small websites, internal tools, APIs, and personal projects.

miniPHP is not a framework.

There is no Composer requirement, no dependency injection container, no ORM, no service providers, and no framework lifecycle to learn.

Just plain PHP with a simple router, helper functions, optional SQLite support, and a project structure that stays out of your way.

Philosophy

The goal is simple:

  1. Clone the repository
  2. Run init_miniphp.sh
  3. Start building

If a feature can be implemented with a few lines of plain PHP, prefer that approach.

miniPHP exists for developers who want:

  • A clean starting point
  • Full control over their code
  • Zero framework lock-in
  • Zero external dependencies

Features

  • Zero dependencies
  • No Composer required
  • Simple config-based router
  • Page and API endpoints
  • Route prefix support
  • SQLite support via PDO
  • Shared view partials
  • Helper functions
  • Path traversal protection
  • Development server script
  • Project initialization script

Quick Start

Clone the repository:

git clone <repository-url> my-project
cd my-project

Initialize the project:

./init_miniphp.sh

The initializer will:

  • Remove the template git remote
  • Generate a new README
  • Prepare the project for a new repository

Then create your own repository and connect it:

git remote add origin <your-repository-url>
git push -u origin main

Start building.


Requirements

  • PHP 8.1+
  • PDO SQLite extension (optional)

View installed extensions:

php -m

Project Structure

config/
├── database.php
└── routes.php

public/
├── css/
│   └── app.css
└── js/
│   └── app.js

src/
├── api/
├── views/
│   ├── pages/
│   └── partials/
├── bootstrap.php
├── database.php
├── helpers.php
└── router.php

storage/
└── database.sqlite

index.php
server.sh
init_miniphp.sh

Running

Start the development server:

./server.sh

Default URL:

http://127.0.0.1:3333

Routing

Routes are defined in:

config/routes.php

Example:

return [
    'GET' => [
        '/'         => 'home.php',
        '/about'    => 'about.php',
        '/api/test' => 'api/example.php',
    ],
];

Route Prefixes

By default page routes resolve to:

src/views/pages/

Additional route prefixes can be registered:

$route_bases = [
    'api/' => ROOT . '/src/api',
];

Example:

'/api/users' => 'api/users.php',

loads:

src/api/users.php

while:

'/about' => 'about.php',

loads:

src/views/pages/about.php

Creating New Route Types

Create a new directory:

src/docs/

Register it:

$route_bases = [
    'api/'  => ROOT . '/src/api',
    'docs/' => ROOT . '/src/docs',
];

Now:

'/docs/getting-started' => 'docs/getting-started.php',

resolves to:

src/docs/getting-started.php

No router modifications required.


Pages

Create:

src/views/pages/contact.php

Example:

<?php partial('head', ['title' => 'Contact']); ?>

<h1>Contact</h1>

<p>Get in touch.</p>

<?php partial('footer'); ?>

Register the route:

'GET' => [
    '/contact' => 'contact.php',
],

Visit:

http://localhost:3333/contact

API Endpoints

Create:

src/api/contact.php

Example:

<?php

declare(strict_types=1);

header('Content-Type: application/json');

echo json_encode([ 'success' => true, ]);

Register the route:

'GET' => [
    '/api/contact' => 'api/contact.php',
],

Database

Configuration:

config/database.php

Usage:

$db = db();

$rows = $db->query( 'SELECT * FROM users')->fetchAll();

Helpers

Included helpers:

escape_string()
debug()
debugx()
get_config()
partial()

License

MIT

S
Description
No description provided
Readme MIT 56 KiB
Languages
PHP 84.4%
Shell 13.7%
CSS 0.9%
Hack 0.6%
JavaScript 0.4%