رفع مشکل ini_set() has been disabled for security reasons
خطای ini_set() has been disabled for security reasons ایراد اسکریپت شما نیست؛ یعنی مدیر سرور نام تابع ini_set را در دستور disable_functions فایل php.ini قرار داده و PHP اجازه اجرای آن را نمیدهد. برای رفع مشکل یا باید این نام از فهرست حذف شود، یا همان تنظیمی که میخواستید با این تابع عوض کنید را از مسیر دیگری مثل .user.ini، .htaccess یا کنترلپنل اعمال کنید.
این پیغام دقیقاً چه میگوید
متن کامل خطا معمولاً به این شکل است:
Warning: ini_set() has been disabled for security reasons in /home/user/public_html/index.php on line 12
PHP هر تابعی که نامش در disable_functions بیاید را هنگام اجرا مسدود میکند؛ یعنی فراخوانی بیاثر میماند، یک Warning چاپ میشود و ادامه اسکریپت با همان تنظیمات پیشفرض سرور پیش میرود. پس معمولاً سایت کاملاً از کار نمیافتد، ولی تنظیمی که انتظارش را داشتید اعمال نشده است.
یک نکته که وقت زیادی از افراد میگیرد: ini_alter نام مستعار همان ini_set است. بنابراین هنگام بررسی فهرست، هر دو نام را جستوجو کنید.
چرا میزبانها این تابع را میبندند
روی یک سرور اشتراکی دهها سایت کنار هم اجرا میشوند و ini_set به هر اسکریپتی اجازه میدهد در لحظه اجرا محدودیتها را جابهجا کند: بالا بردن memory_limit و max_execution_time (اگر دلیل این کار سرو کردن فایلهای حجیم دانلودی است، ماژول mod_xsendfile راه بسیار کمهزینهتری است)، روشن کردن display_errors که مسیر فایلها و جزئیات اتصال به پایگاهداده را لو میدهد، یا دستکاری include_path و session.save_path. یک اسکریپت آلوده هم از همین تابع برای خاموش کردن گزارش خطا و پنهان کردن رد پای خود استفاده میکند. به همین دلیل بعضی ارائهدهندههای هاست اشتراکی آن را در کنار توابعی مثل system و exec غیرفعال میکنند. این سیاست بین میزبانها یکسان نیست و باید فهرست سرور خودتان را ببینید. فهرست کاملتر کارهایی که برای محدود کردن PHP روی سرور انجام میشود در امنسازی PHP در سرور جمع شده است.
پیدا کردن php.ini فعال و فهرست disable_functions
قبل از هر تغییری باید بدانید کدام فایل پیکربندی واقعاً خوانده میشود. اگر به SSH دسترسی دارید:
php --ini
و برای دیدن مقدار فعلی فهرست:
php -r "echo ini_get('disable_functions'), PHP_EOL;"
مهم است بدانید خروجی این دستورها مربوط به نسخه خط فرمان (CLI) است و در بسیاری از سرورها فایل پیکربندی CLI با فایلی که وبسرور میخواند فرق دارد. برای دیدن پیکربندی واقعی وب، یک فایل موقت با این محتوا بسازید:
<?php phpinfo();
در خروجی آن سه سطر Loaded Configuration File، Additional .ini files parsed و disable_functions را بخوانید. سطر اول مسیر فایل اصلی، سطر دوم فایلهای تکمیلی و سطر سوم دقیقاً همان فهرستی است که خطا را ساخته. بعد از بررسی حتماً این فایل را پاک کنید، چون اطلاعات کاملی از سرور را در اختیار هر بازدیدکنندهای میگذارد.
روی هاست اشتراکی چه کاری از شما برمیآید
خود disable_functions در سطح PHP_INI_SYSTEM تعریف شده؛ یعنی فقط از فایل پیکربندی اصلی سرور قابل تغییر است و کاربر عادی نمیتواند با یک فایل داخل پوشه سایت آن را بازنویسی کند. روی سرورهایی که کلودلینوکس دارند، ابزار PHP Selector به هر حساب اجازه میدهد نسخه PHP و بخشی از تنظیمات آن را جدا از سایر کاربران انتخاب کند، ولی فهرست توابع مسدودشده را همچنان مدیر سرور تعیین میکند.
استثنا میزبانهای قدیمیتری هستند که PHP را به شکل CGI یا suPHP اجرا میکنند و فایل php.ini داخل public_html برای آن حساب بهعنوان پیکربندی اصلی خوانده میشود. در این حالت ساختن فایل php.ini و نوشتن فهرست دلخواه در آن جواب میدهد؛ برای نمونه:
disable_functions = passthru, popen, proc_open, proc_close, proc_terminate, proc_nice, show_source, system
دقت کنید که نام ini_set و ini_alter عمداً در این فهرست نیامده است. اگر سرور شما PHP-FPM یا mod_php باشد این فایل نادیده گرفته میشود و تنها راه، درخواست از پشتیبانی میزبان برای حذف نام تابع از فهرست است.
تنظیم را بدون ini_set اعمال کنید
در بیشتر موارد اصلاً به این تابع نیازی ندارید. اگر PHP بهصورت ماژول آپاچی (mod_php) اجرا میشود، در فایل .htaccess بنویسید:
php_value memory_limit 256Mphp_flag display_errors off
هشدار: اگر PHP روی سرور به شکل FPM یا FastCGI اجرا شود، همین دو خط سایت را با خطای 500 Internal Server Error از دسترس خارج میکنند — همان مکانیزمی که پشت سفید شدن صفحهٔ ورود phpMyAdmin هم هست. در آن حالت بهجای .htaccess فایلی به نام .user.ini کنار اسکریپت بسازید:
memory_limit = 256Mmax_execution_time = 120
فایل .user.ini فقط روی تنظیمات سطح PHP_INI_PERDIR و PHP_INI_USER اثر دارد و تغییرش بلافاصله دیده نمیشود؛ PHP آن را بر اساس مقدار user_ini.cache_ttl که بهطور پیشفرض ۳۰۰ ثانیه است کش میکند. پس اگر بلافاصله بعد از ذخیره تغییری ندیدید، چند دقیقه صبر کنید.
در سیپنل ابزار MultiPHP INI Editor و در دایرکتادمین بخش تنظیمات PHP همین کار را با یک فرم ساده انجام میدهند و اگر PHP Selector هم در دسترس باشد، معمولاً سریعترین راه بدون درگیر شدن با فایل php.ini است.
یک نکته برای کاربران وردپرس: اگر انتظار دارید ثابت WP_MEMORY_LIMIT در wp-config.php حافظه را بالا ببرد، بدانید وردپرس برای اعمال آن از همین ini_set استفاده میکند. تا وقتی تابع بسته باشد این ثابت هم کاری از پیش نمیبرد و باید حافظه را از php.ini یا کنترلپنل افزایش دهید. برای دیدن پیام واقعی خطا در وردپرس هم بهجای ini_set از ثابتهای خود وردپرس استفاده کنید؛ روش کار در روشن کردن نمایش خطا در وردپرس آمده است.
روی سرور مجازی یا اختصاصی
وقتی VPS با دسترسی روت دارید، خودتان صاحب فایل php.ini هستید. اول مسیر فایلی که وبسرور میخواند را پیدا کنید (خروجی php --ini یا سطر Loaded Configuration File در phpinfo())، سپس در آن فایل، مثلاً /etc/php/8.2/fpm/php.ini، سطر disable_functions را باز کنید و فقط نام ini_set و ini_alter را از آن بردارید.
هشدار مهم: کل فهرست را خالی نکنید. باز گذاشتن توابعی مثل system، shell_exec، passthru و proc_open روی سروری که چند سایت میزبانی میکند یک ریسک امنیتی واقعی است و یک قالب یا افزونه آلوده میتواند از آنها برای اجرای دستور روی سیستمعامل استفاده کند.
بعد از ویرایش، سرویس مربوطه را ریاستارت کنید:
systemctl restart php8.2-fpm
روی توزیعهای خانواده RHEL نام سرویس معمولاً php-fpm است و اگر PHP به شکل ماژول آپاچی اجرا میشود باید خود وبسرور را با systemctl restart httpd یا systemctl restart apache2 ریاستارت کنید. در پایان یک بار دیگر phpinfo() را ببینید تا مطمئن شوید مقدار جدید disable_functions واقعاً اعمال شده است.
چطور دیگر با این خطا روبهرو نشوید
تنظیماتی که برای اجرای درست سایت حیاتی هستند را به ini_set نسپارید؛ آنها را در .user.ini یا کنترلپنل بنویسید تا مستقل از سیاست میزبان کار کنند. اگر در کد خودتان ناچار به استفاده از این تابع هستید، پیش از فراخوانی وضعیتش را بررسی کنید تا بهجای Warning، یک مسیر جایگزین اجرا شود:
$disabled = array_map('trim', explode(',', ini_get('disable_functions')));if (!in_array('ini_set', $disabled)) { ini_set('memory_limit', '256M'); }
هنگام انتقال سایت به میزبان جدید هم همان روز اول فهرست disable_functions سرور تازه را با سرور قبلی مقایسه کنید؛ بخش بزرگی از خطاهای «بعد از مهاجرت سایت خراب شد» ریشه در همین تفاوت دارد. اگر تیم فنی در اختیار ندارید، میتوانید بررسی و اصلاح پیکربندی PHP را به تیم پشتیبانی آنلاین سرور بسپارید تا این تغییر با در نظر گرفتن ملاحظات امنیتی انجام شود.