ویژگی تصویر

تابع strncmp() در PHP

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

تابع strncmp() در PHP برای مقایسه بایت به بایتِ دو رشته تا حداکثر تعداد مشخصی از کاراکترها استفاده می‌شود. این تابع binary-safe است و به صورت حساس به حروف (case-sensitive) عمل می‌کند. برای مقایسه کامل رشته‌ها یا بررسی پیشوندها (prefix) کاربرد بسیار معمولی دارد.

امضای تابع

تعریف تابع به شکل زیر است:

int strncmp ( string $str1 , string $str2 , int $len )

سه آرگومان: رشته اول، رشته دوم و تعداد بایت/کاراکترهایی که باید مقایسه شوند (len).

مقدار بازگشتی

مقدار بازگشتیمعنی
< 0str1 کوچکتر از str2 در مقایسه‌ی اولین len بایت
0اولین len بایت هر دو رشته برابر هستند
> 0str1 بزرگتر از str2 در همان محدوده

نکات کلیدی

  • عملیات byte-wise است؛ بنابراین در رشته‌های UTF-8 ممکن است کاراکترهای چندبایتی به درستی تقسیم نشوند.
  • حساس به حروف است؛ برای مقایسه بدون حساسیت از strncasecmp() استفاده کنید.
  • برای مقایسه رمزنگاری‌ای (محافظت در برابر timing attack) از hash_equals() استفاده کنید، نه strncmp.
  • اگر len برابر صفر باشد، تابع مقدار 0 برمی‌گرداند (هیچ بایتی مقایسه نشده است).

مثال‌های کاربردی

1. بررسی پیشوند (prefix)

<?php
$haystack = 'applepie';
$needle = 'app';

if (strncmp($haystack, $needle, strlen($needle)) === 0) {
    echo "پیشوند مطابقت دارد";
} else {
    echo "مطابقت ندارد";
}
?>

در این مثال با استفاده از strncmp و طول needle بررسی می‌کنیم که آیا رشته اول با needle شروع می‌شود یا خیر. استفاده از === 0 ضروری است تا از برابری دقیق عددی اطمینان حاصل شود.

2. مقایسه جزئی (اولین n کاراکتر)

<?php
$a = "HelloWorld";
$b = "HelloMars";

$result = strncmp($a, $b, 5); // فقط 5 کاراکتر اول مقایسه می‌شود

if ($result === 0) {
    echo "پنج کاراکتر اول برابرند";
} elseif ($result < 0) {
    echo "a کمتر است";
} else {
    echo "a بزرگتر است";
}
?>

این کد اولین 5 کاراکتر را مقایسه می‌کند و نتیجه را براساس مقدار عددی بازگشتی تفسیر می‌کند.

مقایسه با توابع دیگر و انتخاب درست

  • strcmp/strncmp: بایت به بایت و حساس به حروف.
  • strncasecmp: مشابه strncmp اما حساسیت به حروف را حذف می‌کند (case-insensitive).
  • substr_compare: امکانات بیشتری مانند مشخص کردن offset و case-insensitive را فراهم می‌کند.
  • strstr/strpos: برای پیدا کردن وجود یک زیررشته (یا موقعیت) کاربردی‌تر و در برخی موارد سریع‌ترند؛ اما برای تعیین ترتیب lexicographic مناسب نیستند.

جایگزین ایمن برای مقایسه‌های رمزنگاری

<?php
// مقایسه کلیدها یا توکن‌ها — نبايد از strncmp برای مقایسه امن استفاده کرد
$a = hash('sha256', 'secret1');
$b = hash('sha256', 'secret2');

if (hash_equals($a, $b)) {
    echo "برابرند";
} else {
    echo "مخالفند";
}
?>

برای مقایسه مقادیر هش یا توکن‌ها که نیاز به مقاومت در برابر حملات زمان‌بندی دارند، از hash_equals استفاده کنید. strncmp به‌دلیل رفتار زمانی وابسته به محتوای رشته، مناسب حملات timing نیست.

ملاحظات مربوط به Unicode و UTF-8

از آنجا که strncmp بر پایه بایت عمل می‌کند، در کار با رشته‌های چندبایتی (مانند UTF-8) ممکن است مرزهای کاراکتر شکسته شوند و نتیجه‌ی غیرمنتظره بدهد. برای کار ایمن با متن‌های UTF-8 از توابع multibyte (mb_*) استفاده کنید یا پیش از مقایسه از mb_substr استفاده کنید تا کاراکترها حفظ شوند.

<?php
// نسخه‌ای سازگار با UTF-8 برای بررسی پیشوند
$haystack = 'سلامدنیا';
$needle = 'سلام';

$len = mb_strlen($needle, 'UTF-8');
if (mb_substr($haystack, 0, $len, 'UTF-8') === $needle) {
    echo "پیشوند UTF-8 مطابقت دارد";
} else {
    echo "مطابقت ندارد";
}
?>

در این نمونه از mb_substr و mb_strlen برای برش و مقایسه کاراکتر-محور استفاده شده است تا اشکال ناشی از بایت‌شکنی در UTF-8 رخ ندهد. هرچند این روش نسبت به strncmp هزینه پردازشی بیشتری دارد اما برای متن‌های چندبایتی صحیح‌تر است.

نمونه بهینه برای بررسی پیشوند (میان کارایی و درستی)

اگر رشته‌ها ASCII باشند و کارایی مهم باشد، استفاده از strncmp بهترین انتخاب است. اما برای UTF-8 یا رشته‌های کاراکتر-محور، از mb_* یا substr_compare با پارامترهای مناسب استفاده کنید.

<?php
// استفاده از substr_compare برای بررسی پیشوند (حساس یا غیرحساس به حروف)
$haystack = 'ExampleString';
$needle = 'example';

if (substr_compare($haystack, $needle, 0, strlen($needle), true) === 0) {
    echo "پیشوند بدون حساسیت به حروف برابر است";
} else {
    echo "مطابقت ندارد";
}
?>

substr_compare این امکان را می‌دهد که از offset استفاده کنید و همچنین با پارامتر آخر، مقایسه را case-insensitive کنید. برای رشته‌های ASCII این روش راحت و کاربردی است.

جمع‌بندی و توصیه‌های عملی

  • از strncmp برای مقایسه سریع بایت‌به‌بایت تا n کاراکتر استفاده کنید، مخصوصاً برای رشته‌های ASCII یا داده‌های باینری.
  • برای مقایسه‌ای بدون حساسیت به حروف از strncasecmp بهره ببرید.
  • در کار با UTF-8 و متن‌های چندبایتی از توابع mb_* یا راهکارهای مبتنی بر کاراکتر استفاده کنید.
  • برای مقایسه امنِ توکن‌ها یا هش‌ها از hash_equals استفاده کنید تا در برابر حملات timing مقاوم باشید.
  • همیشه در بررسی پیشوند از === 0 استفاده کنید تا اشتباهات ناشی از تبدیل نوع پیش نیاید.

با رعایت این نکات می‌توانید از strncmp به‌درستی و با کارایی مناسب در پروژه‌های PHP استفاده کنید و از تله‌های مربوط به کاراکترهای چندبایتی و امنیت جلوگیری نمایید.

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

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