<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Functions for managing the PHP configuration file

BEGIN { push(@INC, ".."); };
use WebminCore;
&amp;init_config();
%access = &amp;get_module_acl();

# 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";
}

# get_config([file])
# Returns an array ref of PHP configuration directives from some file 
sub get_config
{
local ($file) = @_;
$file ||= &amp;get_default_php_ini();
local $fmt = &amp;get_config_fmt($file);
if (!defined($get_config_cache{$file})) {
	local @rv = ( );
	local $lnum = 0;
	local $section;
	open(CONFIG, $file) || return undef;
	if ($fmt eq "ini") {
		# Classic php.ini format
		while(&lt;CONFIG&gt;) {
			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' =&gt; $2,
					    'value' =&gt; $3,
					    'enabled' =&gt; !$1,
					    'line' =&gt; $lnum,
					    'file' =&gt; $file,
					    'section' =&gt; $section,
					    'fmt' =&gt; $fmt,
					  });
				if ($uq) {
					# Remove any comments
					$rv[$#rv]-&gt;{'value'} =~ s/\s+;.*$//;
					}
				}
			elsif (/^\[(.*)\]/) {
				# A new section
				$section = $1;
				}
			$lnum++;
			}
		}
	else {
		# FPM config file format, with php options
		while(&lt;CONFIG&gt;) {
			s/\r|\n//g;
			s/\s+$//;
			if (/^(;?)php_admin_value\[(\S+)\]\s*=\s*(.*)/) {
				# Found an FPM config that sets a PHP variable
				push(@rv, { 'name' =&gt; $2,
					    'value' =&gt; $3,
					    'enabled' =&gt; !$1,
					    'line' =&gt; $lnum,
					    'file' =&gt; $file,
					    'fmt' =&gt; $fmt,
					  });
				}
			$lnum++;
			}
		}
	close(CONFIG);
	$get_config_cache{$file} = \@rv;
	}
return $get_config_cache{$file};
}

# find(name, &amp;config, [disabled-mode])
# Look up a directive by name
sub find
{
local ($name, $conf, $mode) = @_;
local @rv = grep { lc($_-&gt;{'name'}) eq lc($name) &amp;&amp;
		   ($mode == 0 &amp;&amp; $_-&gt;{'enabled'} ||
		    $mode == 1 &amp;&amp; !$_-&gt;{'enabled'} ||
		    $mode == 2) } @$conf;
return wantarray ? @rv : $rv[0];
}

sub find_value
{
local @rv = map { $_-&gt;{'value'} } &amp;find(@_);
return $rv[0];
}

# save_directive(&amp;config, name, [value], [newsection], [neverquote])
# Updates a single entry in the PHP config file
sub save_directive
{
local ($conf, $name, $value, $newsection, $noquote) = @_;
$newsection ||= "PHP";
local $old = &amp;find($name, $conf, 0);
local $cmt = &amp;find($name, $conf, 1);
local $fmt = $old ? $old-&gt;{'fmt'} : @$conf ? $conf-&gt;[0]-&gt;{'fmt'} : "fpm";
local $lref;
if ($fmt eq "ini") {
	$newline = $name." = ".
		   ($value !~ /\s/ || $noquote ? $value :
		    $value =~ /"/ ? "'$value'" : "\"$value\"");
	}
else {
	$newline = "php_admin_value[".$name."] = ".$value;
	}
if (defined($value) &amp;&amp; $old) {
	# Update existing value
	$lref = &amp;read_file_lines($old-&gt;{'file'});
	$lref-&gt;[$old-&gt;{'line'}] = $newline;
	$old-&gt;{'value'} = $value;
	}
elsif (defined($value) &amp;&amp; !$old &amp;&amp; $cmt) {
	# Update existing commented value
	$lref = &amp;read_file_lines($cmt-&gt;{'file'});
	$lref-&gt;[$cmt-&gt;{'line'}] = $newline;
	$cmt-&gt;{'value'} = $value;
	$cmt-&gt;{'enabled'} = 1;
	}
elsif (defined($value) &amp;&amp; !$old &amp;&amp; !$cmt) {
	# Add a new value, at the end of the section
	my ($lastline, $lastfile);
	if ($fmt eq "ini") {
		# Find last directive in requested php.ini section
		my $last;
		foreach my $c (@$conf) {
			if ($c-&gt;{'section'} eq $newsection) {
				$last = $c;
				}
			}
		$last || &amp;error("Could not find any values in ".
				"section $newsection");
		$lastfile = $last-&gt;{'file'};
		$lastline = $last-&gt;{'line'};
		$lref = &amp;read_file_lines($lastfile);
		}
	else {
		# Just add at the end
		$lastfile = @$conf ? $conf-&gt;[0]-&gt;{'file'} : undef;
		$lastfile || &amp;error("Don't know which file to add to");
		$lref = &amp;read_file_lines($lastfile);
		$lastline = scalar(@$lref);
		}

	# Found last value in the section - add after it
	splice(@$lref, $lastline+1, 0, $newline);
	&amp;renumber($conf, $lastline, 1);
	push(@$conf, { 'name' =&gt; $name,
		       'value' =&gt; $value,
		       'enabled' =&gt; 1,
		       'file' =&gt; $lastfile,
		       'line' =&gt; $lastline+1,
		       'section' =&gt; $newsection,
		     });
	}
elsif (!defined($value) &amp;&amp; $old &amp;&amp; $cmt) {
	# Totally remove a value
	$lref = &amp;read_file_lines($old-&gt;{'file'});
	splice(@$lref, $old-&gt;{'line'}, 1);
	@$conf = grep { $_ ne $old } @$conf;
	&amp;renumber($conf, $old-&gt;{'line'}, -1);
	}
elsif (!defined($value) &amp;&amp; $old &amp;&amp; !$cmt) {
	# Turn a value into a comment
	$lref = &amp;read_file_lines($old-&gt;{'file'});
	$old-&gt;{'enabled'} = 0;
	$lref-&gt;[$old-&gt;{'line'}] = "; ".$lref-&gt;[$old-&gt;{'line'}];
	}
}

