مسیر شما: سبز دانش » برنامه نویسی » PHP » رفع خطای Headers Already Sent در PHP و وردپرس + دلیل و چکلیست
خطای headers already sent زمانی رخ میدهد که PHP بخواهد Headerها را بعد از ارسال بخشی از خروجی تغییر دهد. این خروجی ممکن است بهخاطر HTML، فاصلهٔ اضافی، BOM یا حتی یک Warning ایجاد شده باشد. در اکثر موارد رفع این خطا ساده است. متن خطا معمولاً محل آغاز مشکل را به ما بیانگر است و میتوانیم آن را تحلیل و اصلاح کنیم.
در این آموزش ابتدا بهطور کوتاه تحلیل میکنیم که خطای Caot modify header information – headers already sent در PHP یعنی چه و چرا اتفاق میافتد. سپس یاد میگیریم که چطور از روی متن خطا دلیل و محل اتفاق را متوجه شویم. در نهایت راهنماییهایی برای رفع این خطای معروف را در کدهای PHP و وردپرس بهصورت گامبهگام ارزیابی میکنیم.
فهرست محتوای آموزش
دلیل این خطا به ساختار پیامهای HTTP برمیگردد. اما برای درک اینکه چرا اتفاق میافتد (حداقل برای این آموزش) نیاز نیست که وارد شرحات پیچیده شویم. فقط در همین حد بدانید که هر پاسخ HTTP را میتوان بهصورت دو بخش در نظر گرفت:
میتوانیم این مبحث را شبیه به ارسال یک بسته پستی در نظر بگیریم. بسته پستی معادل با Body و آدرس و مشخصاتی که روی بسته مینویسیم معادل Header هستند.
قبل از اینکه بسته را تحویل اداره پست بدهیم، میتوانیم آدرس مبدأ و مقصد و سایر مشخصات را بنویسیم یا اصلاح کنیم؛ اما وقتی بسته را تحویل دادیم تغییر آنها تقریباً سخت و نشدنی است.
در HTTP و فضای وب نیز تقریباً همین اتفاق میافتد. Header باید قبل از خروجی (Body) ارسال شود. بنابراین اگر برنامه ما ابتدا یک متن، کد HTML یا حتی یک پیغام خطا را به خروجی بفرستد و بعدش بخواهیم Header را دستکاری کنیم، با خطای Caot modify header information مواجه میشویم.
دلایل مختلفی میتواند وجود داشته باشد. مهمترین علتها را در جدول زیر نوشتهام:
در پرسشوپاسخهای مستندات PHP (اینجا) صراحتاً گفتهاند که توابعی مثل header()، setcookie() و توابع سشن در PHP باید پیش از هر خروجی اجرا شوند.
برای مثال، قطعه کد زیر مشکل دارد:
<?php
echo "Hello";
header("Location: dashboard.php");
exit;چون ابتدا echo اجرا شده (خروجی دادهایم) و بعد تلاش کردیم که Header مربوط به ریدایرکت (انتقال صفحه) را ارسال کنیم.
قانونش خیلی ساده است: قبل از ارسال Header نباید هیچ خروجیای تولید شده باشد.
فرض کنید سایت ما خطای زیر را میدهد:
Warning: Caot modify header information - headers already sent by
(output started at /home/site/public_html/functions.php:12)
in /home/site/public_html/panel.php on line 45
در نگاه اول، مشابه ارزیابی سایر خطاهای PHP ممکن است فایل panel.php و خط 45 را باعث خطا بدانیم. اما اگر دقت کنید، در این خطا دو محل داریم:
یکی:
output started at .../functions.php:12
و دیگری:
in .../panel.php on line 45
محلی که با output started at آشکار شده، معمولاً جایی است که خروجی برای اولین بار ایجاد شده است. بنابراین احتمالاً مشکل اصلی در همینجاست. در این مثال، یعنی فایل functions.php و حوالی خط 12.
یعنی کدهای ما در functions.php:12 حداقل یک کاراکتر خروجی (در body) ایجاد کرده اما اکنون که اجرای کدها به panel.php:45 رسیده، تلاش میکند که Header نوینی ارسال کند یا دگرگونیهای در آنها بدهد.
گاهی مشکل اصلی آن چیزی نیست که در آخرین Warning میبینیم! مثلاً ممکن است ابتدا خطایی مربوط به تعریف نشدن یک متغیر داشته باشیم و سپس خطای Headers already sent گرفته باشیم.
Warning: Undefined variable $user ...
Warning: Caot modify header information - headers already sent by ...
در این حالت باید Warning اول را نیز جدی بگیریم؛ چون اگر نمایش خطا فعال باشد، همان متن خطا نیز میتواند یک خروجی تولید کند و باعث مشکل شود. (بیشتر بخوانید: مدیریت گزارش خطا در PHP)
مهم: قبل از هر گونه تغییر، از سایت و کدهای خود بکاپ تهیه کنید.
حالا که متوجه شدیم این مشکل چطور ایجاد میشود، رفع آن خیلی سادهتر است.
ابتدا فایلی را که در output started at روشن شده باز کنید. اطراف همان خطی که مشخص کرده را ارزیابی کنید. معمولاً یکی از مواردی که در جدول بالا نوشتهام را میبینید. با حذف یا اصلاح آن، مشکل رفع میشود.
در ادامهٔ این بخش، ۳ مورد از پرتکرارترین دلایل خطا را مطرح میکنم و شیوه رفع آنها را تبیین میدهم.
اگر از توابعی مثل header() یا session_start() در برنامهمان استفاده میکنیم، باید توجه داشته باشیم که پیش از اجرای این توابع نباید هیچگونه خروجیای تولید شده باشد.
مثلاً قطعه کد زیر باعث خطا میشود:
<?php
echo "sabzdanesh.com";
session_start();
$var = "test";و باید آن را به شکل زیر تغییر دهیم:
<?php
session_start();
$var = "test";گاهی نباید خروجی را حذف کنیم چون به آن نیاز داریم! در چنین حالتی باید منطق یا ترتیب کدها را طوری تغییر دهیم که Header قبل از تولید خروجی ارسال شود. مثلاً:
<?php
session_start();
echo "sabzdanesh.com";
$var = "test";در مثال بالا، اگر دستور echo در فایل test.php اجرا شده باشد و تابع session_start() در فایل index.php، در بخش output started at متن خطا، فایل test.php مشخص میشود؛ اما برنامه در هنگام اجرای index.php به خطا میخورد.
این مورد بسیار ساده اما پرتکرار است!
برای مثال، اگر فایلی که باعث خطا شده شبیه به زیر شروع کار شود، همان فضای خالی باعث میشود که تعدادی space در خروجی چاپ شود و خطای caot modify header ایجاد شود.
<?php
header("Location: user.php");برای رفع خطا باید این فضای خالی را از ابتدای فایل کد حذف کنیم:
<?php
header("Location: user.php");گاهی ابتدای فایل درست است. علاوه بر این هیچ خروجیای توسط کدمان ایجاد نشده و خطای دیگری نیز نداریم. در این حالت ممکن است که در ابتدا یا انتهای فایل یک کاراکتر نامرئی قرار گرفته باشد. این مشکل مخصوصاً زمانی دیده میشود که فایل با Encoding نامناسب ذخیره شده باشد.
اگر آن فایل را به تازگیً با یک ویرایشگر متنی باز کردهاید یا بهتازگی ایجادش کردهاید، ممکن است این مشکل پیش آمده باشد.
فایل را با یک ویرایشگر که توانایی ویرایش Encoding را میدهد باز کنید. من Notepad++ را پیشنهاد میکنم. سپس از تنظیمات Encoding تحلیل کنید که فایل روی UTF-8 باشد. اگر UTF-8 BOM بود، آن را به UTF-8 یا UTF-8 without BOM تغییر داده و ذخیره کنید.
علت بروز خطا در وردپرس دقیقاً مشابه کد PHP است. اما با توجه به ساختار اجرای کدها در وردپرس، علاوهبر فایلهای هسته، فایلهای پوسته (قالب) و پلاگینها نیز روی ایجاد Header و Body تأثیرگذار هستند.
برای مثال، همانطور که در مستندات وردپرس (+) نیز بیان شده، ممکن است فایلهای functions.php یا wp-config.php باعث ایجاد این خطا شوند. البته اگر قبل از بروز خطا آنها را دستکاری نکردهاید یا چیزی را آپدیت نکردهاید، این احتمال زیاد کم است.
بهطور کلی، برای رفع خطا همان قوانین و مراحلی که پیشتر گفتم را داریم. برای مثال، فرض کنید پیام خطا به فایل زیر اشاره دارد:
/wp-content/themes/sabz/functions/user-profile.php
ما هم باید به سراغ تحلیل فایل user-profile.php که در فولدر functions در پوسته sabz در مسیر /wp-content/themes/ قرار گرفته برویم.
برای باز کردن فایل دو راهحل دارید:
سپس طبق جدول بخش دوم همین آموزش (بالاتر)، بهدنبال دلیل خطا بگردید و آن را رفع کنید.
گاهی ممکن است خطا مربوط به یک افزونه باشد. در چنین حالتی برای رفع خطای header already sent در وردپرس باید کدهای افزونه را دستکاری کنیم.
مثلاً اگر پیام خطا به مسیر زیر اشاره کرد:
/wp-content/plugins/sabz-user/...
به این معنی است که فایلی در افزونهی sabz-user مشکل را ایجاد کرده است.
اگر Plugin متعلق به خودتان نیست، بهتر است مستقیماً کدهای آن را تغییر ندهید. هم ممکن است مشکل دیگری ایجاد شود و هم دگرگونیها شما در آپدیت بعدی از بین برود. در چنین شرایطی بهتر است محور را با توسعهدهنده افزونه یا یک برنامهنویس PHP مطرح کنید.
اگر میخواهید موقتاً خطا را برطرف کنید یا مطمئن شوید که خطا از همین افزونه است، میتوانید آن را بهطور موقت غیرفعال کنید.
اگر متن خطا بهدرستی یا دقیق نمایش داده نمیشود، شاید فعال کردن Debug وردپرس کاربردی باشد. میتوانید تنظیمات زیر را در wp-config.php قرار دهید:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', true);با این تنظیمات خطاها در فایل wp-content/debug.log ثبت میشوند. در ادامه ممکن است متن خطا بهطور دقیق روی صفحه سایت ظاهر شود.
توجه داشته باشید که پس از اصلاح و رفع خطاها، حتماً این تنظیمات را به حالت قبل برگردانید.
اگر کمی بیشتر جستجو کنید، ممکن است در برخی آموزشها با راهحلی آشنا شوید که میگویند از تابع ob_start() در ابتدای فایل کدی که در output started at... تأیید شده استفاده کنید:
ob_start() قابلیت Output Buffering را فعال میکند. در این حالت، خروجی بهجای اینکه همان لحظه به مرورگر ارسال شود، موقتاً داخل Buffer (یک فضای ذخیره موقت) نگهداری میشود. بنابراین در بعضی سناریوها Headerها فرصت پیدا میکنند که قبل از چاپ خروجیها ارسال و تنظیم شوند.
یعنی کدی که به شکل زیر است:
<?php
echo "sabzdanesh.com";
session_start();
$var = "test";را به کدی شبیه به زیر تبدیل کنیم:
<?php
ob_start();
echo "sabzdanesh.com";
session_start();
$var = "test";این راهحل در بعضی موارد مشکل را رفع میکند. اما یک نکته وجود دارد: ob_start() را جایگزین پیدا کردن علت اصلی خطا نکنید! البته میتوانید از آن برای رفع موقت خطا استفاده کنید.
در این آموزش به علت بروز خطای headers already sent در PHP و نحوه رفع خطا در PHP پرداختیم. بهطور خلاصه اگر بخواهم یک چکلیست برای رفع این خطا به شما بدهم، گامهای زیر را پیشنهاد میکنم:
در اکثر مواقع انجام مراحل همین چک لیست برای پیدا کردن و رفع ارور headers already sent در PHP کافی است.
امیدوارم از این آموزش استفاده کرده باشید. اگر سؤال یا چالشی دارید در بخش دیدگاهها مطرح کنید. در ادامه اگر برایتان مفید بود، خوشحالم میشویم که آن را با دیگران به اشتراک بگذارید.
این آموزش برای همیشه مجانیه! میتونید با اشتراکگذاری لینک این صفحه از ما حمایت کنید یا با تهیه یه فنجون نوشیدنی بهمون انرژی بدید!
برچسب:
نویسنده: استخدام کار