ویژگی تصویر

تابع preg_match_all() در PHP

  /  PHP   /  تابع preg_match_all() در PHP
بنر تبلیغاتی الف
آموزش PHP

تابع preg_match_all() یکی از ابزارهای قدرتمند PHP برای جستجو و استخراج چندگانه الگوها (regular expressions) در یک رشته است. این تابع بر پایهٔ موتور PCRE (Perl Compatible Regular Expressions) کار می‌کند و امکان گرفتن تمامی تطابق‌ها، گروه‌های گروهبندی‌شده و اطلاعات مربوط به موقعیت آن‌ها را فراهم می‌سازد.

امضای تابع و مقدار بازگشتی

امضای تابع به صورت زیر است:

int preg_match_all(string $pattern, string $subject, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]])

تابع تعداد تطابق‌های کامل (matches) را برمی‌گرداند یا در صورت خطا مقدار false را بازمی‌گرداند. آرگومان $matches به صورت مرجع پر می‌شود.

ساختار آرایهٔ خروجی و Flags مهم

چند فلگ پرکاربرد که ساختار خروجی را تعیین می‌کنند:

  • PREG_PATTERN_ORDER (پیش‌فرض): آرایه‌ای با ایندکس‌های 0، 1، … که 0 شامل تطابق‌های کامل و 1 شامل گروه اول برای تمام تطابق‌ها است.
  • PREG_SET_ORDER: هر عنصر آرایه یک تطابق کامل است و داخلش ایندکس‌های 0، 1، … برای گروه‌ها وجود دارند.
  • PREG_OFFSET_CAPTURE: به جای رشتهٔ ساده، هر مقدار به صورت آرایهٔ [match, offset] برگردانده می‌شود که offset موقعیت شروع تطابق در $subject را نشان می‌دهد.
  • PREG_UNMATCHED_AS_NULL (از PHP 7.2): گروه‌هایی که تطابق نداشته‌اند به جای رشتهٔ خالی null می‌شوند.

مثال پایه — استخراج ایمیل‌ها

$text = "Contact: alice@example.com, bob@example.org.";
$pattern = '/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}/';
$result = preg_match_all($pattern, $text, $matches);

var_dump($result);
var_dump($matches);

در این مثال تابع، تعداد ایمیل‌های پیدا شده را در $result قرار می‌دهد و آرایهٔ $matches شامل تمام ایمیل‌ها می‌شود. الگوی ساده بالا برای مثال است؛ در عمل می‌توانید از الگوهای دقیق‌تر برای ایمیل استفاده کنید.

مثال با گروهبندی و PREG_SET_ORDER

$html = 'Page 1Page 2';
$pattern = '/([^<]+)/i';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
    echo "url: {$m[1]}, text: {$m[2]}n";
}

این کد همهٔ تگ‌های <a> با href را پیدا می‌کند. با استفاده از PREG_SET_ORDER، هر تطابق به شکل یک رکورد مستقل در $matches آمده و می‌توانیم به راحتی آدرس و متن لینک را استخراج کنیم.

مثال با PREG_OFFSET_CAPTURE

$subject = "one two one";
$pattern = '/one/';
preg_match_all($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
var_dump($matches);

با استفاده از PREG_OFFSET_CAPTURE هر تطابق به صورت [‘one’, offset] برگردانده می‌شود که offset موقعیتی است که تطابق از آن آغاز شده. این حالت وقتی مفید است که لازم باشد جایگاه دقیق تطابق‌ها را بدانیم.

نکات عملی و بهترین روش‌ها

  • اگر فقط می‌خواهید وجود الگو را بررسی کنید، از preg_match() استفاده کنید — سریع‌تر و سبک‌تر است.
  • برای رشته‌های یونیکد حتماً از فلگ u در الگو استفاده کنید (مثلاً ‘/pattern/u’) تا کلاس‌های p{L} یا متغیرهای یونیکد صحیح کار کنند.
  • از الگوهای خاص و محدود به جای .* گسترده استفاده کنید تا از Backtracking زیاد جلوگیری شود.
  • برای جلوگیری از آسیب‌پذیری ReDoS از کوانتفایرهای تسخیرناپذیر (possessive quantifiers) یا گروه‌های اتمیک استفاده کنید: (?>…) و +/
  • در هنگام کار با ورودی‌های کاربر، الگوها را بررسی یا محدود کنید تا محتوای مخرب نتواند باعث مصرف زیاد منابع شود.

مثال جلوگیری از Catastrophic Backtracking

// آسیب‌پذیر:
$pattern_bad = '/^(.*a){10}/';

// امن‌تر با possessive quantifier یا گروه اتمیک:
$pattern_safe = '/^(?>.*)a{10}/'; // یا استفاده از .*+ (possessive) اگر قابل‌پشتیبانی باشد

الگوی اول می‌تواند باعث backtracking شدید شود. الگوهای اتمیک یا possessive جلوی بازگشت‌های متعدد را می‌گیرند و خطر حملات ReDoS را کاهش می‌دهند.

خطایابی و بررسی خطاها

در صورت بروز خطا، preg_match_all مقدار false برمی‌گرداند. برای تشخیص نوع خطا می‌توانید از تابع preg_last_error() استفاده کنید که مقادیری مانند PREG_NO_ERROR، PREG_INTERNAL_ERROR، PREG_BACKTRACK_LIMIT_ERROR، PREG_RECURSION_LIMIT_ERROR، PREG_BAD_UTF8_ERROR و PREG_BAD_UTF8_OFFSET_ERROR را بازمی‌گرداند.

جدول خلاصهٔ فلگ‌ها

فلگتوضیح
PREG_PATTERN_ORDERپیش‌فرض — آرایه بر اساس گروه‌های الگو مرتب می‌شود
PREG_SET_ORDERهر عنصر آرایه یک تطابق کامل است
PREG_OFFSET_CAPTUREبازگرداندن موقعیت شروع هر تطابق
PREG_UNMATCHED_AS_NULLگروه‌های بدون تطابق به صورت null بازگردانده می‌شوند

موارد کاربرد واقعی

  • استخراج لینک‌ها، ایمیل‌ها یا شماره‌ها از متن
  • آنالیز لاگ‌ها و گرفتن فیلدهای تکرارشونده
  • پاک‌سازی و اعتبارسنجی ورودی‌ها قبل از ذخیرهٔ پایگاه‌داده
  • جایگزینی‌های پیچیده در ترکیب با preg_replace_callback

خلاصهٔ عملی

preg_match_all() برای گرفتن همهٔ تطابق‌های یک الگو بسیار مناسب است، اما باید با احتیاط و دانش نسبت به ساختار الگوها از آن استفاده شود تا هم کارایی حفظ شود و هم از مشکلاتی مانند ReDoS جلوگیری شود. با درک فلگ‌ها (مثل PREG_SET_ORDER و PREG_OFFSET_CAPTURE) و مدیریت خطاها می‌توانید از این تابع در پروژه‌های واقعی به شکل ایمن و بهینه بهره ببرید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: