Mini Shell
#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - ea_sync_user_phpini_settings Copyright 2017 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
package ea_sync_user_phpini_settings;
use strict;
use Cpanel::Config::Httpd ();
use Getopt::Param::Tiny ();
use Cpanel::PwCache ();
use Cpanel::AccessIds ();
use Cwd ();
use Path::Iter ();
use Cpanel::ProgLang ();
use Cpanel::ArrayFunc::Uniq ();
use Cpanel::Version ();
#### barf ##
# <facepalm> paths before ULC in INC can cause the user-run-code to error out with things like:
# Can't locate Cpanel/Exception/CORE.pm: /root/perl5/lib/perl5//x86_64-linux-64int/Cpanel/Exception/CORE.pm: Permission denied at /usr/local/cpanel/Cpanel/Exception.pm line 43.
# Can't locate Cpanel/Carp.pm: /root/perl5/lib/perl5//x86_64-linux-64int/Cpanel/Carp.pm: Permission denied at (eval .*) line 1.
# etc, on and on down the rabbit hole depending on how you try to hack around it
while ( $INC[0] ne '/usr/local/cpanel' ) { shift @INC }
#### /barf ##
our ( $php_version_info, $php, $ini_hr );
exit( run(@ARGV) ) unless caller;
sub run {
my (@args) = @_;
die "This script can only be run by root\n" if $> != 0;
die "This script only operates when you are under EasyApache 4\n" if !Cpanel::Config::Httpd::is_ea4();
# Handle v58 grossfully (not a typo)
eval 'require Cpanel::PHP::Config;';
if ( $@ || !defined &Cpanel::Version::get_short_release_number || Cpanel::Version::get_short_release_number() < 62 ) {
print "Nothing to do (only applies to v64 and newer)\n";
exit(0);
}
my $param = Getopt::Param::Tiny->new( { array_ref => \@args, help_coderef => \&_help, known_only => [ 'user', 'all-users' ], no_args_help => 1, validate => \&_validate, } );
my $starting_dir = Cwd::cwd();
$php_version_info = Cpanel::PHP::Config::get_php_version_info();
die "There are no PHP packages installed via ea4\n" if !@{ $php_version_info->{versions} };
$php = Cpanel::ProgLang->new( type => 'php' );
$ini_hr = {};
my @users;
if ( $param->param('all-users') ) {
require Cpanel::Config::LoadUserDomains;
require Cpanel::PwCache;
Cpanel::PwCache::Build::init_passwdless_pwcache();
my %user_map = Cpanel::Config::LoadUserDomains::loaduserdomains( undef, 0, 1 );
@users = sort keys %user_map;
}
else {
@users = $param->param('user');
}
for my $user (@users) {
print "Operating on “$user” …\n";
_process_user($user);
print " … done!\n";
}
chdir($starting_dir) or die "Could not chdir back to $starting_dir: $!\n";
return 0; # exit clean
}
###############
#### helpers ##
###############
sub _process_user {
my ($user) = @_;
my $user_ar = [ Cpanel::PwCache::getpwnam($user) ];
my $user_homedir = $user_ar->[7];
my $user_php = Cpanel::PHP::Config::get_php_config_for_users( [$user] );
my $user_dir_to_package_map = {};
for my $dom ( sort keys %{$user_php} ) {
next if exists $user_dir_to_package_map->{ $user_php->{$dom}{documentroot} };
$user_dir_to_package_map->{ $user_php->{$dom}{documentroot} } = $user_php->{$dom}{phpversion};
}
my $count = Cpanel::AccessIds::do_as_user( $user, sub { return _proc_dir( $user_homedir, $user_dir_to_package_map ) } );
if ( !$count->{errors} && !$count->{processed} ) {
print "\tNo php.ini files found.\n";
}
else {
$count->{processed} ||= 0;
$count->{errors} ||= 0;
print "\tSuccessfully processed php.ini files: $count->{processed}\n";
print "\tphp.ini files that had errors during processing: $count->{errors}\n";
}
}
sub _proc_dir {
my ( $user_homedir, $user_dir_to_package_map ) = @_;
my $count;
chdir($user_homedir) or die "failed to chdir($user_homedir): $!\n";
my @errors;
my $fetch = Path::Iter::get_iterator( '.', { stop_when_opendir_fails => 1, errors => \@errors } );
while ( my $next_path = $fetch->() ) {
if ( $next_path =~ m{(?:^|/)php\.ini$} ) {
print "\tProcessing $user_homedir/$next_path …\n";
eval {
my $path_parent = $next_path;
$path_parent =~ s{/?php\.ini$}{};
my $package = $user_dir_to_package_map->{ $path_parent ? "$user_homedir/$path_parent" : $user_homedir } || $php_version_info->{default};
$ini_hr->{$package} ||= $php->get_ini( 'package' => $package );
$ini_hr->{$package}->set_directives( path => $next_path, directives => { _ea_sync_user_phpini_settings => 1 }, userfiles => 1 );
};
if ($@) {
warn "ERROR: $@\n" if $@;
$count->{errors}++;
}
else {
$count->{processed}++;
}
print "\t … done!\n";
}
}
if (@errors) {
warn "\tThe following errors occured while traversing “$user_homedir” (some php.ini files may not have been processed):\n";
for my $err (@errors) {
warn "\t\t$err->{function}(" . join( ", ", @{ $err->{args} } ) . ") – $err->{error}\n";
}
}
return $count;
}
sub _validate {
my ($param) = @_;
my $ok = 1; # innocnent until proven guilty ;)
my @users = $param->param('user');
my $all = $param->param('all-users');
if ( $all && @users ) {
warn "You cannot specifiy both --all-users and --user options.\n";
$ok = 0;
}
if ( grep m/^(?:--user|)$/, @users ) {
warn "--user requires a value (--user=<USER>)\n";
$ok = 0;
}
if ( @users > Cpanel::ArrayFunc::Uniq::uniq(@users) ) {
warn "Each <USER> must be unique!\n";
$ok = 0;
}
for my $user ( Cpanel::ArrayFunc::Uniq::uniq(@users) ) {
next if $user =~ m/^(?:--user|)$/; # already looked for this once
if ( !Cpanel::PwCache::getpwnam($user) ) {
warn "“$user” is not a user on this system\n";
$ok = 0;
}
}
return 1 if $ok;
return;
}
sub _help {
my ($param) = @_;
print <<"END_HELP";
Usage: $0 --user=<USER> [--user=<USER2> [--user=<USER3> …]] | --all-users
For given users sync any php.ini files in their home directory to corresponding .user.ini and, on some versions, .htaccess.
Options:
--help this screen
--user=<USERS> specify the user to operate on, may be given more than once
--all-users process all users
END_HELP
exit( $param->param('help') ? 0 : 1 );
}
1;
Zerion Mini Shell 1.0