Накратко: php_admin_value и php_admin_flag задават настройки на PHP в пула на PHP-FPM или в конфигурацията на Apache така, че приложенията не могат да ги променят нито чрез ini_set(), нито чрез .htaccess. php.net изисква точно това за преходните мерки при PHP2Shell, например за memory_limit=-1. След задаването услугата трябва да се рестартира, а стойността да се провери в уеб контекст.
Защо „зададено“ не значи „заключено“
През дните след 21 октомври 2026 г. много администратори записаха преходните мерки на php.net в своя php.ini. Един детайл от препоръката често се изгуби: memory_limit=-1 трябва да е зададен така, че приложенията да не могат да го презапишат. php.net изрично посочва за това php_admin_value в пула на FPM или в конфигурацията на Apache.
Причината е проста. Много CMS, магазини и рамки задават свои собствени стойности, например по-висок лимит на паметта за импорти. Ако стойността стои само в php.ini, приложението я презаписва при следващото извикване. Защитната мярка тогава съществува на хартия, но не и в работещия процес.
Това не засяга само PHP2Shell. Всяко заздравяване, от изключени изходи на грешки до лимити за качване, е толкова силно, колкото е най-слабото му ниво.
Кой изобщо може да променя настройките на PHP
PHP познава четири режима на промяна. Всяка настройка има един от тях и той определя на кои места може да бъде зададена. Значенията идват от ръководството на PHP.
| Режим | Къде може да се задава стойността | Примери |
|---|---|---|
INI_USER |
в скрипта чрез ini_set() и в .user.ini |
малко стойности за времето на изпълнение |
INI_PERDIR |
php.ini, .htaccess, httpd.conf, .user.ini |
post_max_size, session.upload_progress.enabled |
INI_SYSTEM |
само php.ini или httpd.conf |
file_uploads, disable_functions |
INI_ALL |
навсякъде, и чрез ini_set() |
memory_limit, display_errors, open_basedir |
Опасни са най-вече стойностите INI_ALL: те могат да се променят от всеки скрипт. Стойностите INI_PERDIR наистина не могат да се променят чрез ini_set(), но могат чрез .htaccess при mod_php или .user.ini при PHP-FPM. Който има права за писане в уеб корена, тоест и внедреният код, може да създава такива файлове.
php_admin_value в пула на FPM и в Apache
При PHP-FPM стойностите стоят във файла на пула. Ръководството на PHP отбелязва: стойности, зададени с php_admin_value и php_admin_flag, не могат да се презаписват чрез ini_set(). За стойности включено-изключено ползвайте php_admin_flag, за всички останали php_admin_value.
; /etc/php/8.3/fpm/pool.d/seite1.conf (откъс)
[seite1]
user = seite1
group = seite1
listen = /run/php/seite1.sock
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
php_admin_flag[session.upload_progress.enabled] = off
php_admin_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
php_admin_value[open_basedir] = /var/www/seite1/:/tmp/seite1/
Според php.net memory_limit=-1 принадлежи в конфигурацията само заедно с лимит на паметта чрез контейнер или cgroup. Как това се постига със systemd, е описано в статията Задаване на лимити на паметта със systemd и cgroups.
При Apache с mod_php директивите принадлежат в конфигурацията на сървъра или във VirtualHost. Според ръководството на PHP те не са позволени в .htaccess, а веднъж зададени, нито .htaccess, нито ini_set() могат да ги променят.
<VirtualHost *:443>
ServerName www.example.de
DocumentRoot /var/www/seite1/public
<IfModule php_module>
php_admin_value memory_limit -1
php_admin_value post_max_size 32M
php_admin_value upload_max_filesize 24M
php_admin_flag session.upload_progress.enabled off
php_admin_flag display_errors off
</IfModule>
</VirtualHost>
Две тънкости от ръководството: за да изтриете предишно зададена стойност, използвайте none като стойност. А константите на PHP като E_ALL нямат значение в конфигурацията на Apache; за error_reporting там трябва да посочите числовата стойност.
Кои стойности да заключите
Не всяка настройка трябва да е заключена. Смислено е това за всичко, което засяга сигурността или служи като преходна мярка:
- Преходните стойности на php.net за PHP2Shell:
memory_limit,post_max_size,upload_max_filesize,session.upload_progress.enabledи за PHP 8.5fatal_error_backtraces. - Изход на грешки и протоколиране:
display_errors,display_startup_errors,log_errors,error_log. - Достъп до файлове и изолация:
open_basedir,upload_tmp_dir,session.save_path. - Мрежови достъпи от PHP:
allow_url_includeи, ако приложението не го изисква,allow_url_fopen. - Блокирани функции чрез
disable_functions, които в пула според ръководството допълват списъка от php.ini, а не го заместват. Подробности в ръководството Правилно използване на disable_functions.
При session.upload_progress.enabled заключването е особено важно, защото иначе стойността би могла да бъде включена отново чрез .user.ini. Повече по темата в Изключване на session.upload_progress: правилно и трайно.
Проверка дали заключването действа
След всяка промяна рестартирайте услугата и проверете стойността в уеб контекст. Кратък проверочен файл, изтрит веднага след това, показва дали пулът държи стойността, дори когато приложението иска да я промени:
<?php
// Проверочен файл: поставете го за кратко, извикайте го веднъж през домейна, изтрийте го веднага
header('Content-Type: text/plain');
$vorher = ini_get('memory_limit');
$versuch = @ini_set('memory_limit', '256M');
echo "memory_limit: $vorher\n";
echo 'Änderung per ini_set() ', ($versuch === false ? 'blockiert' : 'MÖGLICH'), "\n";
Очаква се -1 и „blockiert“. Ако изходът е „MÖGLICH“, стойността не е зададена чрез php_admin_value или услугата още не е рестартирана. Повторете проверката за всеки пул и всяка версия на PHP.
Водете заключените стойности централно, например в шаблон на пул или във Вашето управление на конфигурацията. Хостинг панелите понякога презаписват ръчно променени файлове на пулове при следващото запазване; там стойностите принадлежат в предвидените от панела полета.
Как PHP подрежда принципно нивата на конфигурация, обяснява php.ini обяснен: структура, нива и приоритет. Пълните преходни мерки са в Незабавни мерки, когато още не можете да пачнете.
Извод: едва заключената стойност е наистина зададена
Преходните мерки на php.net за PHP2Shell изведоха на преден план едно разграничение, което преди често се пренебрегваше: стойност в php.ini е за много настройки само предложение, а стойност в php_admin_value е изискване. За удобни стойности като часовата зона разликата е без значение. За настройки на сигурността и преходни мерки тя решава дали мярката изобщо действа в работата.
Усилието е обозримо: шепа редове за всеки пул или VirtualHost, едно рестартиране, една кратка проверка. Дръжте списъка със заключени стойности малък и обоснован, за да могат разработчиците да разберат защо тяхното приложение не бива да променя дадена стойност. И поддържайте списъка във Вашите шаблони, за да го наследяват автоматично новите сайтове.
Как помага PHP SOS конкретно?
- Прочитане на нивата: установяваме за всеки сайт кои стойности от php.ini, пула, Apache,
.htaccessили.user.iniдействително важат. - Задаване на заключвания: вписваме свързаните със сигурността стойности и преходните мерки за PHP2Shell като
php_admin_valueреспективноphp_admin_flagи рестартираме услугите. - Тест на приложението: проверяваме дали приложението работи безгрешно със заключените стойности и анализираме лога за грешки.
- Поддържане на шаблоните: в рамките на заздравяването на сървъра пренасяме стойностите в шаблони на пулове и в документацията.
Често задавани въпроси
Каква е разликата между php_value и php_admin_value?
И двете задават настройка на PHP. Стойности от php_value приложението може по-късно да промени отново, например чрез ini_set() или .htaccess. Стойности от php_admin_value и php_admin_flag според ръководството на PHP са заключени за ini_set(), а при Apache и за .htaccess.
Мога ли да запиша php_admin_value във файл .htaccess?
Не. Според ръководството на PHP php_admin_value не е позволено във файлове .htaccess. То принадлежи в конфигурацията на сървъра Apache или във VirtualHost, а при PHP-FPM във файла на пула.
Какво се случва, когато приложение иска да промени заключена стойност?
Извикването на ini_set() се проваля и връща false, заключената стойност остава. Добре програмираните приложения се справят с това. След прехода все пак проверете лога за грешки и най-важните функции.
Трябва ли да рестартирам след промяна в пула?
Да. PHP-FPM чете файловете на пуловете при стартиране или при презареждане на услугата. При Apache с mod_php същото важи за конфигурацията на сървъра. Без рестартиране старата стойност продължава да работи.
Може ли disable_functions да се разшири в пула?
Да, със особеност: според ръководството на PHP disable_functions в пула на FPM не презаписва стойностите от php.ini, а ги допълва. Пулът може да блокира още функции, но не може да освободи такива.