ویژگی تصویر

تابع xml_set_notation_decl_handler() در PHP

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

تابع xml_set_notation_decl_handler() یکی از توابع خانواده XML Parser در PHP است که به شما امکان می‌دهد هنگامی که مفسر (Expat) با یک اعلان NOTATION در DTD یک سند XML مواجه می‌شود، یک callback سفارشی اجرا شود. این قابلیت برای پردازش اعلان‌های نوع داده‌های غیر-XML (مانند تصاویر یا داده‌های باینری) یا ثبت متادیتاهای DTD مفید است.

چرا اعلان‌های NOTATION مهم‌اند؟

در DTD، اعلان‌های NOTATION برای توصیف فرمت یا نوع منابع خارجی به‌کار می‌روند. نمونه‌ای از اعلان NOTATION:

<!NOTATION gif SYSTEM "image/gif">

این اعلان می‌گوید که نشانه‌ای به نام gif وجود دارد و نوع آن با یک شناسه سیستم (system identifier) معرفی شده است. پردازشگرهای مبتنی بر رویداد مانند Expat این اعلان‌ها را به رویدادهایی تبدیل می‌کنند که می‌توان با xml_set_notation_decl_handler آن‌ها را مدیریت کرد.

امضاء تابع و پارامترها

تابعشرح
bool xml_set_notation_decl_handler(resource $parser, callable $handler)ثبت handler برای رویداد اعلان NOTATION؛ بازمی‌گرداند true در صورت موفقیت.

پارامترهای callback که Expat به آن می‌فرستد معمولاً به صورت زیر هستند:

  • $parser — منبع (resource) parser
  • $notationName — نام اعلان NOTATION
  • $base — مقدار base (در صورت استفاده از base URI)
  • $systemId — شناسه سیستم (system identifier)
  • $publicId — شناسه عمومی (public identifier)

مثال ساده: ثبت و نمایش اعلان‌های NOTATION

<?php
// ساخت یک XML parser
$parser = xml_parser_create();

// آرایه‌ای برای نگهداری اعلان‌ها
$notations = [];

// ثبت handler
xml_set_notation_decl_handler($parser, function($parser, $name, $base, $systemId, $publicId) use (&$notations) {
    $notations[] = [
        'name' => $name,
        'base' => $base,
        'systemId' => $systemId,
        'publicId' => $publicId,
    ];
});

// خواندن یک فایل XML با DTD (مثال)
$xml = <<<XML
<!DOCTYPE doc [
  
  
]>
<content/>
XML;

// پارس کردن در حالت تک‌باری
if (!xml_parse($parser, $xml, true)) {
    die(sprintf("XML Error: %s at line %dn",
        xml_error_string(xml_get_error_code($parser)),
        xml_get_current_line_number($parser)));
}

// نمایش اعلان‌ها
print_r($notations);

// آزادسازی منابع
xml_parser_free($parser);
?>

در این مثال: ابتدا یک parser ساخته‌ایم، سپس با استفاده از یک closure اعلان‌ها را در آرایه‌ای ذخیره می‌کنیم. هنگام parse کردن رشته XML، هر اعلان NOTATION که در DTD وجود داشته باشد به callback ارسال می‌شود و ما آن را ثبت می‌کنیم. در نهایت، آرایهٔ $notations چاپ می‌شود و اطلاعات اعلان‌ها را می‌بینیم.

شرح بیشتر دربارهٔ کد

  • استفاده از closure با use (&$notations) به ما اجازه می‌دهد داده‌ها را به‌شکل ایمن خارج از callback جمع‌آوری کنیم.
  • تابع xml_parse باید با پارامتر سوم true فراخوانی شود تا پایان سند را علامت بزند.
  • خطاها با xml_error_string و xml_get_current_line_number گزارش می‌شوند که برای تشخیص مشکلات سند مفید است.

نمونه کاربرد واقعی: ثبت و تبدیل اعلان‌ها به JSON

<?php
$parser = xml_parser_create();
$notations = [];

xml_set_notation_decl_handler($parser, function($parser, $name, $base, $systemId, $publicId) use (&$notations) {
    $notations[$name] = [
        'base' => $base,
        'systemId' => $systemId,
        'publicId' => $publicId,
    ];
});

$xml = file_get_contents('example_with_dtd.xml');
if (!xml_parse($parser, $xml, true)) {
    throw new Exception(xml_error_string(xml_get_error_code($parser)));
}

file_put_contents('notations.json', json_encode($notations, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
xml_parser_free($parser);
?>

در این سناریو، اعلان‌ها به‌صورت کلید-مقدار بر اساس نامشان ذخیره می‌شوند و سپس در قالب JSON خروجی گرفته می‌شوند — کاربردی برای ابزارهای میانی که می‌خواهند متادیتای DTD را استخراج و به سیستم‌های دیگر منتقل کنند.

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

  • xml_set_notation_decl_handler تنها با API مبتنی بر Expat کار می‌کند؛ اگر از DOMDocument یا SimpleXML استفاده می‌کنید، این رویدادها به‌صورت مستقیم در دسترس نیستند.
  • اگر سند XML بزرگ یا جریان‌محور است، استفاده از این روال رویدادمحور (SAX-like) مناسب و کم‌حافظه است.
  • مراقب آسیب‌پذیری‌های XXE باشید؛ وقتی DTD و شناسه‌های خارجی را پردازش می‌کنید، ممکن است درخواست‌های خارجی انجام شود. در محیط‌های ناامن، پردازش DTD خارجی را غیرفعال کنید یا از parserهای امن استفاده کنید.
  • همیشه xml_parser_free را برای آزادسازی منابع فراخوانی کنید تا نشت resource رخ ندهد.
  • مقدار بازگشتی xml_set_notation_decl_handler را چک کنید تا از موفقیت ثبت handler مطمئن شوید.

خطاها و محدودیت‌ها

در موارد زیر ممکن است تابع کار نکند یا محدودیت‌هایی وجود داشته باشد:

  • اگر افزونه XML (Expat) در PHP نصب یا فعال نباشد، توابع xml_* قابل استفاده نیستند.
  • بسیاری از برنامه‌های کاربردی مدرن ترجیح می‌دهند از DOM یا libxml استفاده کنند — که ممکن است دسترسی مستقیم به اعلان‌های DTD را به همان شکل فراهم نکند.
  • قابل توجه: xml_set_notation_decl_handler فقط اعلان‌های NOTATION را پوشش می‌دهد؛ برای اعلان‌های دیگر مانند ENTITY باید از توابع مربوطه مثل xml_set_unparsed_entity_decl_handler استفاده کنید.

جمع‌بندی

xml_set_notation_decl_handler() ابزاری ارزشمند در موقعیت‌هایی است که نیاز دارید اعلان‌های NOTATION موجود در DTD را در جریان پردازش رویدادی XML (Expat) دریافت و مدیریت کنید. این تابع برای استخراج متادیتا، ثبت فرمت‌ها یا آماده‌سازی داده برای پردازش‌های بعدی مفید است. ولی باید محدودیت‌ها و ریسک‌های امنیتی را در نظر بگیرید و در پروژه‌های جدید بررسی کنید که آیا رویکرد مبتنی بر DOM یا ابزارهای دیگر مناسب‌تر نیست.

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

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