2.3 · Includes, organization & file handling

Level 2 · PHP & the Web

2.3Includes, organization & file handling

Goal: Organize your code with includes (require/include, config, header/footer) and handle files (read/write, secure uploads) — while avoiding inclusion and upload flaws.
Estimated time: 11 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • Write once, include everywhere: header, footer, config and functions live in dedicated files assembled with require/include — zero duplication.
  • require for the essential: require fails fatally if the file is missing (config, functions), include only warns — *_once avoids redefinitions.
  • Uploads = hostile input: real type checked, size limited, file renamed, storage with no PHP execution — an uploaded executable PHP file hands the server to the attacker.

Running mini-case — Riad tidies up the association website

Riad's association website is growing: the same menu copied into ten pages, the database connection copied everywhere — each change becomes painful. He tidies up: config.php for settings, header.php and footer.php for layout, fonctions.php for utilities, each page assembled with require. Then he adds event photo uploads: the upload is treated as hostile input — real type checked, file renamed, stored with no PHP execution. In 2.4, he will timestamp these photos with DateTime.

Sequel to thread 2.2: Riad's site moves from duplicated tinkering to a clean structure — and continues in 2.4.

1. Includes: write once, reuse everywhere

A real site shares common elements (header, menu, footer, configuration): duplicating them in every file is tedious and unmaintainable. PHP offers inclusion statements: include and require insert the contents of one file into another. The difference: require triggers a FATAL ERROR if the file cannot be found — for ESSENTIAL files (configuration, core functions); include only emits a warning and continues — for optional files. Their require_once and include_once variants guarantee a UNIQUE inclusion (no redefinitions) — often preferable. Typical: header.php and footer.php included in each page, config.php required at the top of scripts. Riad now edits his menu in a single place. A crucial SECURITY point: NEVER include a path coming from user input (include $_GET['page']) — it is an arbitrary file inclusion flaw.

2. Organizing before frameworks

These inclusions underpin the organization of a hand-built project: splitting the code into logical files (configuration, functions, interface elements, pages) and assembling them — a first step towards a clean architecture, leading to MVC (section 4-1) and autoloading (section 3-3). The principles: SEPARATE by responsibility, REUSE through includes, SEPARATE logic (processing, queries) from display (the HTML afterwards), arrange into clear folders (includes/, pages, assets/, secured uploads/), and place sensitive files (config with credentials) OUTSIDE the web root. Riad's site adopts this structure: every page starts with requiring the config, does its logic, then includes the display.

3. Files and uploads: read, write, stay suspicious

PHP READS and WRITES server files: file_get_contents() (read all), file_put_contents() (write), fopen()/fread()/fwrite()/fclose() (step by step, large files), file_exists(), unlink() (delete). The sensitive case: uploads, files sent by the user in $_FILES — to treat as hostile input. The protections, all together: CHECK the REAL type (the content, not the declared extension, which can be forged) with an allowlist and the SIZE; RENAME the file (never the user name); store it OUTSIDE the web root or in a folder with NO PHP execution — otherwise a malicious uploaded PHP file called by URL runs and compromises the server; move it with move_uploaded_file() after checking the error code. Riad's event photos follow exactly this protocol.

Common misinterpretation: “Checking the uploaded file's extension is enough — .jpg means it is an image.” No. The extension and the browser-declared type are forged in one line: a malicious script renamed photo.jpg passes that check effortlessly. Serious checking targets the REAL CONTENT (server-detected MIME type, strict allowlist), combined with renaming and above all storage with no PHP execution — even a trapped file becomes harmless. Riad's rule: an upload is hostile input; treat it as such, with all the protections, not just one.
Organizing & handling files Structure, secure Includesrequire (fatal) / include; *_once (unique)+OrganizationConfig, header/footer, separate functions+Uploads ($_FILES)Type/size, rename, no PHP execution Never include a path coming from the user (inclusion flaw).
Structure, secure
Text version of the diagram (SEO / screen readers / translation): 1) Riad WRITES ONCE: config, header, footer and functions live in dedicated files; each page assembles them with require — no more duplication. 2) He picks the right tool: require (fatal) for the essential, include for the optional, *_once against redefinitions — and never a path coming from the user. 3) He treats UPLOADS as hostile: real type and size checked, file renamed, stored with no PHP execution. Lesson: structure code with includes, secure every incoming file.

🔎 Concrete example — 🔎 Concrete example — Riad's event photos, secured

All the protections, as for Riad's uploads:

// check error, size, REAL TYPE (allowlist)
$nom = bin2hex(random_bytes(8)) . '.jpg';
move_uploaded_file($_FILES['img']['tmp_name'],
  __DIR__ . '/../uploads/' . $nom);
// folder with no PHP execution

Reading: content checked, random renaming, storage with no execution.

Lesson: never keep the user-supplied name.

Section vocabulary

include / require
Insert the contents of one file into another; require triggers a FATAL error if missing (essentials), include a warning and continues (optionals).

Simple example: Riad requires config.php at the top of each page.

What it is not: copy-pasting the same menu into ten pages.

Reflex: essential = require.

require_once / include_once
Guarantee that a file is included only ONCE, avoiding multiple inclusions and redefinition errors — often preferable.

Simple example: fonctions.php is required with _once on all of Riad's pages.

What it is not: a repeated inclusion that redefines the same functions.

Reflex: shared file = _once by default.

Organization with includes
Splitting code into logical files (config, functions, header/footer, pages) assembled with includes; a first step towards a clean architecture (MVC, autoloading).

