رسیدگی یا مدیریت خطاها در php
رسیدگی به خطاها در php بسیار ساده است. به صورت پیشفرض اگر خطایی رخ دهد، یک پیغام خطا که توضیح دهنده ی خطا است، همراه با نام فایل و شماره خط به مرورگر فرستاده می شود.
هنگام ایجاد برنامه های تحت وب، بررسی خطاها یک بخش مهم است. اگر کد شما امکان بررسی خطا را نداشته باشد، در این صورت بسیار غیرحرفه ای عمل کرده اید و ممکن است در معرض خطر امنیتی قرار بگیرید.
در زیر بعضی روش های معمول بررسی خطا در php توضیح داده خواهد شد:
- استفاده از دستور ساده ()die
- خطاهای معمولی و راه اندازی رسیدگی کننده خطا
- واقعه نگاری خطاها
استفاده از تابع ()die
این تابع متنی را که به عنوان پارامتر برای آن مشخص کرده ایم، چاپ می کند و از کد جاری خارج می شود.
مثال: در این مثال با استفاده از تابع ()fopen یک فایل متنی را به صورت فقط خواندنی باز می کنیم:
<?php
$file=fopen("welcome.txt","r");
?>
اگر فایل وجود نداشته باشد، با خطای زیر مواجه می شویم:
Warning: fopen(welcome.txt) [function.fopen]: failed to open stream:
No such file or directory in C:\webfolder\test.php on line 2
برای اینکه کاربر با پیغام خطای بالا مواجه نشود، قبل از هر چیز، وجود فایل "welcome.txt" را بررسی می کنیم:
<?php
if(!file_exists("welcome.txt"))
die("File not found");
else
$file=fopen("welcome.txt","r");
?>
کد بالا کارامدتر از کد قبلی است، حالا اگر فایل وجود نداشته باشد بعد از اجرای اسکریپت، پیغام خطای زیر نمایش داده می شود:
File not found
توجه: در اسکریپت بالا، بعد از اجرای دستور ()die، ادامه اجرای اسکریپت متوقف می شود.
متوقف کردن اسکریپت، به این سادگی، همیشه راه درست نیست. بیایید نگاهی به توابع تناوبی رفع خطا در php بیندازیم.
ایجاد یک تابع رسیدگی کننده خطا (error handler)
ایجاد این تابع کاملاً ساده است، و هرگاه که در کد PHP خطایی رخ داد این تابع فراخوانی می شود.
این تابع باید بتواند حداقل با دو پارامتر کار کند(سطح خطا و پیغام خطا) اما تا پنج پارامتر را بپذیرد(اختیاری: فایل، شماره خط و متن پیغام):
نحوه استفاده:
error_function(error_level,error_message,error_file,error_line,error_context)
پارامتر | توضیحات |
---|---|
error_level | الزامی است، سطح گزارش خطا را مشخص می کند. جدول زیر را برای انواع سطوح گزارش خطا ببینید. |
error_message | الزامی است، پیغام خطا را برای خطای تعریف شده توسط کاربر مشخص می کند. |
error_file | اختیاری است. نام فایلی را که خطا در ان رخ داده است مشخص می کند. |
error_line | اختیاری است. شماره خطی را که خطا در آن رخ داده است مشخص می کند. |
error_context | اختیاری است. یک آرایه که شامل تمام متغییرهای در حال استفاده هنگام رخداد خطا با مقادیرشان است را مشخص می کند. |
سطوح گزارش خطا:
مقدار | نام ثابت | توضیحات |
---|---|---|
2 | E_WARNING | خطاهای زمان اجرا غیر جدی. اجرای script متوقف نمی شود |
8 | E_NOTICE | اخطارهای زمان اجرا.script چیزی پیدا کرده که ممکن است خطا باشد? اما می تواند در اجرای معمولی script نیز رخ دهد |
256 | E_USER_ERROR | خطای جدی کاربرساز. مانند یک E-ERROR که توسط کابر با استفاده از تابع trigger_error( ) در php به وجود می آید. |
512 | E_USER_WARNING | هشدار غیرجدی کاربرساز. مانند یک E_WARNING است که توسط کابر با استفاده از تابع trigger_error( ) در php به وجود می آید. |
1024 | E_USER_NOTICE | اخطار کاربرساز. مانند یک E_NOTICE است که توسط کابر با استفاده از تابع trigger_error( ) در php به وجود می آید. |
4096 | E_RECOVERABLE_ERROR | خطای جدی گرفتنی. مانند یک E_ERROR است اما بوسیله ی رفع خطای تعریف شده توسط کاربر می توان ان را گرفت(set_error_handler( ) را نیز ببینید) |
8191 | E_ALL | همه ی خطاها و هشدارها?به جز سطح E_STRICT) E_STRICT در php 6.0 جزئی از E_ALL خواهد شد.) |
حالا اجازه دهید تا یک تابع برای رسیدگی کردن به خطاها ایجاد کنیم، که شامل ورودی های زیر است:
- errno$: سطح خطا
- errstr$: متن خطا
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br />";
echo "Ending Script";
die();
}
کد بالا موقعی که راه اندازی شد، "سطح خطا" و "متن خطا" را می گیرد و سپس با چاپ کردن دو مورد ذکر شده به اجرای اسکریپت پایان می دهد.
در حال حاضر باید تصمیم بگیریم که چه موقع تابع بالا، راه اندازی شود.
تنظیم رسیدگی کننده خطا
ما قصد داریم تابع "customError" را به عنوان پیشفرض رسیدگی کننده خطا در PHP معرفی کنیم، این کار به سادگی با استفاده از تابع زیر در PHP امکان پذیر است:
set_error_handler("customError");
نکته: یک پارامتر دوم می تواند برای مشخص کردن سطح خطا به تابع ()set_error_handler اضافه شود، ولی چون می خواهیم که تابع معمولی مان همه ی خطاها را رفع کند، ()set_error_handler تنها با یک پارامتر فراخوانی می شود.
مثال: در زیر سعی کرده ایم با چاپ متغییر "test$" که وجود ندارد تابع "رسیدگی کننده خطا" یا همان "customError" را تست کنیم:
<?php
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr";
}
set_error_handler("customError");
echo($test);
?>
خروجی کد بالا:
Error: [8] Undefined variable: test
راه اندازی یک خطا
در اسکریپتی که کاربران می توانند داده وارد کنند، می توان موقع رخداد یک ورودی غیرمجاز خطاها را راه اندازی کرد. در php، این کار با تابع ()trigger_error انجام می شود.
مثال: در این مثال اگر متغییر "test" بزرگتر از "1" باشد، یک خطا رخ می دهد:
<?php
$test=2;
if ($test>1)
{
trigger_error("Value must be 1 or below");
}
?>
خروجی کد بالا:
Notice: Value must be 1 or below
in C:\webfolder\test.php on line 5
یک خطا می تواند هر جایی در اسکریپت که بخواهید راه اندازی شود و با افزودن پارامتر دوم شما می توانید مشخص کنید که چه سطح خطایی راه اندازی شود.
مثال: در این مثال یک خطا با سطح E_USER_WARNING رخ می دهد، اگر متغییر "test" بزرگتر از "1" باشد، تابع رسیدگی کننده خطا، راه اندازی شده و اسکریپت را خاتمه می دهیم:
<?php
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br />";
echo "Ending Script";
die();
}
set_error_handler("customError",E_USER_WARNING);
$test=2;
if ($test>1)
{
trigger_error("Value must be 1 or below",E_USER_WARNING);
}
?>
خروجی کد بالا:
Error: [512] Value must be 1 or below
Ending Script
اکنون که طریقه ی رسیدگی به خطاها و چگونگی راه اندازی آن ها را یاد گرفتیم، اجاز دهید نگاهی به واقعه نگاری (Log) خطاها بیندازیم.
واقعه نگاری خطاها (Log)
به طور پیش فرض، php یک گزارش خطا به سیستم واقعه نگاری سرورها یا یک فایل، بسته به اینکه پیکر بندی گزارش خطا چگونه درفایل php.ini تنظیم شده است ارسال می کند. با استفاده از تابع ()error_log شما می توانید گزارش های خطا را به به یک فایل مشخص شده یا یک مقصد دور ارسال کنید.
ارسال پیغام های خطاها به خودتان از طریق email می تواند روش خوبی برای آگاه شدن از خطاهای خاص باشد.
مثال: در این مثال اگر یک خطای خاص رخ دهد ما یک e-mail را همراه با یک پیغام خطا به آدرس مشخص شده می فرستیم و اسکریپت خاتمه خواهد یافت:
<?php
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br />";
echo "Webmaster has been notified";
error_log("Error:[$errno]$errstr",1,"
}
set_error_handler("customError",E_USER_WARNING);
$test=2;
if ($test>1)
{
trigger_error("Value must be 1 or below",E_USER_WARNING);
}
?>
خروجی کد بالا:
Error: [512] Value must be 1 or below
Webmaster has been notified
و در ادامه ایمیل دریافت شده چیزی شبیه زیر خواهد بود:
Error: [512] Value must be 1 or below
توجه: این نباید برای همه ی خطاها استفاده شود، خطاهای معین باید با سیستم واقعه نگاری پیش فرض php در سرور ثبت شوند.
برای مشاهده فیلم ها و آموزش های پروژه محور برنامه نویسی PHP کلیک کنید.
errno$: (سطح خطا) --> 8
errstr$: (متن خطا) --> Undefined variable: test
اسکریبت مورد نظر:
<?php
function customError($errno, $errstr)
{
echo "Error: [$errno] $errstr";
}
set_error_handler("customError");
echo($test);
?>بنابراین زمانی که تابع customError صدا زده می شود، پارامترهای مذکور بصورت اتوماتیک توسط PHP مقداردهی شده اند.
نهایتا وظیفه تابع customError در زیر کاملا واضح است که باعث چاپ همزمان "سطح خطا" و "متن خطا" شده و در انتهای آن با استفاده از تابع die از برنامه خارج می شویم.
function customError($errno, $errstr)
{
echo "Error: [$errno] $errstr";
echo "Ending Script";
die();
}
Warning: fopen(welcome.txt) [function.fopen]: failed to open stream:
No such file or directory in C:\webfolder\test.php on line 2
همان طور که در بالا می بینید، داخل پیام خطا، "نام فایل" و "آدرس فایلی" که خطا در آن اتفاق افتاده است بصورت کامل ذکر شده که از لحاظ امنیتی، نباید نمایش داده شود. اما ما با استفاده از تابع customError می توانیم موارد ذکر شده را از داخل متن خطا حذف کنیم و کلا مدیریت گزارش خطاها را بدست بگیریم.
بعد از اجرای کد چنین خطایی دارم ممکنه کمک کنید:Parse error: syntax error, unexpected T_ELSE in C:\xampp\htdocs\f\r.php on line 6529
متن کد نیومده! ولی متن خطا داره میگه، تو کدها خطای گرامری وجود داره.
یه جایی تو دستور if else احتمالا مرتکب خطا شدید.
این موارد رو چک کنید.
میخاستم اگه بشه این کد رو که در بالا نوشته بودید توضیح بدید .ممنون.
دقیقا منظور شما کدوم قسمت از کد هست؟؟؟
من میگم دستور if دو حالت داره. یا شرطش درسته یا غلط.
اینجا اگر شرط درست باشه (فایل وجود نداشته باشه) ، ()die اجرا میشه و بعد از اون هیچ چیزی اجرا نمیشه. (یعنی else اجرا نمیشه)
و اگر شرط غلط باشه (فایل وجود داشه باشه) ، از بلاک if خارج میشه و دستور بعد از if هرچی باشه اجرا میشه و حالت دیگری وجود نداره که else نیاز داشته باشه.
معمول ترین نوع ساختار تصمیم گیری if است. یک دستور if می گوید "اگر شرطی برقرار است کد معینی را انجام بده". دستور if-else به دو شکل می تواند باشد: همراه با else يا بدون آن.
if(expression)
{
statement
}
يا
if(expression)
{
statement
}
else
{
statement
}
بدنبال کلمه if یک پرانتز می آید که عبارت شرط در آن قرار دارد و يک مقدار بولين false يا true توليد می کند (در C به صورت صفر و غير صفر ارزيابی می شود). با درست و غلط بودن عبارت شرطی مسير اجرا تعيين می شود. اگر درست باشد دستور بعد از if اجرا می شود. اگر else وجود داشته باشد در صورت برقرار نبودن شرط دستور بعد از else اجرا می شود.
با توجه به توضیحات ذکر شده، در صورت برقرار نبودن شرط if عبارت جلوی else اجرا می شود. بر اساس سوال شما، یعنی در صورتی که فایل وجود داشته باشد و نخواهیم در صورت وجود فایل کار دیگری انجام دهیم بله می توانیم else را بر داریم.
نه من نگفتم عبارت جلوی else برداشته بشه. حرف من اینه که خود کلمه ی else از این کد برداشته بشه. یعنی فقط خط سوم رو حذف کنیم. اگر این کار رو بکنیم نتیجه هیچ تغییری نمی کنه. امتحان کنید.
من از اول دارم میگم کاری به عبارت جلوی else نداشته باشید. فقط else را بردارید شما دوباره میگید else به همراه عبارت جلوی else.
حرف من این است که اگر نیاز به انجام کاری هم باشد (مثل الآن) ، می توان کلمه ی else را برداشت و عبارت جلوی else بدون else نوشت.
در تکمیل صحبت های خانم دوستی و همچنین نظرات آقای ربانی:
اینکه آقای ربانی می فرماید که با برداشتن کلمه ی else عبارت شرطی بدون هیچ مشکلی اجرا می شود درسته مثلا می تونید عبارت زیر را امتحان کنید:
< ?php
if (1>2)
echo "1>2";
echo "2>1";
? >
در کدهای بالا در خط کد 7 دستور else را برداشته ایم و عبارت شرطی به درستی عمل می کند.
در زبان پایتون اگر اشتباه نکنم عبارات شرطی به این شکل نوشته می شوند(در یکی از حالت هایش) . به نظرم این طور نوشتن دستورات در php مربوط به نسخه های قدیمی آن باشد. و در php نوین، ذکر شده است که عبارت else را اضافه کنیم.
die("File not found");
else
$file=fopen("welcome.txt","r");
مگر بعد از اجراي دستور ()die، ادامه اجراي اسکريبت متوقف نمی شود؟
پس دیگر نوشتن کلمه ی else نیازی نیست! اگر بلوک if اجرا شد ادامه ی اسکریپت اجرا نمی شود و اگر اجرا نشد بقیه اجرا می شود.
پس کاربرد کلمه ی else در اینجا چیست؟
اما توجه داشته باشید که زمانی که آدرس دهی بدرستی انجام شده باشد، باید به قسمت else منتقل شویم و فایل مورد نظرمان را open کنیم.