sub renumber
{
local ($conf, $line, $oset) = @_;
foreach my $c (@$conf) {
	$c-&gt;{'line'} += $oset if ($c-&gt;{'line'} &gt; $line);
	}
}

# can_php_config(file)
# Returns 1 if some config file can be edited
sub can_php_config
{
local ($file) = @_;
return &amp;indexof($file, map { $_-&gt;[0] } &amp;list_php_configs()) &gt;= 0 ||
       $access{'anyfile'};
}

# get_default_php_ini()
# Returns the first php.ini that exists
sub get_default_php_ini
{
local @inis = split(/\t+/, $config{'php_ini'});
foreach my $ai (@inis) {
	local ($f, $d) = split(/=/, $ai);
	return $f if (-r $f);
	}
if (-r $config{'alt_php_ini'} &amp;&amp; @inis) {
	# Fall back to default file
	local ($f) = split(/=/, $inis[0]);
	&amp;copy_source_dest($config{'alt_php_ini'}, $f);
	return $f;
	}
return undef;
}

# list_php_configs()
# Returns a list of allowed config files and descriptions
sub list_php_configs
{
local @rv;
&amp;get_default_php_ini();		# Force copy of sample ini file
if ($access{'global'}) {
	foreach my $ai (split(/\t+/, $config{'php_ini'})) {
		local ($f, $d) = split(/=/, $ai);
		push(@rv, [ $f, $d || $text{'file_global'} ]);
		}
	}
foreach my $ai (split(/\t+/, $access{'php_inis'})) {
	local ($f, $d) = split(/=/, $ai);
	push(@rv, [ $f, $d || $f ]);
	}
if (&amp;foreign_installed("virtual-server")) {
	&amp;foreign_require("virtual-server");
	foreach my $v (&amp;virtual_server::list_available_php_versions()) {
		if ($v-&gt;[0]) {
			my $ini = &amp;virtual_server::get_global_php_ini($v-&gt;[0]);
			push(@rv, [ $ini, "PHP $v-&gt;[0]" ]) if ($ini &amp;&amp; -r $ini);
			}
		}
	}
my %done;
return grep { !$done{$_-&gt;[0]}++ } @rv;
}

# onoff_radio(name)
# Returns a field for editing a binary configuration value
sub onoff_radio
{
local ($name) = @_;
local $v = &amp;find_value($name, $conf);
return &amp;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'} ] ]);
}

# graceful_apache_restart([file])
# Signal a graceful Apache restart, to pick up new php.ini settings
sub graceful_apache_restart
{
local ($file) = @_;
if (&amp;foreign_installed("apache")) {
	&amp;foreign_require("apache", "apache-lib.pl");
	if (&amp;apache::is_apache_running() &amp;&amp;
	    $apache::httpd_modules{'core'} &gt;= 2 &amp;&amp;
	    &amp;has_command($apache::config{'apachectl_path'})) {
		&amp;clean_environment();
		&amp;system_logged("$apache::config{'apachectl_path'} graceful &gt;/dev/null 2&gt;&amp;1");
		&amp;reset_environment();
		}
	}
if ($file &amp;&amp; &amp;get_config_fmt($file) eq "fpm" &amp;&amp;
    &amp;foreign_check("virtual-server")) {
	# Looks like FPM format ... maybe a pool restart is needed
	&amp;foreign_require("virtual-server");
	if (defined(&amp;virtual_server::restart_php_fpm_server)) {
		&amp;virtual_server::push_all_print();
		&amp;virtual_server::set_all_null_print();
		&amp;virtual_server::restart_php_fpm_server();
		&amp;virtual_server::pop_all_print();
		}
	}
}

# 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'} &amp;&amp; $access{'user'} ne 'root' &amp;&amp; $&lt; == 0) {
	local $rv = &amp;eval_as_unix_user(
		$access{'user'}, sub { &amp;get_config($file) });
	if ((!$rv || !@$rv) &amp;&amp; $!) {
		&amp;error(&amp;text('file_eread', &amp;html_escape($file), $!));
		}
	return $rv;
	}
else {
	return &amp;get_config($file);
	}
}

# read_file_contents_as_user(file)
sub read_file_contents_as_user
{
local ($file) = @_;
if ($access{'user'} &amp;&amp; $access{'user'} ne 'root' &amp;&amp; $&lt; == 0) {
	return &amp;eval_as_unix_user(
		$access{'user'}, sub { &amp;read_file_contents($file) });
	}
else {
	return &amp;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'} &amp;&amp; $access{'user'} ne 'root' &amp;&amp; $&lt; == 0) {
	return &amp;eval_as_unix_user(
                $access{'user'}, sub { &amp;write_file_contents($file, $data) });
	}
else {
	&amp;write_file_contents($file, $data);
	}
}

# 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
{
local ($file) = @_;
if ($access{'user'} &amp;&amp; $access{'user'} ne 'root' &amp;&amp; $&lt; == 0) {
	&amp;eval_as_unix_user($access{'user'}, 
		sub { &amp;flush_file_lines($file) });
	}
else {
	&amp;flush_file_lines($file);
	}
}

1;

</pre></body></html>