You already have a working PHP page. Let's take it apart.
Opening Payments feels like opening one page. Behind the scenes, two files are working together: one decides what to show; the other decides where it goes.
This guide follows the simple Overview page you've been building. The code examples explain your application; they aren't connected to a simulator.
What happens when you open Payments?
- Your browser asks for
/.Apache selectspublic/index.php, according to the directory index setting you configured. - PHP runs
index.phpon the server.It assigns the page's text to variables, then loads your shared layout. - The layout produces HTML.PHP inserts the variable values into the heading, description and browser tab title.
- The browser displays the result.It receives HTML and loads your CSS. The PHP source itself stays on the server.
The useful bit: changing a PHP file affects what the server produces on the next request. You normally save the file and refresh the page; you don't restart Apache for a text change.
A small file with one clear job
Open /var/www/srnty/payments/public/index.php and you'll recognise this structure. A controller is simply the file that prepares this page. These comments explain each part:
<?php
// Start PHP mode. The server interprets the code below.
declare(strict_types=1);
// Use strict scalar type checking for function calls made from this file.
date_default_timezone_set('Europe/London');
// Use London time when PHP works with dates in this request.
$pageTitle = 'Overview';
// Store the page's heading text in a variable.
$pageDescription =
'Manage supplier payments outside the normal payment run.';
// Store a second piece of text. A statement can span multiple lines.
require __DIR__ . '/../views/layout.php';
// Load the shared layout, which can use the variables above.
declare(strict_types=1); must be the first statement in the file. Comments and blank lines can come before it. It doesn't validate your payment forms or check every variable.
There is no closing ?> here because the file contains only PHP. Leaving it out helps avoid accidentally sending whitespace to the browser.
A variable is a named value
$pageTitle = 'Overview';
$pageTitle- The variable's name. PHP variables begin with
$, and names are case-sensitive:$pageTitleand$pagetitleare different. =- Assign the value on the right to the variable on the left. It means “store this”, rather than “compare these”.
'Overview'- A string: text enclosed in matching quotes. The quote marks delimit the text; they aren't displayed as part of it.
;- The end of this statement. Missing it is a common cause of a syntax error.
Changing that line to $pageTitle = 'Payment cockpit'; changes the stored value. It doesn't print anything yet. Something must output it.
Comments are notes for you. PHP ignores text after // until the end of that line. /* ... */ is useful for longer comments. Neither appears as page content.
What does that require line actually mean?
require __DIR__ . '/../views/layout.php';
require- Load and run another file here. A missing required file causes an error; the page cannot carry on normally.
__DIR__- The directory containing this PHP file. In
public/index.php, that's/var/www/srnty/payments/public. .- Join two strings. PHP uses a dot for text concatenation.
/../views/layout.php- Move up from
publicintopayments, then intoviewsto findlayout.php.
The resulting location is /var/www/srnty/payments/views/layout.php. This is a server file path, not a browser URL.
Order matters: when your controller requires the layout, that layout can access the variables already defined in the controller. If the layout tries to output a variable before it has been defined, PHP can warn that it's undefined.
This is where PHP meets your HTML
In views/layout.php, the heading is:
<h1><?= e($pageTitle) ?></h1>
You know the <h1> part. The piece in the middle is PHP. <?= ... ?> means “output the result of this expression”. It's shorthand for:
<h1><?php echo e($pageTitle); ?></h1>
echo sends text into the response. If $pageTitle holds 'Overview', the browser receives:
<h1>Overview</h1>
One value, several places. Your layout uses $pageTitle in both the heading and the <title> element. Change the assignment once and both change. The sidebar's fixed Overview label is separate HTML, so it stays the same.
Display text as text
e() is a helper we defined in your layout. It isn't a built-in PHP function:
function e(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
function defines reusable code. $value receives the text passed into it. The two string declarations describe its input and return types. return hands the result back to the caller; it doesn't print it.
htmlspecialchars() is the built-in function doing the work. For example, if the title is '<b>Urgent</b>', it produces <b>Urgent</b>. The browser displays the literal text <b>Urgent</b> rather than making it bold.
ENT_QUOTES escapes both types of quotation mark, and 'UTF-8' specifies the text encoding. This helper is suitable for the HTML text and quoted attributes used here. It isn't a universal way to secure SQL, JavaScript or every other context.
Rename the heading, then see it happen
This is an optional manual exercise on your real site. These commands don't run from this page.
- Back up the controller. In your server terminal:
sudo install -d -o serenity -g serenity -m 0700 /var/www/srnty/payments/backups sudo -u serenity cp -p /var/www/srnty/payments/public/index.php "/var/www/srnty/payments/backups/index.php-before-heading-$(date +%Y%m%d-%H%M%S-%N)"This keeps a timestamped copy outside the public website folder.
- Open the file.
sudo -u serenity nano /var/www/srnty/payments/public/index.phpFind the existing
$pageTitleassignment. Change only its text:$pageTitle = 'Payment cockpit';Keep the rest of the file. Save with Ctrl+O, then Enter; exit with Ctrl+X.
- Check the syntax.
php -l /var/www/srnty/payments/public/index.php-lasks PHP to check syntax without executing the page. “No syntax errors detected” means the syntax passed, not that every behaviour is correct. If it reports an error, check the quotes and semicolon first. - Open the Overview page and refresh.
The heading should read Payment cockpit. The browser tab should read Payment cockpit | Additional Payments. The navigation label remains Overview.
Undo it: change the same assignment back to its previous text, usually 'Overview', save, check and refresh. No database changes are involved.
Where the other pieces fit
public/index.php- Prepares the Overview page. This is the controller we've followed above.
public/new-request.php- Prepares the New payment request page and selects its form view.
views/layout.php- Shared page structure. Uses the page variables and includes
$contentViewwhen provided. The Overview uses the fallback panel. views/request-form.php- The form's HTML. Showing fields is separate from validating or saving a request.
app/database.php- Creates and returns a PDO connection. A caller can receive it with
$pdo = require ...;. Loading a page layout alone doesn't query the database. config/database.php- Private connection settings. Keep credentials out of page output, screenshots and shared code.
public/assets/app.css- Appearance and layout in the browser. PHP chooses the text; CSS styles the resulting HTML.
The connection to remember: the controller assigns values → the layout outputs them → the browser displays HTML.