Lesson 7 / الدرس 7
One file, one job / ملف واحد، عمل واحد
Everything so far fits in one file. Real applications do not, and the mechanism that splits them is require — which is also, when handed a value from a visitor, one of the most dangerous things in the language.
كل ما سبق يسع ملفًا واحدًا. والتطبيقات الحقيقية لا تسعه، والآلية التي تقسّمها هي require — وهي أيضًا، حين تُسلَّم قيمة من زائر، من أخطر ما في اللغة.
require 'file.php' runs that file right here, as if you had pasted it in. Its functions become available, and anything it prints appears at that point in the page. That is the entire mechanism — every framework's loading machinery is this with automation on top.
require 'file.php' تشغّل ذلك الملف هنا تمامًا، كأنك لصقته. فتصير دالاته متاحة، ويظهر ما يطبعه عند تلك النقطة في الصفحة. وتلك هي الآلية كلها — فآليات التحميل في كل إطار هي هذه وفوقها أتمتة.Three ways to load a file, and one to use
| Form | If the file is missing | Use it for |
|---|---|---|
| require | Fatal error, execution stops | Anything the page cannot work without |
| include | Warning, execution continues | Almost nothing — the page limps on broken |
| require_once | Fatal, and never runs twice | Files defining functions or classes |
Use require, or require_once for definitions. include exists so that a missing file becomes a half-rendered page instead of an obvious failure, which is almost never what you want — a page that fails loudly gets fixed, and one that fails quietly ships.
require، أو require_once للتعريفات. أما include فموجودة ليصير الملف المفقود صفحة نصف مرسومة بدل إخفاق ظاهر، وهذا لا يكاد يكون ما تريد — فالصفحة التي تخفق بصوت عالٍ تُصلَح، والتي تخفق بهدوء تُشحن.The shape a small application takes
public/ <- the ONLY directory the web can reach
index.php <- the front controller; everything arrives here
assets/
src/ <- your code. Above the web root, unreachable.
bootstrap.php <- loads everything, once
Content.php
views/ <- the HTML-with-holes files
layout.php
home.php
content/ <- data
config.php <- credentials. Never in git.
public/ is reachable over the web; everything else sits one level above it, where no URL can name it. If config.php lived inside public/, a misconfigured server that stopped executing PHP would serve your database password as plain text. public/ وحدها هي التي يمكن بلوغها عبر الويب؛ وكل ما عداها يقبع فوقها بمستوى، حيث لا يستطيع رابط تسميته. ولو سكن config.php داخل public/، لقدّم خادمٌ سيئ الضبط كفّ عن تنفيذ PHP كلمةَ سر قاعدة بياناتك نصًّا صريحًا.<?php
// src/bootstrap.php — loaded once, by the front controller.
declare(strict_types=1);
require __DIR__ . '/../config.php';
require __DIR__ . '/helpers.php';
require __DIR__ . '/Content.php';
// __DIR__ is the directory of THIS file, always. A bare
// require 'helpers.php' is resolved against the working
// directory instead, which is whatever the caller happened
// to be in — so it works until the day the file is required
// from somewhere else.
require should start with __DIR__. It is the directory of the file doing the requiring, so the path means the same thing no matter who called it — a class of bug that is very hard to see and trivial to prevent. require ينبغي أن يبدأ بـ__DIR__. فهي مجلد الملف الطالب، فيعني المسار الشيء نفسه أيًّا كان المستدعي — وهو صنف من العلل يصعب رؤيته جدًا ويتفه منعه.require من أي شيء أرسله زائر أبدًا. فـrequire "pages/" . $_GET['p'] . ".php" تبدو معقولة وهي ثغرة تنفيذ كود عن بُعد: فـp بقيمة ../../config تقرأ بيانات اعتمادك، وإن كان مجلد رفعٍ قابلًا للبلوغ شغّلت ملفًا كتبه المهاجم. طابق المدخل مع قائمة أسماء كتبتها أنت — ولا تركّب منه مسارًا قط. وصنف Content في هذا الموقع يفحص نمط كل مسار محتوى مرتين، ولهذا السبب.Check yourself / اختبر نفسك
1. Why does only public/ sit inside the web root?
A misconfigured server that serves PHP files as text is a real failure mode. When the credentials are outside the document root, that failure exposes nothing, because no URL names them.
2. Why must a require path never be built from $_GET?
The fix is not to filter the value but to stop assembling paths at all: match the input against a list of names you wrote, and the attacker can only choose from your list.
3. Why start every require path with __DIR__?
A bare relative path resolves against the working directory, which belongs to whoever called you. It works until the file is required from somewhere else, and then fails in a way that looks unrelated to the change that caused it.
Score / النتيجة: 0 / 3