ویژگی تصویر

تابع serialize() در PHP

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

تابع serialize() در PHP داده‌های پیچیده مانند آرایه‌ها و اشیاء را به یک رشتهٔ قابل ذخیره یا انتقال تبدیل می‌کند. این رشته قالب مخصوص PHP دارد و با تابع مقابل، یعنی unserialize()، قابل بازگردانی به مقدار اولیه است. کاربردهای رایج شامل ذخیره در پایگاه‌داده، کش، فایل و انتقال بین سرویس‌ها است.

چرا و چه وقت از serialize استفاده کنیم؟

  • ذخیرهٔ ساختار دادهٔ پیچیده در یک ستون متن در دیتابیس.
  • کَش‌کردن (caching) آرایه‌ها و اشیاء در فایل یا مموری.
  • ذخیرهٔ نشست‌ها (session) که به صورت پیش‌فرض از سریالایز استفاده می‌کنند.
  • انتقال داده بین پروسس‌ها یا APIهای درون برنامه‌ای که فقط رشته دریافت می‌کنند.

قالب خروجی serialize

قالب سریالایز پی‌اچ‌پی به صورت متن است و اجزای مختلف را با شناسهٔ نوع و طول نشان می‌دهد. مثال‌هایی از قالب‌ها:

  • s:length:”string”; — رشته
  • i:value; — عدد صحیح
  • d:value; — عدد اعشاری
  • b:0; یا b:1; — بولین
  • a:length:{…} — آرایه
  • O:length:”ClassName”:members:{…} — شیء

مثال ساده: آرایه و بازگردانی

$arr = ['name' => 'Ali', 'age' => 30, 'tags' => ['php', 'serialize']];
$serialized = serialize($arr);
$unserialized = unserialize($serialized);
var_dump($serialized, $unserialized);

در این مثال ابتدا آرایه‌ای را سریالایز می‌کنیم که خروجی آن رشته‌ای مطابق قالب PHP خواهد بود. سپس با unserialize مقدار اصلی را بازمی‌سازیم. توجه داشته باشید که unserialize به کلاس‌ها و تعریف‌های نوع هنگام بازسازی اشیاء نیاز دارد.

کار با اشیاء و متدهای جادویی

برای اشیاء، PHP متدهای ویژه‌ای را صدا می‌زند:

  • __sleep() — قبل از سریالایز برای مشخص کردن چه پروپرتی‌هایی ذخیره شوند.
  • __wakeup() — بعد از unserialize برای بازسازی منابع مانند اتصال دیتابیس.
  • __serialize() و __unserialize() — از PHP 7.4 جایگزین روش قدیمی‌تر Serializable شده‌اند و کنترل دقیق‌تری می‌دهند.
class User {
  private $name;
  private $conn; // resource

  public function __construct($name) {
    $this->name = $name;
    $this->conn = null;
  }

  public function __serialize(): array {
    return ['name' => $this->name];
  }

  public function __unserialize(array $data): void {
    $this->name = $data['name'];
    // می‌توان اتصال دیتابیس را در اینجا دوباره برقرار کرد
    $this->conn = null;
  }
}

در این کد، __serialize اطلاعات قابل ذخیره را بازمی‌گرداند و __unserialize هنگام بازسازی، داده را دریافت می‌کند. این روش امن‌تر و خواناتر از Serializable است.

مسائل امنیتی: خطرات unserialize

unserialize می‌تواند در مقابل Object Injection آسیب‌پذیر باشد؛ حمله‌ای که با ارسال دادهٔ سریالایزدِ مخرب، کد دلخواه را از طریق متدهای جادویی مانند __wakeup یا متدهای کلاس‌ها اجرا می‌کند. برای کاهش ریسک:

  • هیچگاه دادهٔ غیرقابل‌اعتماد را مستقیم به unserialize ندهید.
  • از گزینهٔ allowed_classes در unserialize استفاده کنید: unserialize($data, [‘allowed_classes’ => false]) برای جلوگیری از بازسازی اشیاء.
  • در صورتی که نیاز به بازسازی اشیاء دارید، فقط کلاس‌های مورد اعتماد را اجازه دهید.
$safe = unserialize($input, ['allowed_classes' => false]);

با این پارامتر، اشیاء سریالایز شده تبدیل به آرایه یا خطا نخواهند شد و فقط ساختارهای اسکالر و آرایه‌ای بازسازی می‌شوند. این یکی از ساده‌ترین روش‌های افزایش امنیت است.

مقایسه با json_encode و دیگر گزینه‌ها

ویژگیserialize()json_encode()
قابلیت ذخیره اشیاءبله (با اطلاعات کلاس)نه (فقط دادهٔ ساختاری)
قابل حمل بین زبان‌هاخیر (فرمت PHP خاص)بله
حجم خروجیمعمولاً بیشترمعمولاً کمتر و فشرده‌تر
امنیتنیاز به احتیاط بیشترامن‌تر برای دادهٔ غیرقابل‌اعتماد

برای کارایی بهتر و کاهش حجم گاهی از افزونه‌هایی مثل igbinary استفاده می‌شود که فرمت باینری فشرده‌تری نسبت به serialize تولید می‌کند.

نکات فنی و بهترین شیوه‌ها

  • اگر کلاس‌ها هنگام unserialize در دسترس نباشند، PHP خطا می‌دهد یا اشیاء را به کلاس __PHP_Incomplete_Class تبدیل می‌کند.
  • برای تشخیص شکست unserialize از مقایسه خاص استفاده کنید، زیرا تابع ممکن است مقدار boolean false را واقعاً بازگرداند: بررسی کنید که ورودی مربوطه دقیقاً با رشتهٔ ‘b:0;’ مطابقت نداشته باشد یا از بررسی نوع استفاده نمایید.
  • برای داده‌های بین‌زبانی یا APIها از json_encode/json_decode استفاده کنید مگر آنکه نیاز صریح به بازسازی اشیاء PHP داشته باشید.
  • در برنامه‌های حساس، همیشه allowed_classes را مشخص کنید یا از فرمت‌های امن‌تر بهره ببرید.

مثال: استفادهٔ ایمن در عمل

// دریافت داده از منبع خارجی (مثلاً header یا POST)
$input = $_POST['payload'] ?? '';

$data = null;
if ($input !== '') {
  $data = @unserialize($input, ['allowed_classes' => false]);
  if ($data === false && $input !== 'b:0;') {
    // دادهٔ نامعتبر یا حمله — لاگ کرده و رد کنید
    error_log('Invalid serialized payload');
    $data = null;
  }
}

در این نمونه ابتدا unserialize را با allowed_classes غیرفعال صدا می‌زنیم تا اشیاء بازسازی نشوند. سپس با چک دقیق بررسی می‌کنیم که false به‌خاطر خطا نیست (چون b:0; می‌تواند مقدار false واقعی را تولید کند).

جمع‌بندی

تابع serialize() ابزار قدرتمندی برای ذخیره‌سازی و انتقال ساختارهای پیچیده در PHP است، اما به دلیل فرمت خاص و خطرات امنیتی مرتبط باید با احتیاط و آگاهی استفاده شود. در مواردی که ارتباط بین زبان‌ها یا امنیت مهم است، json_encode گزینهٔ مناسب‌تری خواهد بود؛ و در کاربردهای داخلی که نیاز به بازسازی اشیاء دارید، از allowed_classes و متدهای جدید __serialize/__unserialize استفاده کنید. افزونه‌های فشرده‌ساز مانند igbinary نیز برای صرفه‌جویی در حافظه و زمان کاربردی‌اند.

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

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