2007-04-12 20:24:50 +00:00
|
|
|
# Functions for managing the PHP configuration file
|
|
|
|
|
2009-03-01 21:35:40 +00:00
|
|
|
BEGIN { push(@INC, ".."); };
|
|
|
|
use WebminCore;
|
2007-04-12 20:24:50 +00:00
|
|
|
&init_config();
|
|
|
|
%access = &get_module_acl();
|
|
|
|
|
2017-05-31 22:26:46 -07:00
|
|
|
# get_config_fmt(file)
|
|
|
|
# Returns a format code for php.ini or FPM config files
|
|
|
|
sub get_config_fmt
|
|
|
|
{
|
|
|
|
local ($file) = @_;
|
|
|
|
return $file =~ /\.conf$/ ? "fpm" : "ini";
|
|
|
|
}
|
|
|
|
|
2007-04-12 20:24:50 +00:00
|
|
|
# get_config([file])
|
|
|
|
# Returns an array ref of PHP configuration directives from some file
|
|
|
|
sub get_config
|
|
|
|
{
|
|
|
|
local ($file) = @_;
|
2010-01-08 13:06:15 -08:00
|
|
|
$file ||= &get_default_php_ini();
|
2017-05-31 22:26:46 -07:00
|
|
|
local $fmt = &get_config_fmt($file);
|
2007-04-12 20:24:50 +00:00
|
|
|
if (!defined($get_config_cache{$file})) {
|
|
|
|
local @rv = ( );
|
|
|
|
local $lnum = 0;
|
|
|
|
local $section;
|
2020-03-14 17:20:54 -07:00
|
|
|
open(CONFIG, "<".$file) || return undef;
|
2017-05-31 22:26:46 -07:00
|
|
|
if ($fmt eq "ini") {
|
|
|
|
# Classic php.ini format
|
|
|
|
while(<CONFIG>) {
|
|
|
|
s/\r|\n//g;
|
|
|
|
s/\s+$//;
|
|
|
|
local $uq;
|
|
|
|
if (/^(;?)\s*(\S+)\s*=\s*"(.*)"/ ||
|
|
|
|
/^(;?)\s*(\S+)\s*=\s*'(.*)'/ ||
|
|
|
|
($uq = ($_ =~ /^(;?)\s*(\S+)\s*=\s*(.*)/))) {
|
|
|
|
# Found a variable (php.ini format)
|
|
|
|
push(@rv, { 'name' => $2,
|
|
|
|
'value' => $3,
|
|
|
|
'enabled' => !$1,
|
|
|
|
'line' => $lnum,
|
|
|
|
'file' => $file,
|
|
|
|
'section' => $section,
|
|
|
|
'fmt' => $fmt,
|
|
|
|
});
|
|
|
|
if ($uq) {
|
|
|
|
# Remove any comments
|
|
|
|
$rv[$#rv]->{'value'} =~ s/\s+;.*$//;
|
|
|
|
}
|
2007-05-05 04:48:38 +00:00
|
|
|
}
|
2017-05-31 22:26:46 -07:00
|
|
|
elsif (/^\[(.*)\]/) {
|
|
|
|
# A new section
|
|
|
|
$section = $1;
|
|
|
|
}
|
|
|
|
$lnum++;
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
2017-05-31 22:26:46 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
# FPM config file format, with php options
|
|
|
|
while(<CONFIG>) {
|
|
|
|
s/\r|\n//g;
|
|
|
|
s/\s+$//;
|
2021-09-12 17:08:12 -07:00
|
|
|
if (/^(;?)(php_admin_value|php_value)\[(\S+)\]\s*=\s*(.*)/) {
|
2017-05-31 22:26:46 -07:00
|
|
|
# Found an FPM config that sets a PHP variable
|
2021-09-12 17:08:12 -07:00
|
|
|
push(@rv, { 'name' => $3,
|
|
|
|
'value' => $4,
|
|
|
|
'admin' => $2 eq "php_admin_value" ? 1 : 0,
|
2017-05-31 22:26:46 -07:00
|
|
|
'enabled' => !$1,
|
|
|
|
'line' => $lnum,
|
|
|
|
'file' => $file,
|
|
|
|
'fmt' => $fmt,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
$lnum++;
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
close(CONFIG);
|
|
|
|
$get_config_cache{$file} = \@rv;
|
|
|
|
}
|
|
|
|
return $get_config_cache{$file};
|
|
|
|
}
|
|
|
|
|
|
|
|
# find(name, &config, [disabled-mode])
|
2017-05-31 22:26:46 -07:00
|
|
|
# Look up a directive by name
|
2007-04-12 20:24:50 +00:00
|
|
|
sub find
|
|
|
|
{
|
|
|
|
local ($name, $conf, $mode) = @_;
|
|
|
|
local @rv = grep { lc($_->{'name'}) eq lc($name) &&
|
|
|
|
($mode == 0 && $_->{'enabled'} ||
|
|
|
|
$mode == 1 && !$_->{'enabled'} ||
|
|
|
|
$mode == 2) } @$conf;
|
|
|
|
return wantarray ? @rv : $rv[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
sub find_value
|
|
|
|
{
|
|
|
|
local @rv = map { $_->{'value'} } &find(@_);
|
|
|
|
return $rv[0];
|
|
|
|
}
|
|
|
|
|
2010-06-19 14:07:44 -07:00
|
|
|
# save_directive(&config, name, [value], [newsection], [neverquote])
|
2007-04-12 20:24:50 +00:00
|
|
|
# Updates a single entry in the PHP config file
|
|
|
|
sub save_directive
|
|
|
|
{
|
2010-06-19 14:07:44 -07:00
|
|
|
local ($conf, $name, $value, $newsection, $noquote) = @_;
|
2007-04-12 20:24:50 +00:00
|
|
|
$newsection ||= "PHP";
|
|
|
|
local $old = &find($name, $conf, 0);
|
|
|
|
local $cmt = &find($name, $conf, 1);
|
2017-05-31 22:26:46 -07:00
|
|
|
local $fmt = $old ? $old->{'fmt'} : @$conf ? $conf->[0]->{'fmt'} : "fpm";
|
2007-04-12 20:24:50 +00:00
|
|
|
local $lref;
|
2017-05-31 22:26:46 -07:00
|
|
|
if ($fmt eq "ini") {
|
|
|
|
$newline = $name." = ".
|
|
|
|
($value !~ /\s/ || $noquote ? $value :
|
|
|
|
$value =~ /"/ ? "'$value'" : "\"$value\"");
|
|
|
|
}
|
|
|
|
else {
|
2021-09-12 17:08:12 -07:00
|
|
|
my $n = !$old || $old->{'admin'} ? "php_admin_value" : "php_value";
|
|
|
|
$newline = $n."[".$name."] = ".$value;
|
2017-05-31 22:26:46 -07:00
|
|
|
}
|
2007-04-12 20:24:50 +00:00
|
|
|
if (defined($value) && $old) {
|
|
|
|
# Update existing value
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($old->{'file'});
|
2007-04-12 20:24:50 +00:00
|
|
|
$lref->[$old->{'line'}] = $newline;
|
|
|
|
$old->{'value'} = $value;
|
|
|
|
}
|
|
|
|
elsif (defined($value) && !$old && $cmt) {
|
|
|
|
# Update existing commented value
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($cmt->{'file'});
|
2007-04-12 20:24:50 +00:00
|
|
|
$lref->[$cmt->{'line'}] = $newline;
|
|
|
|
$cmt->{'value'} = $value;
|
|
|
|
$cmt->{'enabled'} = 1;
|
|
|
|
}
|
|
|
|
elsif (defined($value) && !$old && !$cmt) {
|
|
|
|
# Add a new value, at the end of the section
|
2017-05-31 22:26:46 -07:00
|
|
|
my ($lastline, $lastfile);
|
|
|
|
if ($fmt eq "ini") {
|
|
|
|
# Find last directive in requested php.ini section
|
|
|
|
my $last;
|
|
|
|
foreach my $c (@$conf) {
|
|
|
|
if ($c->{'section'} eq $newsection) {
|
|
|
|
$last = $c;
|
|
|
|
}
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
2017-05-31 22:26:46 -07:00
|
|
|
$last || &error("Could not find any values in ".
|
|
|
|
"section $newsection");
|
|
|
|
$lastfile = $last->{'file'};
|
|
|
|
$lastline = $last->{'line'};
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($lastfile);
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-05-31 22:26:46 -07:00
|
|
|
# Just add at the end
|
|
|
|
$lastfile = @$conf ? $conf->[0]->{'file'} : undef;
|
|
|
|
$lastfile || &error("Don't know which file to add to");
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($lastfile);
|
2017-05-31 22:26:46 -07:00
|
|
|
$lastline = scalar(@$lref);
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
2017-05-31 22:26:46 -07:00
|
|
|
|
|
|
|
# Found last value in the section - add after it
|
|
|
|
splice(@$lref, $lastline+1, 0, $newline);
|
|
|
|
&renumber($conf, $lastline, 1);
|
|
|
|
push(@$conf, { 'name' => $name,
|
|
|
|
'value' => $value,
|
|
|
|
'enabled' => 1,
|
|
|
|
'file' => $lastfile,
|
|
|
|
'line' => $lastline+1,
|
|
|
|
'section' => $newsection,
|
|
|
|
});
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
elsif (!defined($value) && $old && $cmt) {
|
|
|
|
# Totally remove a value
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($old->{'file'});
|
2007-04-12 20:24:50 +00:00
|
|
|
splice(@$lref, $old->{'line'}, 1);
|
|
|
|
@$conf = grep { $_ ne $old } @$conf;
|
|
|
|
&renumber($conf, $old->{'line'}, -1);
|
|
|
|
}
|
|
|
|
elsif (!defined($value) && $old && !$cmt) {
|
|
|
|
# Turn a value into a comment
|
2019-10-05 23:00:35 -07:00
|
|
|
$lref = &read_file_lines_as_user($old->{'file'});
|
2007-04-12 20:24:50 +00:00
|
|
|
$old->{'enabled'} = 0;
|
|
|
|
$lref->[$old->{'line'}] = "; ".$lref->[$old->{'line'}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub renumber
|
|
|
|
{
|
|
|
|
local ($conf, $line, $oset) = @_;
|
|
|
|
foreach my $c (@$conf) {
|
|
|
|
$c->{'line'} += $oset if ($c->{'line'} > $line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# can_php_config(file)
|
|
|
|
# Returns 1 if some config file can be edited
|
|
|
|
sub can_php_config
|
|
|
|
{
|
|
|
|
local ($file) = @_;
|
|
|
|
return &indexof($file, map { $_->[0] } &list_php_configs()) >= 0 ||
|
|
|
|
$access{'anyfile'};
|
|
|
|
}
|
|
|
|
|
2010-01-08 13:06:15 -08:00
|
|
|
# get_default_php_ini()
|
|
|
|
# Returns the first php.ini that exists
|
|
|
|
sub get_default_php_ini
|
|
|
|
{
|
2013-03-30 17:56:53 -07:00
|
|
|
local @inis = split(/\t+/, $config{'php_ini'});
|
|
|
|
foreach my $ai (@inis) {
|
2010-01-08 13:06:15 -08:00
|
|
|
local ($f, $d) = split(/=/, $ai);
|
2021-08-14 13:20:46 -07:00
|
|
|
local @f = glob($f);
|
|
|
|
return $f[0] if (@f && -r $f[0]);
|
2010-01-08 13:06:15 -08:00
|
|
|
}
|
2021-08-14 13:20:46 -07:00
|
|
|
if ($config{'alt_php_ini'} && -r $config{'alt_php_ini'} && @inis) {
|
2013-03-30 17:56:53 -07:00
|
|
|
# Fall back to default file
|
|
|
|
local ($f) = split(/=/, $inis[0]);
|
|
|
|
©_source_dest($config{'alt_php_ini'}, $f);
|
|
|
|
return $f;
|
|
|
|
}
|
2010-01-08 13:06:15 -08:00
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
2007-04-12 20:24:50 +00:00
|
|
|
# list_php_configs()
|
2010-01-08 13:06:15 -08:00
|
|
|
# Returns a list of allowed config files and descriptions
|
2007-04-12 20:24:50 +00:00
|
|
|
sub list_php_configs
|
|
|
|
{
|
|
|
|
local @rv;
|
2013-03-30 17:56:53 -07:00
|
|
|
&get_default_php_ini(); # Force copy of sample ini file
|
2007-04-12 20:24:50 +00:00
|
|
|
if ($access{'global'}) {
|
|
|
|
foreach my $ai (split(/\t+/, $config{'php_ini'})) {
|
|
|
|
local ($f, $d) = split(/=/, $ai);
|
2021-08-14 17:40:56 -07:00
|
|
|
foreach my $fp (split(/,/, $f)) {
|
|
|
|
foreach my $gf (glob($fp)) {
|
|
|
|
push(@rv, [ $gf, $d || $text{'file_global'} ]);
|
|
|
|
}
|
2021-08-14 13:20:46 -07:00
|
|
|
}
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach my $ai (split(/\t+/, $access{'php_inis'})) {
|
|
|
|
local ($f, $d) = split(/=/, $ai);
|
2021-08-14 17:40:56 -07:00
|
|
|
foreach my $fp (split(/,/, $f)) {
|
|
|
|
foreach my $gf (glob($fp)) {
|
|
|
|
push(@rv, [ $gf, $d || $gf ]);
|
|
|
|
}
|
2021-08-14 13:20:46 -07:00
|
|
|
}
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
2019-12-25 10:15:00 -08:00
|
|
|
foreach my $i (@rv) {
|
|
|
|
if (-d $i->[0] && -r "$i->[0]/php.ini") {
|
|
|
|
$i->[0] = "$i->[0]/php.ini";
|
|
|
|
}
|
|
|
|
}
|
2020-02-02 09:53:12 -08:00
|
|
|
if ($access{'global'} && &foreign_installed("virtual-server")) {
|
2016-04-21 21:28:40 -07:00
|
|
|
&foreign_require("virtual-server");
|
|
|
|
foreach my $v (&virtual_server::list_available_php_versions()) {
|
|
|
|
if ($v->[0]) {
|
|
|
|
my $ini = &virtual_server::get_global_php_ini($v->[0]);
|
|
|
|
push(@rv, [ $ini, "PHP $v->[0]" ]) if ($ini && -r $ini);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
my %done;
|
|
|
|
return grep { !$done{$_->[0]}++ } @rv;
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# onoff_radio(name)
|
|
|
|
# Returns a field for editing a binary configuration value
|
|
|
|
sub onoff_radio
|
|
|
|
{
|
|
|
|
local ($name) = @_;
|
|
|
|
local $v = &find_value($name, $conf);
|
|
|
|
return &ui_radio($name, lc($v) eq "on" || lc($v) eq "true" ||
|
|
|
|
lc($v) eq "yes" || $v eq "1" ? "On" : $v ? "Off" : "",
|
|
|
|
[ !$v ? ( [ "", $text{'default'} ] ) : ( ),
|
|
|
|
[ "On", $text{'yes'} ],
|
|
|
|
[ "Off", $text{'no'} ] ]);
|
|
|
|
}
|
|
|
|
|
2017-06-01 12:45:41 -07:00
|
|
|
# graceful_apache_restart([file])
|
2007-04-12 20:24:50 +00:00
|
|
|
# Signal a graceful Apache restart, to pick up new php.ini settings
|
|
|
|
sub graceful_apache_restart
|
|
|
|
{
|
2017-06-01 12:45:41 -07:00
|
|
|
local ($file) = @_;
|
2007-04-12 20:24:50 +00:00
|
|
|
if (&foreign_installed("apache")) {
|
|
|
|
&foreign_require("apache", "apache-lib.pl");
|
|
|
|
if (&apache::is_apache_running() &&
|
|
|
|
$apache::httpd_modules{'core'} >= 2 &&
|
|
|
|
&has_command($apache::config{'apachectl_path'})) {
|
|
|
|
&clean_environment();
|
|
|
|
&system_logged("$apache::config{'apachectl_path'} graceful >/dev/null 2>&1");
|
|
|
|
&reset_environment();
|
|
|
|
}
|
|
|
|
}
|
2017-06-01 12:45:41 -07:00
|
|
|
if ($file && &get_config_fmt($file) eq "fpm" &&
|
|
|
|
&foreign_check("virtual-server")) {
|
|
|
|
# Looks like FPM format ... maybe a pool restart is needed
|
|
|
|
&foreign_require("virtual-server");
|
|
|
|
if (defined(&virtual_server::restart_php_fpm_server)) {
|
2022-02-06 20:35:29 +03:00
|
|
|
my $conf;
|
|
|
|
if (-r $file) {
|
|
|
|
my @conf;
|
2022-02-06 13:35:52 -08:00
|
|
|
@conf = grep { &is_under_directory($_->{'dir'}, $file) }
|
|
|
|
&virtual_server::list_php_fpm_configs();
|
|
|
|
if (@conf) {
|
|
|
|
$conf = &virtual_server::get_php_fpm_config(
|
|
|
|
$conf[0]->{'shortversion'});
|
|
|
|
}
|
2022-02-06 20:35:29 +03:00
|
|
|
}
|
2017-06-01 12:45:41 -07:00
|
|
|
&virtual_server::push_all_print();
|
|
|
|
&virtual_server::set_all_null_print();
|
2022-02-06 20:35:29 +03:00
|
|
|
&virtual_server::restart_php_fpm_server($conf);
|
2017-06-01 12:45:41 -07:00
|
|
|
&virtual_server::pop_all_print();
|
|
|
|
}
|
|
|
|
}
|
2022-09-16 18:45:27 +03:00
|
|
|
if ($file && &get_config_fmt($file) eq "ini" &&
|
|
|
|
&foreign_installed("virtual-server") &&
|
|
|
|
&foreign_installed("virtualmin-nginx")) {
|
|
|
|
&foreign_require("virtual-server");
|
|
|
|
&foreign_require("virtualmin-nginx", "virtual_feature.pl");
|
|
|
|
my @dom = grep { $file =~ /^$_->{'home'}\// }
|
|
|
|
&virtual_server::list_domains();
|
|
|
|
&virtualmin_nginx::feature_restart_web_php($dom[0]);
|
|
|
|
}
|
2007-04-12 20:24:50 +00:00
|
|
|
}
|
|
|
|
|
2009-07-02 23:51:56 +00:00
|
|
|
# get_config_as_user([file])
|
|
|
|
# Like get_config, but reads with permissions of the ACL user
|
|
|
|
sub get_config_as_user
|
|
|
|
{
|
|
|
|
local ($file) = @_;
|
|
|
|
if ($access{'user'} && $access{'user'} ne 'root' && $< == 0) {
|
|
|
|
local $rv = &eval_as_unix_user(
|
|
|
|
$access{'user'}, sub { &get_config($file) });
|
|
|
|
if ((!$rv || !@$rv) && $!) {
|
|
|
|
&error(&text('file_eread', &html_escape($file), $!));
|
|
|
|
}
|
|
|
|
return $rv;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return &get_config($file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 21:26:10 -07:00
|
|
|
# read_file_contents_as_user(file)
|
|
|
|
sub read_file_contents_as_user
|
|
|
|
{
|
|
|
|
local ($file) = @_;
|
|
|
|
if ($access{'user'} && $access{'user'} ne 'root' && $< == 0) {
|
|
|
|
return &eval_as_unix_user(
|
|
|
|
$access{'user'}, sub { &read_file_contents($file) });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return &read_file_contents($file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# write_file_contents_as_user(file, data)
|
|
|
|
# Writes out the contents of some file
|
|
|
|
sub write_file_contents_as_user
|
|
|
|
{
|
|
|
|
local ($file, $data) = @_;
|
|
|
|
if ($access{'user'} && $access{'user'} ne 'root' && $< == 0) {
|
|
|
|
return &eval_as_unix_user(
|
|
|
|
$access{'user'}, sub { &write_file_contents($file, $data) });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
&write_file_contents($file, $data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 23:00:35 -07:00
|
|
|
# read_file_lines_as_user(file, ...)
|
|
|
|
sub read_file_lines_as_user
|
|
|
|
{
|
|
|
|
local @args = @_;
|
|
|
|
if ($access{'user'} && $access{'user'} ne 'root' && $< == 0) {
|
|
|
|
return &eval_as_unix_user(
|
|
|
|
$access{'user'}, sub { &read_file_lines(@args) });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return &read_file_lines(@args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 23:51:56 +00:00
|
|
|
# flush_file_lines_as_user(file)
|
|
|
|
# Writes out a file as the Unix user configured in this module's ACL
|
|
|
|
sub flush_file_lines_as_user
|
|
|
|
{
|
2020-09-30 12:00:06 +03:00
|
|
|
local ($file, $eof, $ignore) = @_;
|
2009-07-02 23:51:56 +00:00
|
|
|
if ($access{'user'} && $access{'user'} ne 'root' && $< == 0) {
|
|
|
|
&eval_as_unix_user($access{'user'},
|
2020-09-30 12:00:06 +03:00
|
|
|
sub { &flush_file_lines($file, $eof, $ignore) });
|
2009-07-02 23:51:56 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-09-30 12:00:06 +03:00
|
|
|
&flush_file_lines($file, $eof, $ignore);
|
2009-07-02 23:51:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-12 20:24:50 +00:00
|
|
|
1;
|
|
|
|
|