آموزش برنامهنویسی
آموزش PHP از صفر؛ یک فرم واقعی با اعتبارسنجی بساز
مرورگر و سرور را بفهم، POST را بخوان، ورودی را بررسی کن و خروجی HTML امن بنویس. پروژهٔ کامل برنامهریز مطالعه با PHP و تست همراه.

تصویر اختصاصی مجلهٔ ساروی؛ ساختهشده با هوش مصنوعی
اگر فایل PHP را با دوبار کلیک باز کنی و کد یا صفحهٔ خراب ببینی، هنوز PHP اجرا نشده است. PHP روی سرور کار میکند و نتیجهٔ HTML را به مرورگر میفرستد. در این درس یک فرم کوچک میسازیم که تعداد روز و دقیقهٔ مطالعه را میگیرد، ورودی خراب را رد میکند و زمان کل را نشان میدهد.
فرم PHP خودت را با ساروی توسعه بده۱. مسیر یک درخواست را بفهم
مرورگر صفحه را از سرور میخواهد. سرور فایل PHP را اجرا میکند و پاسخ HTML میدهد. وقتی فرم را ارسال میکنی، مرورگر درخواست تازهای با دادههای فرم میفرستد. PHP آن دادهها را میخواند و صفحهٔ نتیجه را میسازد.
در این نمونه، دادهای در پایگاه داده ذخیره نمیشود و ایمیلی ارسال نمیکنیم. این انتخاب کمک میکند اول جریان درخواست، اعتبارسنجی و نمایش را یاد بگیری. بعداً ذخیرهسازی و کنترل دسترسی، کارهای جدا با قراردادهای تازه خواهند بود.
۲. پروژه را با سرور محلی اجرا کن
فایلهای ZIP را در یک پوشه باز کن. php --version را بزن تا مطمئن شوی PHP 8 نصب است. سپس سرور توسعه را فقط روی 127.0.0.1 اجرا کن و نشانی را در مرورگر باز کن. سرور داخلی PHP برای توسعه و آزمایش است؛ آن را میزبان تولید عمومی فرض نکن.
php --version
php -S 127.0.0.1:8000
# Open http://127.0.0.1:8000/index.phpمنبع این بخش: PHP: سرور داخلی توسعه ↗
۳. متغیر و تابع را در یک مثال ببین
در PHP نام متغیر با $ شروع میشود. $days و $minutes ورودی عددی تابعاند و آرایهٔ خروجی، زمان کل را هم دارد. ضرب روز در دقیقه ساده است؛ بخش مهم، قرارداد ورودی است: روز از ۱ تا ۱۴ و دقیقهٔ روزانه از ۱۰ تا ۱۸۰.
declare(strict_types=1) در فراخوانیهای این فایل، تبدیل ضمنی بعضی نوعهای اسکالر را محدود میکند. این دستور جای بررسی دادهٔ HTTP را نمیگیرد؛ ورودی فرم همچنان باید پیش از ورود به منطق برنامه اعتبارسنجی شود.
<?php
declare(strict_types=1);
function studyPlan(int $days, int $minutes): array
{
if ($days < 1 || $days > 14 || $minutes < 10 || $minutes > 180) {
throw new InvalidArgumentException('Values outside allowed range');
}
return ['days' => $days, 'minutes' => $minutes, 'total' => $days * $minutes];
}
function escapeHtml(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
۴. فرم HTML چه دادهای میفرستد؟
name="days" نام کلید داده است. method="post" تعیین میکند فرم با POST ارسال شود. required و min و max به کاربر داخل مرورگر کمک میکنند، اما تضمین امنیت سمت سرور نیستند؛ درخواست را میتوان بدون همین فرم هم ساخت.
value مقدار قبلی را پس از خطا نگه میدارد تا کاربر مجبور نشود همهچیز را دوباره تایپ کند. چون این مقدار از ورودی آمده، قبل از نمایش داخل HTML آن را escape میکنیم. نسخهٔ کامل فایل همین رفتار را دارد.
۵. $_POST قابل اعتماد نیست
کاربر میتواند روز را متن، مقدار خالی یا حتی آرایه بفرستد. ابتدا بررسی میکنیم مقدار رشته است، سپس FILTER_VALIDATE_INT و بازهٔ مجاز را اعمال میکنیم. false یعنی اعتبارسنجی موفق نشده است.
از مقایسهٔ دقیق === false استفاده میکنیم. در پروژههای دیگر، صفر ممکن است مقدار معتبر باشد و مقایسهٔ شل، آن را با false اشتباه بگیرد. در این قرارداد، صفر مجاز نیست، ولی نوشتن شرط دقیق عادت بهتری برای فهم رفتار نوعهاست.
$daysRaw = is_string($_POST['days'] ?? null) ? $_POST['days'] : '';
$days = filter_var($daysRaw, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 14]
]);
if ($days === false) {
$errors[] = 'روزها باید عدد صحیح بین ۱ و ۱۴ باشد.';
}منبع این بخش: PHP: فیلترهای اعتبارسنجی ↗
۶. اعتبارسنجی و escape دو کار متفاوتاند
اعتبارسنجی میپرسد آیا داده برای مسئلهٔ ما معتبر است؟ escape میپرسد چطور این داده را در یک زمینهٔ خروجی مشخص، مثل متن یا ویژگی HTML، نمایش دهیم؟ htmlspecialchars برای زمینهٔ HTML استفاده شده است.
همین تابع جای آمادهسازی SQL، اعتبارسنجی URL یا قواعد جاوااسکریپت را نمیگیرد. اگر بعداً پایگاه داده اضافه کردی، باید از query پارامتری استفاده کنی. «ورودی را یک بار تمیز کردم» برای همهٔ محلهای مصرف معنی یکسانی ندارد.
منبع این بخش: PHP: htmlspecialchars ↗
۷. خطا را نزدیک به مسئله نشان بده
اگر روز ۳۰ باشد، پیام «روزها باید بین ۱ و ۱۴ باشد» از «ورودی نامعتبر» مفیدتر است. مقدارهای قبلی را نگه میداریم و تا وقتی خطا وجود دارد محاسبه نمیکنیم.
در فایل واقعی، منطق محاسبه در study-plan.php و رابط در index.php جداست. require با __DIR__ به پوشهٔ همین فایل اشاره میکند و به مسیر فعلی اجرای فرمان وابسته نیست. این تفکیک باعث میشود تست منطق، بدون ساخت درخواست مرورگر اجرا شود.
۸. تست و چند درخواست خراب
php -l فقط نحو را بررسی میکند؛ نتیجهٔ محاسبه را ثابت نمیکند. فایل تست، ۷ روز و ۳۰ دقیقه را با خروجی ۲۱۰ بررسی میکند و مرزهای نامعتبر را رد میکند. یک نمونهٔ escape هم آزمایش میشود.
در مرورگر، مقدار خالی، حداقل، حداکثر و ارسال دوبارهٔ فرم را امتحان کن. برای فهم کنترل سمت سرور، محدودیت HTML را با ابزار توسعه موقتاً تغییر بده و ببین PHP هنوز مقدار خارج از بازه را رد میکند.
php -l index.php
php study-plan-test.php
# PHP study planner: all checks passed۹. قدم بعدی: محاسبهٔ زمان را به برنامه تبدیل کن
سه موضوع درسی و وزن تقریبی هرکدام را به ورودی اضافه کن. پیش از کد، مثال بنویس: اگر ۲۱۰ دقیقه داریم و وزنها ۱، ۲ و ۴ است، سهمها ۳۰، ۶۰ و ۱۲۰ دقیقهاند. مشخص کن با گرد کردن و زمان باقیمانده چه میکنی.
اگر ذخیرهسازی یا حساب کاربری میخواهی، باید ماندگاری داده، احراز هویت و کنترل دسترسی طراحی شود. این فرم ساده هنوز آن نیازها را حل نکرده است. برای صفحهٔ ایستای معرفی، HTML و CSS مسیر کمپیچیدگیتری دارد.
۱۰. از AI تغییر کوچک و قابل بررسی بخواه
فایل فعلی و رفتار مورد انتظار را به ساروی بده. بگو ورودی نامعتبر باید رد شود و پیامها نزدیک فرم بمانند. درخواست «یک برنامهریز خیلی حرفهای» ممکن است چند قابلیت نیمهکاره اضافه کند که هنوز نمیدانی چطور بررسیشان کنی.
برای هر تغییر، یک ورودی درست و یک ورودی خراب تعریف کن. بعد از اصلاح، هر دو را اجرا کن. به این شکل هم پروژه جلو میرود و هم جریان PHP برایت روشن میماند.
این کار را خودت انجام بده.
- سرور محلی را در پوشهٔ پروژه اجرا کن.
- ورودی معتبر، خالی و خارج از بازه را امتحان کن.
- تست منطق و escaping را پیش از تغییر اجرا کن.
در انجام این کار به مشکل خوردی؟
از پشتیبانی کمک بگیر