Simple example: Riad's site: config, header/footer, assembled pages.

What it is not: one big file mixing logic, queries and duplicated HTML.

Reflex: duplicated code = file to extract and include.

File handling
Reading and writing server files: file_get_contents, file_put_contents, fopen/fread/fwrite, file_exists, unlink.

Simple example: Riad reads a template and writes an export with file_get_contents/put_contents.

What it is not: an upload processed with no checks at all.

Reflex: server file = check existence and rights.

Uploads ($_FILES) — security
User-sent files ($_FILES): check real type and size, RENAME, store outside the root or with no PHP execution, limit extensions.

Simple example: Each of Riad's photos is renamed and stored with no PHP execution.

What it is not: a file kept under its original name in an executable folder.

Reflex: upload = hostile input, full protocol.

In practice — In practice — Organizing code and handling files

  1. Create header.php and footer.php and include them in several pages with require; create a config.php required at the top of scripts.
  2. Understand the require (fatal) / include (warning) difference and the point of require_once (unique inclusion).
  3. Read and write a file (file_get_contents / file_put_contents); check its existence (file_exists).
  4. Process an upload ($_FILES) SECURELY: check real type and size, RENAME the file, store it in a folder with no PHP execution — and NEVER include a path coming from the user.
You organize your code with includes (require/include, config, header/footer) and handle files (read/write, secure uploads) — while avoiding inclusion and upload flaws.

Ready-to-say script — explaining the tidy-up to the association office (30 s)

“I tidied up the site: the menu and footer exist in a single copy; each page includes them — a change is made in one place. And for photos, each file is checked, renamed and stored in a folder where no script can run: even a trapped file stays harmless.”

Say it while showing a menu change applied everywhere instantly.

Copy-paste template — assembled page skeleton


Small showcase site

Five pages share header and footer: Riad fixes the menu once, the whole site follows.

Protected config

Database credentials outside the web root, required at the top: never exposed by URL, never in the repository.

Data export

The member list is written with file_put_contents after file_exists: controlled reading and writing.

Event photos

Renamed uploads, real type checked, folder with no PHP execution: the gallery stays harmless.

Caution: An upload folder where PHP runs turns each upload into a potential takeover: a malicious file called by its URL runs on your server (data theft, total compromise). Always store uploads outside the web root or with no PHP execution, and never include a path coming from the user. This guide gives the basic protocol — have any real upload system audited before going live.

✓ Best practices

  • Split code into logical files and reuse through includes.
  • Prefer require for essential files and *_once against redefinitions.
  • Treat uploads with all the protections (real type, renaming, no execution).

✗ Common pitfalls

  • Including a path coming from user input (arbitrary file inclusion).
  • Keeping a user-supplied name for an uploaded file.
  • Storing uploads in a folder where PHP runs (takeover).

Key takeaways

  • INCLUDES (include/require): inserting one file into another to avoid duplicating (header, footer, config, functions). require = fatal if missing (essentials); include = warning (optionals); *_once = unique inclusion.
  • Organizing code into logical files assembled with includes = a first step towards a clean architecture (before MVC/autoloading).
  • FLAW TO AVOID: NEVER include a path coming from USER input (include $_GET['page']) — arbitrary file inclusion.
  • FILE HANDLING (file_get_contents/put_contents, fopen…) and above all SECURE UPLOADS ($_FILES): check real type/size, RENAME, store with no PHP execution, limit extensions (a classic source of serious flaws).

48h challenge — apply it tomorrow

Factor a real project: extract header, footer and config into files included with require/require_once, logic before display. Then secure a real upload: real type, size, renaming, folder with no PHP execution.

Section exit checklist
  • I can explain require vs include and the point of *_once.
  • I can structure a project (config, header/footer, logic before display).
  • I have secured a real upload with the full protocol.
Self-rating 1-5: do I factor instead of duplicating?do I treat each upload as hostile input?

Frequently asked questions

How do I cleanly organize a hand-built PHP project before using a framework?

Aim for SEPARATION and REUSE, against “spaghetti code” (everything mixed, duplicated, unstructured). (1) SEPARATE into logical files: configuration (config.php), reusable functions (or classes, level 3), shared interface (header.php, footer.php), pages (specific content). (2) REUSE through includes: written once, included everywhere — one change in a single place. (3) SEPARATE logic and display: logic first (processing, queries), HTML afterwards — the path towards MVC (section 4-1). (4) STRUCTURE the folders: includes/, pages, assets/, secured uploads/. (5) SECURE: sensitive files OUTSIDE the web root, ideally a single entry point, secrets out of the repository. This organization teaches the principles that FRAMEWORKS formalize (MVC, routing, autoloading, config, security).

Why are file uploads so security-sensitive, and how do I handle them safely?

An upload lets a user DROP a file onto YOUR server. The worst scenario: a malicious .php file uploaded then called by URL — the server RUNS it and the attacker takes control (files, database, everything). Other risks: huge files (denial of service), misleading types, overwriting. Protections, all together: (1) NEVER execute — folder with no PHP or OUTSIDE the web root: THE key protection. (2) RENAME (never the user name) with a safe name and a controlled extension. (3) CHECK the REAL TYPE (content, not the declared extension) — allowlist. (4) LIMIT the size. (5) Validate the extension (allowlist). (6) Check the $_FILES error code and move with move_uploaded_file(). In a real project, prefer the proven tools of frameworks for such a critical topic.

Check your understanding

What is THE key protection for uploaded files?

Additional resources (optional, to go further)

Level 2 examFresh, harder questions to test what you've learned