اعتبارسنجی دادهها در کدنویسی وردپرس
راهنمای عملی اعتبارسنجی دادهها در وردپرس؛ تفاوت اعتبارسنجی از پاکسازی، الگوهای عملی و اشتباهات رایج بر پایه تجربه واقعی.
چند سال پیش، ساعت یازده شب، تماسی از یک کارفرمای فروشگاهی گرفتم که صدایش میلرزید: «امروز ۲۰۰ بسته به آدرس اشتباه رفته، همه به یک کد پستی در شهری که ما اصلاً شعبه نداریم.» آن شب تا صبح کد را خواندم و وقتی به ریشه رسیدم، فهمیدم ماجرا هیچ ربطی به هک یا حمله نداشت. یک فرم ساده بود. یک فیلد کد پستی که ورودیاش از یک سرویس بیرونی میآمد و هیچکس چک نکرده بود که آن عدد، واقعاً یک کد پستی معتبر است یا یک عدد دلخواه که با فاصله اشتباهی وارد شده. اعتبارسنجی داده، دقیقاً همینجاست که اهمیتش خودش را نشان میدهد — نه در روزهای خوب، بلکه در همان شبی که ۲۰۰ بسته در مسیر اشتباه است و پول و اعتبار در حال سوختن است. این مقاله، همان چیزی است که در پروژههای واقعی برای اعتبارسنجی دادهها در وردپرس به کار میبرم. اگر با مفاهیم پایه آشنا نیستید، پیش از ادامه افزونه وردپرس چیست، نوشتن PHP امن برای وردپرس و پاکسازی دادهها در وردپرس را بخوانید.
داستانی که مسیر فنی مرا تغییر داد
آن شب بعد از تماس، سه چیز فهمیدم که تا امروز در هر پروژهای به کارم میآید:
اول، اعتبارسنجی داده فقط کار یک تابع یا یک قاعده نیست. آن فرم، از سه لایه تشکیل شده بود: فیلد سمت مرورگر با یک رجکس ساده، فیلد سمت سرور با sanitize_text_field، و ذخیره در دیتابیس با update_post_meta. هر سه لایه، داده را «تمیز» کرده بودند، اما هیچکدام نپرسیده بودند که آیا این داده «معتبر» است. و این تفاوت، همان چیزی است که ۲۰۰ بسته را به شهر اشتباه فرستاد.
دوم، اعتبارسنجی نه یک بار برای همیشه، بلکه بهازای هر نوع دادهای متفاوت است. کد پستی، شماره تلفن، ایمیل، کد ملی، تاریخ — هرکدام الگوی خودشان را دارند و اگر بخواهید با یک الگوی عمومی همه را پوشش دهید، نتیجه همان فاجعه است.
سوم، و مهمتر از همه: در پروژههای بعدی، هر جا دادهای از یک سرویس بیرونی میآمد، قبل از هر کار دیگری، یک لایه اعتبارسنجی جدا میگذاشتم. این عادت کوچک، در پنج پروژه بعدی، جلوی چند حادثه مشابه را گرفت. یکی از آنها، دادهای بود که یک افزونه تبدیل ارز، قیمتها را با اعشار اشتباه ذخیره میکرد و اگر اعتبارسنجی نبود، موجودی انبار را با اعداد اعشاری منفی میریخت.
اعتبارسنجی، هنر پرسیدن «آیا این داده واقعاً همان چیزی است که فکر میکنم؟» پیش از ذخیرهکردن آن است.
اعتبارسنجی دقیقاً چیست؟
اعتبارسنجی (Validation)، فرآیند بررسی این است که داده ورودی، با انتظارات ما مطابقت دارد یا نه. سوالهای اعتبارسنجی اینها هستند:
- آیا این داده، از نوع درست است؟ (عدد، متن، تاریخ)
- آیا این داده، در محدوده مجاز است؟ (طول، مقدار، بازه)
- آیا این داده، در قالب درست است؟ (ایمیل، URL، کد پستی)
- آیا این داده، وجود دارد و خالی نیست؟
- آیا این داده، با منطق کسبوکار ما سازگار است؟ (مثلاً تعداد، از موجودی انبار بیشتر نباشد)
اگر پاسخ به هرکدام «نه» باشد، داده باید رد شود و کاربر باید بازخورد مناسبی بگیرد. اینجا نکته مهمی است که در پروژههای واقعی بارها دیدهام: اعتبارسنجی، پیش از ذخیره داده اتفاق میافتد، نه بعد از آن. اگر داده معتبر وارد دیتابیس شود و بعداً بخواهید آن را درست کنید، نصفِ کار به بازسازی داده گذشته تلف میشود. آن ۲۰۰ بسته، برای همین «بعداً» رفتند — چون هیچکس قبل از ذخیره نپرسیده بود.
تفاوت اعتبارسنجی و پاکسازی
یکی از بیشترین سوءبرداشتها در پروژهها این است که اعتبارسنجی و پاکسازی را یکی میگیرند. این دو، دو کار متفاوت انجام میدهند:
| مفهوم | هدف | خروجی | تابع نمونه |
|---|---|---|---|
| پاکسازی (Sanitize) | ایمنسازی داده از کدهای خطرناک | دادهای که نمیتواند به سایت آسیب بزند | sanitize_text_field |
| اعتبارسنجی (Validate) | تطبیق دادن داده با انتظار منطقی | بله یا خیر — داده معتبر است یا نه | is_email، wp_checkdate |
یک مثال ساده: اگر کاربر ایمیل ali#example.com را وارد کند، پاکسازی آن را حفظ میکند (چون کاراکترهای خطرناک ندارد)، اما اعتبارسنجی میگوید این ایمیل معتبر نیست. یا کد پستی 0000000000 — پاکسازی آن را رد نمیکند، چون کد خطرناکی نیست؛ اما اعتبارسنجی میگوید کد پستی ایران ۱۰ رقم است و نه با صفر شروع میشود.
در پروژههای خودم، همیشه این دو لایه را جدا نگه میدارم: اول پاکسازی، تا داده خطرناک نباشد؛ سپس اعتبارسنجی، تا داده معتبر باشد. اگر فقط یکی را داشته باشید، نیمی از مسیر امنیت و صحت داده را طی کردهاید. تفصیل بیشتر را در پاکسازی دادهها در وردپرس آوردهام؛ این مقاله، روی لایه اعتبارسنجی تمرکز میکند.
پاکسازی، خطر را از داده میگیرد؛ اعتبارسنجی، درستی داده را تایید میکند. اولی امنیت میآورد، دومی صحت.
سه لایه اعتبارسنجی در وردپرس
در پروژههای واقعی، اعتبارسنجی را در سه لایه اجرا میکنم:
- لایه مرورگر (Client-side): برای تجربه کاربری سریع. اعتبارسنجی HTML5 و جاوااسکریپت اینجا انجام میشود. هدفش، بازخورد فوری به کاربر است، نه امنیت.
- لایه سرور (Server-side): برای امنیت و صحت واقعی. اینجا داده دوباره بررسی میشود، حتی اگر در لایه مرورگر تایید شده باشد.
- لایه منطق کسبوکار (Business logic): برای بررسیهایی که به دادههای دیگر سایت وابستهاند. مثلاً بررسی اینکه کد پستی، در لیست مناطق مجاز فروشگاه باشد.
نکته کلیدی که در پروژهها زیاد یادآوری میکنم: هرگز به اعتبارسنجی سمت مرورگر اعتماد نکنید. مهاجم میتواند درخواست POST را دستی ارسال کند یا کد جاوااسکریپت را دور بزند. اعتبارسنجی مرورگر، برای کاربر خوب و صادق است؛ برای مهاجم، مانعی نیست. اعتبارسنجی سرور، لایه واقعی دفاع است.
اعتبارسنجی سمت مرورگر
اعتبارسنجی سمت مرورگر، در HTML5 چند قابلیت استاندارد دارد که میتوانید بدون نوشتن یک خط جاوااسکریپت از آنها استفاده کنید:
<input type="email" required />
<input type="number" min="1" max="100" />
<input type="url" />
<input type="tel" pattern="[0-9]{10,11}" />
<input type="text" minlength="3" maxlength="50" />
این attributeها، در مرورگرهای مدرن، اعتبارسنجی سمت کاربر را انجام میدهند و پیام خطا نشان میدهند. اما سه محدودیت که در پروژهها دیدهام:
- پیامهای پیشفرض انگلیسی هستند. در سایت فارسی، پیام «Please fill out this field» تجربه کاربری بدی میسازد. مسیر سفارشیسازی این پیامها با جاوااسکریپت انجام میشود.
- قابل دور زدن هستند. مهاجم میتواند با ابزارهای مرورگر، این محدودیتها را بردارد. بنابراین هرگز نباید جای اعتبارسنجی سرور را بگیرند.
- در مرورگرهای قدیمی ممکن است پشتیبانی نشوند. برای کاربران با مرورگر قدیمی یا موبایلهای قدیمی، اعتبارسنجی مرورگر ممکن است کاملاً بیاثر باشد.
توصیه من در پروژههای ایرانی: از attributeهای HTML5 برای تسریع تجربه کاربری استفاده کنید، اما انتظار نداشته باشید که امنیت را تامین کنند. مسیر پیادهسازی فرم را در افزونههای فرمساز وردپرس آوردهام؛ یکی از معیارهای انتخاب فرمساز، پشتیبانی از اعتبارسنجی ترکیبی درست است.
اعتبارسنجی سمت سرور
اعتبارسنجی سمت سرور، لایه واقعی است. الگوی استاندارد:
function myplugin_process_form() {
// ۱. بررسی نانس و دسترسی
if ( ! isset( $_POST['nonce'] )
|| ! wp_verify_nonce( $_POST['nonce'], 'my_action' ) ) {
wp_die( 'درخواست نامعتبر' );
}
// ۲. پاکسازی
$email = sanitize_email( $_POST['email'] );
$age = absint( $_POST['age'] );
// ۳. اعتبارسنجی
$errors = array();
if ( ! is_email( $email ) ) {
$errors[] = 'ایمیل وارد شده معتبر نیست';
}
if ( $age < 18 || $age > 120 ) {
$errors[] = 'سن باید بین ۱۸ و ۱۲۰ سال باشد';
}
// ۴. تصمیم
if ( ! empty( $errors ) ) {
// بازگشت به فرم با پیامهای خطا
return;
}
// ۵. ذخیره
update_user_meta( get_current_user_id(), 'age', $age );
}
توابع اعتبارسنجی رایج در وردپرس:
is_email( $email ): بررسی معتبر بودن ایمیل.is_numeric( $value ): بررسی عددی بودن. توجه: این تابع با اعداد فارسی هم کار میکند.wp_checkdate( $month, $day, $year, $date ): بررسی معتبر بودن تاریخ میلادی.wp_check_filetype( $filename, $mimes ): بررسی نوع فایل بر اساس پسوند.is_wp_error( $thing ): بررسی اینکه آیا نتیجه یک تابع، خطا است یا نه.preg_match( $pattern, $subject ): برای اعتبارسنجی با الگوی regex (کد پستی، کد ملی، شماره تلفن).
یک نکته تخصصی که در پروژههای چندزبانه به کار میآید: اعداد فارسی (۱۲۳) و اعداد انگلیسی (123) در اعتبارسنجی PHP متفاوت رفتار میکنند. اگر فرم شما به کاربر اجازه میدهد عدد فارسی وارد کند، قبل از اعتبارسنجی با is_numeric، آن را با یک تابع تبدیل به عدد انگلیسی تبدیل کنید. این اشتباه، در سایتهای آموزشی و فروشگاهی با کاربران غیرفنی، بسیار رایج است و به پیام خطای اشتباه میانجامد.
الگوهای اعتبارسنجی دادههای رایج
هر نوع داده، الگوی اعتبارسنجی خودش را دارد. الگوهای زیر، تجربه چند ساله در پروژههای ایرانی است:
- شماره موبایل ایران: الگوی
/^09[0-9]{9}$/— دقیقاً ۱۱ رقم، شروع با ۰۹. - کد ملی ایران: ۱۰ رقم با الگوریتم چکسام خاص. پیادهسازی این چکسام در یک تابع جداگانه، دقیقتر از regex است.
- کد پستی ایران: ۱۰ رقم، بدون صفر شروع. توجه: اعتبارسنجی واقعی نیاز به API سازمان پست دارد؛ ولی چک فرمت اولیه از خطاهای واضح جلوگیری میکند.
- شماره شبا: شروع با IR، ۲۴ رقم پس از آن، با الگوریتم چکسام بینالمللی. پیادهسازی نادرست چکسام، شباهای معتبر را رد میکند.
- شماره کارت بانکی: ۱۶ رقم با الگوریتم Luhn. اعتبارسنجی Luhn میتواند اشتباهات تایپی کاربر را کشف کند، حتی اگر شماره در سیستم بانکی وجود نداشته باشد.
- ایمیل:
is_emailوردپرس کافی است. برای اعتبارسنجی پیشرفتهتر (بررسی MX رکورد)، به API خارجی نیاز دارید که معمولاً لازم نیست. - URL:
filter_var( $url, FILTER_VALIDATE_URL )یا بررسی باwp_http_validate_url. - تاریخ شمسی: تبدیل به میلادی و سپس
wp_checkdate. تبدیلگر شمسی به میلادی نیاز به کتابخانه دارد.
یک تجربه مستقیم: در یک پروژه فروشگاهی، تیم پشتیبانی مدام از «کد شبا نامعتبر» شاکی بود. بعد از بررسی، مشخص شد تابع اعتبارسنجی، الگوی چکسام را از منبعی کپی کرده بود که با فرمت شباهای ایرانی سازگار نبود. بعد از بازنویسی تابع با یک کتابخانه معتبر، شکایتها به صفر رسید. آن پروژه، درس بزرگی به من داد: قبل از استفاده از یک تابع اعتبارسنجی آماده، آن را با دادههای واقعی منطقه خودتان تست کنید.
اعتبارسنجی دادههای محلی، نیاز به تحقیق محلی دارد؛ الگوی جهانی، همیشه جواب نمیدهد.
اعتبارسنجی در REST API
در وردپرس ۴.۷ به بعد، REST API قابلیت اعتبارسنجی پارامترها را در سطح تعریف endpoint دارد. الگوی استاندارد:
register_rest_route( 'myplugin/v1', '/item', array(
'methods' => 'POST',
'callback' => 'myplugin_create_item',
'permission_callback' => function() {
return current_user_can( 'edit_posts' );
},
'args' => array(
'email' => array(
'required' => true,
'type' => 'string',
'format' => 'email',
'validate_callback' => function( $param ) {
return is_email( $param );
},
'sanitize_callback' => 'sanitize_email',
),
'age' => array(
'type' => 'integer',
'minimum' => 18,
'maximum' => 120,
),
),
) );
مزیت این الگو، این است که وردپرس، خودکار خطای ۴۰۰ با پیام مناسب برمیگرداند؛ نیازی به نوشتن کد اضافه برای اعتبارسنجی ندارید. راهنمای کامل را در ساخت API اختصاصی برای وردپرس و استفاده از REST API در وردپرس آوردهام.
بازخورد به کاربر و تجربه فرم
اعتبارسنجی، بدون بازخورد درست به کاربر، تجربه بدی میسازد. سه اصل در تجربه کاربری فرمهای اعتبارسنجیشده:
- پیام خطا کنار فیلد باشد، نه بالای فرم: کاربر باید بداند کدام فیلد مشکل دارد. پیام عمومی «اطلاعات ناقص است» تجربه بدی میسازد.
- پیام خطا مشخص و راهنما باشد: نه «ایمیل نامعتبر»، بلکه «ایمیل باید شامل @ و دامنه باشد. مثال: ali@example.com». راهنما، کاربر را از تکرار خطا نجات میدهد.
- داده معتبر را حفظ کنید: اگر فرمی خطا دارد و کاربر دوباره بازمیگردد، همه فیلدهای معتبر باید از پیش پر باشند. پاککردن فرم، کاربر را کلافه میکند.
تجربهام در پروژههای فروشگاهی این است که فرمهای اعتبارسنجیشده با بازخورد خوب، در حدود ۲۰ تا ۳۰ درصد نرخ تکمیل بالاتری دارند نسبت به فرمهای اعتبارسنجیشده با پیامهای عمومی. این تفاوت کوچک در UX، در تعداد سفارشهای ماهانه، تفاوت بزرگی میسازد. الگوی کامل فرم و تجربه کاربری را در افزونههای فرمساز وردپرس آوردهام.
جدول چکلیست اعتبارسنجی
جمعبندی چکلیست اعتبارسنجی دادهها در وردپرس:
| نوع داده | تابع یا ابزار | نکته مهم |
|---|---|---|
| ایمیل | is_email | پیش از ذخیره، sanitize_email هم اجرا شود |
| عدد صحیح | absint یا is_numeric | تبدیل اعداد فارسی به انگلیسی |
| عدد اعشاری | floatval یا is_numeric | دقت اعشار مناسب کسبوکار |
| URL | filter_var یا wp_http_validate_url | اجازه فقط پروتکل http و https |
| تاریخ میلادی | wp_checkdate | تبدیل تاریخ شمسی به میلادی اول |
| شماره موبایل ایران | preg_match با الگوی ۰۹ | توجه به پیششمارههای جدید |
| کد ملی ایران | الگوریتم چکسام | نه فقط regex، الگوریتم کامل |
| شماره شبا | کتابخانه معتبر + تست محلی | الگوی آماده غیرایرانی، اشتباه است |
| فایل آپلود | wp_check_filetype | لیست mimeهای مجاز مشخص باشد |
| REST API | args در register_rest_route | sanitize و validate جدا تعریف شوند |
اشتباهات رایج در اعتبارسنجی
در اشتباهات امنیتی رایج وردپرس و اشتباهات رایج کدنویسی وردپرس فهرست کامل را نوشتهام؛ اما شش مورد که در اعتبارسنجی بیشتر میبینم:
- اعتماد به اعتبارسنجی مرورگر: لایه مرورگر برای UX است، نه امنیت. هر داده باید سمت سرور دوباره بررسی شود.
- قاطیکردن اعتبارسنجی با پاکسازی: این دو کار متفاوت دارند. اگر فقط sanitize کنید، داده معتبر نمیشود؛ اگر فقط validate کنید، داده خطرناک میماند.
- اعتبارسنجی نکردن اعداد اعشاری: در فروشگاه، قیمتها و مقادیر باید اعشاری باشند، اما نه با دقت بینهایت. تعیین دقت (مثلاً ۲ رقم اعشار) و اعتبارسنجی آن، از خطاهای انبار و مالی جلوگیری میکند.
- عدم توجه به اعداد فارسی: کاربر فارسی ممکن است عدد را با حروف فارسی وارد کند. تابع اعتبارسنجی باید قبل از اجرا، اعداد فارسی را به انگلیسی تبدیل کند.
- پیام خطای عمومی: پیام «فرم نامعتبر است» کاربر را سردرگم میکند. پیام باید مشخص کند کدام فیلد و چه مشکلی دارد.
- نبود اعتبارسنجی در ورودیهای API: اگر endpoint REST API دارید و args آن را تعریف نکردهاید، دادههای نامعتبر میتوانند وارد دیتابیس شوند. راهنمای کامل در ساخت API اختصاصی.
یک اشتباه کمتکرار اما گرانقیمت: اعتبارسنجی با الگوی regex که فقط برای انگلیسی طراحی شده. مثلاً الگوی ایمیل که ali@example.com را میپذیرد اما علی@example.com را رد میکند. در سایتهای فارسی، کاربر ممکن است ایمیل فارسی وارد کند؛ اگر اعتبارسنجی شما آن را رد کند، پیام خطای اشتباه میگیرد. توصیه من: از is_email وردپرس استفاده کنید که استانداردهای بینالمللی را پوشش میدهد.
دید مهندسی
از منظر مهندسی، اعتبارسنجی داده در وردپرس یک تصمیم معماری پیوسته است، نه یک تابع که به فرمها اضافه شود. سه لایه را در پروژههای حرفهای همیشه مرور میکنم. لایه اول، تفکیک Validation Layer بهعنوان یک لایه مستقل: در پروژههای بزرگ، اعتبارسنجی نباید درون توابع پردازش فرم باشد. باید یک لایه جداگانه داشته باشد که با یک API واضح، داده را بررسی کند. مثلاً کلاس My_Plugin_Validator با متدهای validate_email، validate_mobile، validate_order_data. این ساختار، هم تستپذیری را افزایش میدهد و هم در تغییر قواعد، یک نقطه واحد تغییر میکند. تفصیل این الگو در اصول کدنویسی تمیز آوردهام. لایه دوم، اعتبارسنجی بهعنوان بخشی از Domain Model: در سیستمهای پیچیده، هر موجودیت داده (User، Order، Product) باید قواعد اعتبارسنجی خودش را داشته باشد. مثلاً یک Order نمیتواند بدون آدرس معتبر ذخیره شود، و یک Product نمیتواند قیمت منفی داشته باشد. این لایه، در معماریهای Domain-Driven Design (DDD) استاندارد است و در پروژههای وردپرسی بزرگ، اثر مستقیم روی صحت داده دارد. لایه سوم، پایش مستمر داده ذخیرهشده: اعتبارسنجی در ورودی، جلوی دادههای نامعتبر آینده را میگیرد؛ اما دادههای نامعتبر گذشته، همچنان در دیتابیس باقی میمانند. در پروژههای بلندمدت، هر شش ماه یک بازبینی داده انجام میدهم: پرسوجویی که دادههای خارج از قاعده را مییابد و آنها را پاکسازی یا اصلاح میکند. مسیر این نوع پایش در پاکسازی دیتابیس وردپرس آمده است.
یک نکته تکمیلی برای تیمهای فنی: در پروژههای بزرگ، اعتبارسنجی را بهعنوان بخشی از CI اجرا کنید. مثلاً تستهای خودکار که با دادههای معتبر و نامعتبر، توابع اعتبارسنجی را بررسی میکنند. این کار، جلوی regression در آینده را میگیرد. مسیر کامل در تست و دیباگ پروژههای وردپرس و CI/CD در وردپرس آمده است. تجربهام این است که در پروژهای با اعتبارسنجی مستقل و تستشده، شکایتهای «داده اشتباه ذخیره شد»، در ماه سوم به صفر میرسد. و این صفر، تفاوت بین یک تیم با اعتبارسنجی جدی و یک تیم بدون آن است.
جمعبندی
اعتبارسنجی دادهها در وردپرس، در سه لایه خلاصه میشود: لایه مرورگر برای تجربه کاربری، لایه سرور برای امنیت و صحت واقعی، و لایه منطق کسبوکار برای بررسی وابستگیها. سه اصل در پایان تاکید میکنم: اول، اعتبارسنجی را از پاکسازی جدا نگه دارید؛ این دو کار متفاوت دارند. دوم، هرگز به اعتبارسنجی مرورگر اعتماد نکنید؛ لایه واقعی، سرور است. سوم، دادههای محلی، نیاز به اعتبارسنجی محلی دارند؛ الگوی جهانی همیشه جواب نمیدهد.
اگر همین امروز در حال کار روی یک پروژه وردپرسی هستید، پیشنهاد عملی من سه گام است: ابتدا فرمهای فعلی سایت خود را فهرست کنید و ببینید کدامها اعتبارسنجی سرور دارند و کدامها فقط به HTML5 تکیه کردهاند؛ سپس یک لایه اعتبارسنجی مستقل برای پروژه خود طراحی کنید که قواعد کسبوکار را از توابع پردازش فرم جدا کند؛ و در پایان، دادههای فعلی دیتابیس را برای قاعدههای خاص (کد ملی، شماره موبایل، ایمیل) بررسی کنید و ببینید چه میزان داده نامعتبر ذخیره شده. اگر در هر مرحلهای گیر کردید یا تجربهای از یک حادثه ناشی از اعتبارسنجی ناکافی دارید، در دیدگاهها بنویسید. تجربه شما از یک پروژه با اعتبارسنجی جدی یا یک حادثه ناشی از نبود آن، برای توسعهدهنده بعدی که در همین نقطه ایستاده، ارزشمندترین راهنماست. ✅