????

Your IP : 18.119.102.46


Current Path : /scripts/
Upload File :
Current File : //scripts/phpextensionmgr

#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - scripts/phpextensionmgr                   Copyright 2014 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;

use Cpanel::YAML::Syck                   ();
use Cpanel::CachedDataStore              ();
use Cpanel::Config::LoadCpConf           ();
use Cpanel::Config::CpConfGuard          ();
use Cpanel::Config::Httpd::EA4           ();
use Cpanel::Config::Sources              ();
use Cpanel::ConfigFiles::Apache          ();
use Cpanel::HttpUtils::ApRestart::BgSafe ();
use Cpanel::Crypt::GPG::Settings         ();
use Cpanel::HttpRequest                  ();
use Cpanel::Logger                       ();
use Cpanel::OSSys                        ();
use Cpanel::SafeDir::RM                  ();
use Cpanel::SafeRun::Errors              ();
use Cpanel::Sync::Digest                 ();

my $help;
my $prefix;
my $action;
my $extension;
my $local_tarball;    # From cmd line, for testing new tarball, circumvents tarball download. Warning: bypasses md5 sum check

# This script does not work properly with EA4 right now
if ( Cpanel::Config::Httpd::EA4::is_ea4() ) {
    die "This script is not supported in EasyApache 4 at this time\n";
}

my $apacheconf = Cpanel::ConfigFiles::Apache->new();

my %extensions = (
    'Zendopt'        => 'binary',
    'PHPSuHosin'     => 'source',
    'IonCubeLoader'  => 'binary',
    'SourceGuardian' => 'binary',
    'EAccelerator'   => 'source',
    'Xcache'         => 'source',
);

GetOptions( 'help' => \$help, 'prefix=s' => \$prefix, 'local-tarball=s' => \$local_tarball );

$action    = shift || ( $help = 1 );
$action    = lc($action);
$extension = shift || ( $help = 1 );

if ( $action eq 'list' ) {
    print "Available Extensions:\n";
    print join( "\n", keys %extensions );
    print "\n";
    exit;
}
elsif ( !$help && $action ne 'status' && $action ne 'install' && $action ne 'uninstall' ) {
    print "Invalid action specified\n";
    $help = 1;
}

pod2usage(1) if $help;

if ( $> != 0 ) {
    print "This script must be run by the root user.\n";
    exit 1;
}

# check that extension is in list
my $found = 0;
foreach my $avail_ext ( keys %extensions ) {
    if ( lc($extension) eq lc($avail_ext) ) {
        $extension = $avail_ext;
        $found     = 1;
        last;
    }
}

unless ($found) {
    print "Extension ${extension} is not supported\n";
    exit 1;
}

if ( $prefix && $prefix =~ m{(?:/usr/local/cpanel/3rdparty|/var/cpanel/3rdparty)} ) {

    my $deprecate_msg = qq{The prefix $prefix is deprecated. Please see the documentation at: https://go.cpanel.net/1136phpextensionmgr};
    print $deprecate_msg, "\n";
    Cpanel::Logger->new->deprecated($deprecate_msg);

    if ( $extension !~ m{(?:IonCubeLoader|Zendopt|SourceGuardian)} ) {
        my $unsupported_msg = "The extension `$extension' is not supported for internal PHP.";
        local $SIG{__DIE__} = sub { exit 1; };
        Cpanel::Logger->new->die($unsupported_msg);
    }

    my %extensions_cpcfg = (qw/ Zendopt zend IonCubeLoader ioncube SourceGuardian sourceguardian /);
    my $cpconf_ref       = Cpanel::Config::LoadCpConf::loadcpconf();

    my %php_loaders = map { ( $_ => 1 ) } split( /,/, $cpconf_ref->{'phploader'} );

    # Verify that extention to be installed is not already configured
    my @extensions_cpcfg = values(%extensions_cpcfg);

    # Get the proper value needed for $cpconf_ref
    my $extension_cpcfg = $extensions_cpcfg{$extension};

    if ( $action eq 'install' ) {
        if ( $php_loaders{$extension_cpcfg} ) {
            print "$extension_cpcfg is already enabled for internal PHP\n";
            exit 3;
        }
        $php_loaders{$extension_cpcfg} = 1;
    }
    elsif ( $action eq 'uninstall' ) {
        if ( !$php_loaders{$extension_cpcfg} ) {
            print "$extension_cpcfg is not enabled for internal PHP\n";
            exit 3;
        }
        delete $php_loaders{$extension_cpcfg};
    }
    elsif ( $action eq 'status' ) {
        print 'Installed extensions for internal PHP: ' . $cpconf_ref->{'phploader'} . "\n";
        exit 2;
    }
    else {
        # Should never be able to get here.
        die("Unsupported action");
    }

    # Assure none is only saved if nothing else is selected.
    delete $php_loaders{'none'};
    if ( !%php_loaders ) {
        $php_loaders{'none'} = 1;
    }

    # Write cpanel.config
    require Cpanel::Config::CpConfGuard;
    my $cpconf_guard = Cpanel::Config::CpConfGuard->new() or die("Failed to load cpanel config file: $!");
    $cpconf_guard->{'data'}->{'phploader'} = join( ',', keys(%php_loaders) );
    $cpconf_guard->save();

    if ( exists $php_loaders{'sourceguardian'} ) {
        if ( -e '/var/cpanel/disablesourceguardian' ) {
            unlink '/var/cpanel/disablesourceguardian';
        }
    }

    # Update the php.ini with to use extensions
    system '/usr/local/cpanel/bin/checkphpini';
    system '/usr/local/cpanel/bin/install_php_inis';

    print "$extension_cpcfg has been " . ( $action eq 'install' ? 'installed' : 'uninstalled' ) . "\n";

    exit 2;
}

my $tarball_filename = $local_tarball || get_tarball_filename( $extension, \%extensions );

# setup working directory

my $home = -d '/usr/home' ? '/usr/home' : '/home';
mkdir $home . '/cpeasyapache'               unless -d $home . '/cpeasyapache';
mkdir $home . '/cpeasyapache/phpextensions' unless -d $home . '/cpeasyapache/phpextensions';
unless ( -d $home . '/cpeasyapache/phpextensions' ) {
    die "Could not mkdir $home/cpeasyapache/phpextensions";
}

chdir $home . '/cpeasyapache/phpextensions' or die "Could not chdir to $home/cpeasyapache/phpextensions: $!";

# download tarball
download_tarball_if_needed($tarball_filename) if !$local_tarball;

# make certain php.ini is available for installations
if ( $action eq 'install' ) {
    if ($prefix) {
        system( '/usr/local/cpanel/scripts/updatephpconf', $prefix );
    }
    else {
        system('/usr/local/cpanel/scripts/updatephpconf');
    }
}

# untar
my $file_list = Cpanel::SafeRun::Errors::saferunnoerror( 'tar', 'tfz', $tarball_filename );
my @FILES = split( /\n/, $file_list, 2 );
my $extension_dir = $FILES[0];

unless ( $extension_dir =~ m{[^\./]+[^/]*/?} ) {
    die "Extension directory in downloaded tarball appears to be invalid: $extension_dir";
}

if ( -d $extension_dir ) {

    # unlink the exististing directory
    Cpanel::SafeDir::RM::safermdir($extension_dir);
}

Cpanel::SafeRun::Errors::saferunallerrors( 'tar', 'xzf', $tarball_filename );

# cd
chdir $extension_dir or die "Could not chdir into $extension_dir: $!";

# execute ./cpanel-install (prefix)
my @cmd           = ();
my $maybe_restart = 0;
if ( $action eq 'install' ) {
    print "Installing $extension\n";
    @cmd           = ('./cpanel-install');
    $maybe_restart = 1;
}
elsif ( $action eq 'uninstall' ) {
    print "Uninstalling $extension\n";
    @cmd           = ('./cpanel-uninstall');
    $maybe_restart = 1;
}
else {
    print "Determining status of $extension\n";
    @cmd = ('./cpanel-status');
}

push @cmd, $prefix if $prefix;
system(@cmd);

if ($maybe_restart) {
    my $phpopts = Cpanel::CachedDataStore::fetch_ref( $apacheconf->file_conf_php_conf() . '.yaml' );
    $phpopts = { 'phpversion' => undef } unless $phpopts;

    # If phpversion isn't set, the default is that php5 is dso.
    if ( !$phpopts->{'phpversion'} || $phpopts->{'php5'} eq 'dso' || $phpopts->{'php4'} eq 'dso' ) {
        Cpanel::HttpUtils::ApRestart::BgSafe::restart();
    }
}

# cleanup?

sub get_tarball_filename {
    my $extension      = shift;
    my $extensions_ref = shift;
    my $filename       = $extension . '.pm.tar.gz';

    if ( $extensions_ref->{$extension} eq 'source' ) {
        return $filename;
    }

    my ( $system, $release, $machine ) = ( Cpanel::OSSys::uname() )[ 0, 2, 4 ];
    $system  = 'linux';
    $release = 'generic';
    if ( $machine =~ /64/i ) {
        $machine = '64';
    }
    else {
        $machine = '32';
    }

    return $filename . ".$system-$release-$machine";
}

sub download_tarball_if_needed {
    my $tarball_filename = shift;
    my $httpClient = Cpanel::HttpRequest->new( 'hideOutput' => 0 );

    if ( !-e 'targz.yaml' || ( stat(_) )[9] < time() - 24 * 60 * 60 ) {
        print "Updating digest list\n";
        my $sources = Cpanel::Config::Sources::loadcpsources();

        # Download signed targz.yaml
        $httpClient->download( 'http://' . $sources->{'HTTPUPDATE'} . "/cpanelsync/easy/targz.yaml", 'targz.yaml', 1 );
        die "Could not download targz.yaml" unless -e 'targz.yaml';

        system('touch targz.yaml');    # make sure mtime is updated
    }

    my ( $targz_md5s, $targz_sha512s ) = eval { YAML::Syck::LoadFile('targz.yaml'); };

    if ( !( $targz_md5s || $targz_sha512s ) ) {
        die "Couldn't load targz.yaml: $!";
    }

    my $tarball_ea_dir      = '/var/cpanel/perl/easy/Cpanel/Easy/';
    my $tarball_ea_fullpath = $tarball_ea_dir . $tarball_filename;

    my %tarball_digests = (
        md5    => $targz_md5s->{$tarball_ea_fullpath},
        sha512 => $targz_sha512s->{$tarball_ea_fullpath},
    );

    if ( ( -e $tarball_filename ) && _digest_file_match( \%tarball_digests, $tarball_filename ) ) {

        # Local copy available...good to go.
        return;
    }
    elsif ( ( -e $tarball_ea_fullpath ) && _digest_file_match( \%tarball_digests, $tarball_ea_fullpath ) ) {

        # EA3 copy available
        unlink $tarball_filename if ( -e $tarball_filename );
        system( 'cp', $tarball_ea_fullpath, $tarball_filename );
    }
    else {
        print "Downloading tarball for $extension\n";
        my $sources = Cpanel::Config::Sources::loadcpsources();
        $httpClient->download( 'http://' . $sources->{'HTTPUPDATE'} . "/cpanelsync/easy/targz/Cpanel/Easy/${tarball_filename}", $tarball_filename );
        die "Could not download $tarball_filename" unless -e $tarball_filename;
        die "Failed to match a valid digest for $tarball_filename" if ( !_digest_file_match( \%tarball_digests, $tarball_filename ) );
    }
}

sub _digest_file_match {
    my ( $digests_r, $file ) = @_;
    for my $algo ( Cpanel::Crypt::GPG::Settings::allowed_digest_algorithms() ) {
        my $expected = $digests_r->{$algo};
        my $real = Cpanel::Sync::Digest::digest( $file, { algo => $algo } );

        if ( defined($expected) && ( $real eq $expected ) ) {
            return 1;
        }
    }
    return 0;
}

__END__

=head1 NAME

phpextensionmgr - Installer/Uninstaller for common PHP extensions

=head1 SYNOPSIS

phpextensionmgr [options] [action] [extension]

    Options:
      --help       Help message
      --prefix     Installation prefix for PHP (normally /usr/local)

    Actions:
      install      Install or update the extension
      uninstall    Uninstall the extension
      status       Display the installation status of the extension
      list         Show available extensions

=cut