Alpha ZealPHP is early-stage and under active development. APIs may change between minor versions until v1.0. Feedback and bug reports welcome on GitHub.

Your First Page

Drop a file, get a URL. The filesystem is the router.

You will learn

  • Create a page by adding a file to public/
  • How implicit routing maps files to URLs
  • Add dynamic content with PHP
  • Handle query parameters

The problem

In most frameworks, adding a new page means editing a routing table, creating a controller, registering it somewhere, and maybe writing a view. That's a lot of ceremony for "show some HTML."

ZealPHP takes a different approach: the filesystem is the router.

Step 1: Create a file

Create a file at public/greeting.php:

<?php
echo "<h1>Hello, World!</h1>";
echo "<p>This page was served by ZealPHP.</p>";

Step 2: Visit the URL

Open http://localhost:8080/greeting in your browser. That's it — no routing config, no controller registration. ZealPHP saw a file at public/greeting.php and mapped it to GET /greeting automatically.

How implicit routing works

Think of the public/ folder as a filing cabinet. Folders are drawers, files are documents. The URL is the path you'd describe to find a document:

public/index.php       → GET /
public/about.php       → GET /about
public/blog/post.php   → GET /blog/post
public/css/site.css    → GET /css/site.css  (static files too)

No configuration. No routing table. The file's location is its URL. If you rename the file, the URL changes. If you delete the file, the URL returns 404.

Adding dynamic content

These are PHP files, so you can use any PHP you want. Let's make the greeting personal:

<?php
$name = htmlspecialchars($_GET['name'] ?? 'World');
echo "<h1>Hello, {$name}!</h1>";
echo "<p>The time is " . date('H:i:s') . "</p>";

Visit /greeting?name=Alice and the page greets Alice by name.

See it live

This very site uses implicit routing. The page you're reading right now is served from public/learn.php. Every page in the docs — /routing, /streaming, /ws — is a file in public/.

Try it: Open the greeting demo →

What about messy URLs?

"But I don't want .php in my URLs!" — you won't see them. ZealPHP strips the extension automatically. public/about.php responds at /about, not /about.php. Requesting /about.php directly returns 403.

Using a layout

Right now, your page outputs raw HTML with no <head>, no stylesheet, no navigation. Every real page needs a shared layout. The next lesson teaches you how to wrap pages in a layout template using App::render().

Here's a preview — this is how most pages in ZealPHP apps look:

<?php use ZealPHP\App;
App::render('/_master', [
    'title' => 'About',
    'page'  => 'about',
]);

That's the entire file. Three lines. The master template handles the HTML shell, nav, footer, and CSS — your page template only has the content.

If you create a file at public/blog/post.php, what URL will serve it?

Key Takeaways

  • Files in public/ automatically become URLs — no routing config needed
  • The URL mirrors the file path: public/blog/post.php/blog/post
  • Use $_GET for query parameters, standard PHP for dynamic content
  • .php extensions are stripped — clean URLs by default