PHP - Architecture
Catégorie | Cours |
---|
Cours de Julie Chaumard
To Do
Chapters | Homeworks | Exercises | Weeks | Dates |
---|---|---|---|---|
PHP | 4 | 23/06/2025 | ||
4 | 24/06/2025 | |||
Book - Chapter 11 - P.493
- Connolly, R. and Hoar, R. (2018). Fundamentals of Web Development (2nd ed.). Pearson.
Display in PHP
- echo
- print_r
- To display the contents of an array in a friendly manner
echo '<pre>';print_r($myArray);echo '</pre>';
Paths
Type of paths
Canonical
For the entire URL, not a short one
https://www.mydomain.com/images/logo.png
Absolut
Entire path from the root
/var/www/html/project/includes/init.php
Relative
A path based on the current location
../includes/header.php
Retrieve the path
- dirname() : the folder of a file
dirname(string $path, int $levels = 1): string echo dirname('/var/www/html/index.php'); // Résultat : /var/www/html echo dirname('/var/www/html/index.php', 2); // Résultat : /var/www
- realpath() : returns the absolute path of a file or directory, resolving relative paths (../, ./)
echo realpath('config/../includes/init.php'); //return /var/www/html/project/includes/init.php
- Get the relative path of the project
define('ROOT_DIR', realpath(__DIR__)); $relativePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', ROOT_DIR); DOCUMENT_ROOT = /home/juliechaat/www ROOT_DIR = /home/juliechaat/www/tutos/web_dev/practice/exercices // You get the relative path tutos/web_dev/practice/exercices
- Add the Domain name to have the exact URL of the project
SEO and paths
- In the internal links with
<a>
you should put the relative path of the page and not the entire canonical URL.- Search engine understand and convert itself to absolut path
Portability
Project portability means the ability of a project to be moved or used in different environments (local server, remote server, new folder, new domain…) without needing to change the code.
If the project is portable, everything works without modification:
- internal links
- CSS, JS, and image paths
- PHP includes (require, include)
- the database connection (if properly configured)
- redirections
What makes a project non-portable: hard-coded absolute paths
How to make partable
1. Organisation des chemins
- Définir une constante ROOT_DIR dans bootstrap.php avec realpath(__DIR__)
- Utiliser ROOT_DIR pour toutes les inclusions PHP (require, include)
- Éviter les chemins absolus codés en dur (ex: /Users/Julie/Desktop/monprojet/)
- Utiliser dirname(__FILE__) ou __DIR__ au lieu de chemins relatifs complexes comme ../../
2. Gestion des URL
- Définir une constante BASE_URL dans bootstrap.php à partir de $_SERVER
- Utiliser <?= BASE_URL ?> pour toutes les URL dans le HTML (CSS, JS, liens)
- Éviter d’écrire le nom de domaine en dur (ex: http://localhost/monprojet/)
3. Inclusion de fichiers PHP
- Centraliser tous les require et include dans un fichier bootstrap.php
- Utiliser require_once ROOT_DIR . '/includes/fichier.php' partout
- Créer des chemins dynamiques pour les templates (header, footer, etc.)
4. Chemins vers les assets (CSS, JS, images)
- Ne pas utiliser de chemins relatifs comme ../assets/css/style.css dans le HTML
- Utiliser des chemins absolus à partir de la racine web /assets/... ou <?= BASE_URL ?>/assets/...
5. Structure des dossiers
- Organiser clairement le projet (ex: /public, /includes, /config, /template-parts)
- Mettre le point d’entrée (index.php) dans /public
- Protéger les autres dossiers via .htaccess si besoin
6. Configuration (base de données, constantes)
- Placer les infos sensibles (connexion BDD, clés API…) dans config.php
- Ne jamais versionner ce fichier (ajouter à .gitignore)
- Utiliser des variables d’environnement si possible (.env)
7. Redirections et formulaires
- Utiliser BASE_URL dans les action="..." de formulaires
- Utiliser header("Location: " . BASE_URL . "/page.php") pour les redirections
8. Déploiement
- Tester sur serveur local ET distant (MAMP, XAMPP, OVH, o2switch…)
- Vérifier que tous les chemins fonctionnent après déplacement du projet
- S’assurer qu’il n’y a aucune dépendance au chemin local du développeur
Bootstrap.php
A file to give the root instruction of your project.
To automatically define the path to not have to change it when you change the web server of your project
DOCUMENT_ROOT = /home/juliechaat/www
ROOT_DIR = /home/juliechaat/www/tutos/web_dev/practice/exercices
// You get the relative path
tutos/web_dev/practice/exercices
<?php
// bootstrap.php
// Project root path
// define('ROOT_DIR', realpath(__DIR__));
// Relative path = substract the absolut project path ($_SERVER['DOCUMENT_ROOT'] ) to the path of the file (dirname(__DIR__))
$relativePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', ROOT_DIR);
// The directory of the project
define('BASE_URL_REL', $relativePath);
// Protocol : http or https ?
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
// the domain name
$host = $_SERVER['HTTP_HOST'];
An Improved Architecture
- Organize all your pages inside a dedicated folder (e.g.
page-templates/
) to keep your project structure clean.
- Create a
router.php
file to dynamically serve the correct page from the folder based on the URL.
- Configure an
.htaccess
file to enable clean, user-friendly, and SEO-friendly URLs (e.g./exercise_1
instead of/router.php?page=exercise_1
).
Note: This is not a fully implemented MVC (Model-View-Controller) architecture, but it follows a similar logic by separating responsibilities and organizing code for better maintainability.
MCV architecture
MVC stands for Model - View - Controller. It’s a design pattern used to separate different parts of a web application:
- Model → handles the data and business logic (database queries, calculations …).
- View → displays the user interface (HTML templates, CSS).
- Controller → acts as a middleman between the Model and the View (receives user input, fetches data from the model, and sends it to the view, ….).
This structure helps keep code modular, testable, and easier to maintain.
What would be needed for full MVC here?
To turn our current routing system into a real MVC structure, we would need to:
- Create a controllers/ folder
Each controller handles requests, calls the model, and returns a view.
- Create a models/ folder
Each model represents a type of data (User.php, Product.php, …) and handles database operations.
- Create a views/ folder
Each view is a template (PHP, HTML, etc.) responsible only for presentation.
- Update the router to load the right controller based on the URL.
Practice
Implement an organized architecture in the sample project
funwebdev (project folder)
├── exercices
├── assets
│ ├── css
│ │ ├── footer.css
│ │ ├── header.css
│ │ └── main.css
│ ├── fonts
│ │ ├── SourGummy_Expanded-Light.ttf
│ ├── images
│ │ ├── 5855174537.jpg
│ │ └── central-park.jpg
│ └── js
│ ├── countries.js
│ └── exercise_1.js
├── bootstrap.php
├── index.php
├── page-templates
│ ├── countries.php
│ ├── exercise_1.php
│ ├── exercise_2.php
│ ├── folder_2
│ │ └── exercise_3.php
│ └── infophp.php
├── readme.md
├── router.php
├── template-parts
│ ├── footer.php
│ ├── head.php
│ └── header.php
├── test.php
└── test2.php
exercices/index.php
<?php
require_once __DIR__ . '/bootstrap.php';
include ROOT_DIR . '/template-parts/head.php';
include ROOT_DIR . '/template-parts/header.php';
?>
<main>
<h1>Home Page</h1>
</main>
<?php
include_once('template-parts/footer.php');
?>
exercices/.htaccess
Be careful: when you upload the project files to your web host, .htaccess is a hidden file — don’t forget to include it!
RewriteEngine On
# Si le fichier ou dossier existe, ne rien faire
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Sinon, rediriger vers router.php
RewriteRule ^(.+)$ router.php?page=$1 [QSA,L]
exercices/router.php
<?php
require_once __DIR__ . '/bootstrap.php';
// This router dynamically loads pages from the "page-templates" folder
// It supports clean URLs using .htaccess rewriting rules
// $_GET contains the parameters passed in the URL, such as ?page=exercise_1
// $_GET['page'] can also include a subfolder, like folder_2/exercise_3
$page = $_GET['page'] ?? 'index';
//echo $_GET['page'];
// path to the page-templates to display
if ($page === "index") {
$file = __DIR__ . "/" . $page . '.php';
} else {
$file = __DIR__ . '/page-templates/' . $page . '.php';
}
// if the page-templates exists => display the page, else display error 404
if (file_exists($file)) {
require_once $file;
} else {
http_response_code(404);
echo "<h1>404 - Page not found</h1>";
}
/template-parts/header.php
<header>
<nav>
<ul>
<li><a href="<?php echo BASE_URL_REL ?>/exercise_1"><i class="fa-solid fa-user"></i>Exercise 1</a></li>
<li><a href="<?php echo BASE_URL_REL ?>/exercise_2">Exercise 2</a></li>
<li><a href="<?php echo BASE_URL_REL ?>/folder_2/exercise_3">Exercise 3</a></li>
<li><a href="<?php echo BASE_URL_REL ?>/countries">Countries</a></li>
<li><a href="#footer_page">Footer</a></li>
<li><a href="<?php echo BASE_URL_REL ?>/exercise_2#footer_page">Exercise 2 Footer</a></li>
</ul>
</nav>
</header>
exercices/bootstrap.php
<?php
// bootstrap.php
// Project root path
define('ROOT_DIR', realpath(__DIR__));
// Protocol : http or https ?
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
// the domain name
$host = $_SERVER['HTTP_HOST'];
// Relative path = substract the absolut project path ($_SERVER['DOCUMENT_ROOT'] ) to the path of the file (dirname(__DIR__))
$relativePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', ROOT_DIR);
// The directory of the project
define('BASE_URL_REL', $relativePath);
Agence digitale Parisweb.art
Tout savoir sur Julie, notre directrice de projets digitaux :
https://www.linkedin.com/in/juliechaumard/