#!/usr/bin/perl # 2021-08-02 use strict; use warnings; use utf8; use Getopt::Long; use File::Slurp; use Data::Dumper; my $self; sub sys { my $cmd = shift; my %opts = @_; $opts{die} = 1 if !defined $opts{die}; #print "++ $cmd\n"; system $cmd; if ($? == -1) { die "-- $cmd\nfailed to execute: $!\n"; } elsif ($? & 127) { my $signal = $? & 127; die "-- $cmd\nchild died with signal $signal\n"; } my $ex = $? >> 8; if ($ex > 0 and $opts{die}) { print STDERR "-- $cmd\nexit code $ex\n"; print STDERR "Continue? [y/N]\n"; my $ans = ; exit 1 if $ans !~ /^y/i; } return $ex; } sub fpmconf { my $dir = "$self->{phpconfdir}/fpm/pool.d"; my $fn = "$dir/$self->{site}.conf"; if (!-d $dir) { die "error: directory `$dir' doesn't exist\n"; } if (-e $fn and !$self->{force_overwrite}) { print "$fn already exists; use --force-overwrite to overwrite\n"; return; } my $conf = <{site}] user = $self->{user} group = $self->{group} listen = /run/php/php$self->{php}-fpm-$self->{site}.sock listen.owner = www-data listen.group = www-data pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 php_admin_value[open_basedir] = $self->{siteroot} php_admin_value[sys_temp_dir] = $self->{siteroot}/tmp php_admin_value[upload_tmp_dir] = $self->{siteroot}/tmp php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,dl,setenv EOT write_file($fn, $conf); print "$fn written, reloading fpm service.\n"; sys "systemctl reload php$self->{php}-fpm.service"; } sub fpmconf_find { my %conf; for my $ver (glob("$self->{phpconfbase}/[0-9]*")) { $ver =~ s/^.*\///; next if $ver !~ /^\d[\d.]+$/; my $fn = "$self->{phpconfbase}/$ver/fpm/pool.d/$self->{site}.conf"; if (-e $fn) { $conf{$ver} = $fn; } } return %conf; } sub fpmconf_list { my %conf = fpmconf_find; for my $ver (sort keys %conf) { print "$ver -> $conf{$ver}\n"; } } sub fpmconf_remove_other { my %conf = fpmconf_find; for my $ver (sort keys %conf) { next if $ver eq $self->{php}; if ($self->{keep_other}) { print "keeping php $ver pool conf: $conf{$ver}\n"; next; } if (!unlink($conf{$ver})) { print "error: could not delete $conf{$ver}\n"; next; } print "$conf{$ver} removed, reloading php$ver-fpm\n"; sys "systemctl reload php$ver-fpm.service"; } } sub apacheconf { my @oldconf = read_file($self->{apachecf}); my @newconf; my @phpblock = ( qq{}, qq{ SetHandler "proxy:unix:/run/php/php$self->{php}-fpm-$self->{site}.sock|fcgi://localhost"}, qq{} ); my $found = 0; for (my $i = 0; $i <= $#oldconf; $i++) { my $line = $oldconf[$i]; push @newconf, $line; if ($line !~ /^(\s*)#-\[\[-www-phpfpm/) { next; } my $indent = $1; while ($oldconf[$i] !~ /^\s*#-]]-www-phpfpm/) { $i++; if ($i >= $#oldconf) { die "error: block without end found in: $self->{apachecf}\n"; } } for my $bl (@phpblock) { push @newconf, "$indent$bl\n"; } push @newconf, $oldconf[$i]; $found = 1; } if (!$found) { die "no #-[[-www-phpfpm block found in: $self->{apachecf}\n"; } write_file($self->{apachecf}, @newconf); print "$self->{apachecf} written, reloading apache\n"; sys "systemctl reload apache2.service"; } $self = { site => "", php => undef, phpconfbase => '/etc/php', phpconfdir => undef, force_overwrite => 0, keep_other => 0, list => 0, delete => 0, }; my $usage = < \$self->{site}, "php|p=s" => \$self->{php}, "force-overwrite|f" => \$self->{force_overwrite}, "keep-other|k" => \$self->{keep_other}, "list|l" => \$self->{list}, "delete|d" => \$self->{delete}, 'help|h' => sub { print $usage; exit 0 } ) or die $usage; if (!$self->{site}) { die "no site name given\n$usage"; } if ($self->{site} !~ /^[a-z][a-z0-9]*$/) { die "site contains invalid characters: $self->{site}\n"; } if ($self->{list}) { fpmconf_list; exit; } if ($self->{delete}) { if ($self->{keep_other} or $self->{force_overwrite} or $self->{list} or $self->{php}) { die "--delete incompatible with other options\n"; } $self->{php} = '..invalid..'; fpmconf_remove_other; exit; } if (!$self->{php}) { die "no PHP version given\n$usage"; } if ($self->{php} !~ /^\d[\d\.]+$/) { die "invalid PHP version given: $self->{php}\n$usage"; } $self->{siteroot} = "/www/$self->{site}"; $self->{apachecf} = "/etc/apache2/sites-enabled/$self->{site}.conf"; $self->{user} = "www-$self->{site}"; $self->{group} = $self->{user}; $self->{dbname} = $self->{site}; $self->{dbuser} = $self->{site}; $self->{phpconfdir} = "$self->{phpconfbase}/$self->{php}"; if (!-d $self->{siteroot}) { die "site doesn't exist: directory `$self->{siteroot}' not found\n"; } if (!-d $self->{phpconfdir}) { die "php configuration directory doesn't exist: $self->{phpconfdir}\n"; } fpmconf; apacheconf; fpmconf_remove_other; # vim: set tabstop=4 shiftwidth=4 expandtab smarttab: