#!/usr/local/cpanel/3rdparty/bin/perl

# cpanel - bin/checkphpini                         Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

#----------------------------------------------------------------------
# XXX XXX IMPORTANT!! XXX XXX
#
# This modulino is loaded and run as a module in at least one place.
# Do NOT add exit() to this code!
#----------------------------------------------------------------------

package bin::checkphpini;

use strict;
use warnings;

use Cpanel::Config::LoadCpConf ();
use Cpanel::Binaries           ();
use Cpanel::PHPINI             ();
use Cpanel::SafeFile           ();
use Cpanel::Timezones          ();

use constant {
    PHP_INI_SUFFIX => '/etc/php.ini',
};
my $verbose;

# TODO: Is this script just for cpanel-php?
# phpconfig - extension dir?

exit( bin::checkphpini::run(@ARGV) // 0 ) unless caller();

my $logger;

sub _logger {
    require Cpanel::Logger;
    $logger ||= Cpanel::Logger->new();
    return $logger;
}

# Only for tests, it is hard to mock out constants
sub _unversioned {
    return Cpanel::Binaries::CPANEL_PHP_UNVERSIONED;
}

sub run {
    my @args = @_;

    # abort if the php target is disabled
    my $php_version = Cpanel::Binaries::get_php_version();
    if ( !$php_version ) {
        _logger()->warn("skipping bin/checkphpini: No PHP versions appear to be installed on this system.");
        return;
    }

    $verbose = grep( /^--verbose$/, @args ) ? 1 : 0;
    my $prefix_dir         = Cpanel::Binaries::get_prefix('php');
    my $unversioned_prefix = _unversioned();
    my $php_ini            = $prefix_dir . PHP_INI_SUFFIX();

    # Make sure php.ini isn't immutable.
    if ( -e $php_ini ) {
        system 'chattr', '-i', $php_ini;
    }

    # Copy php.ini from php.ini.dist
    -e "$php_ini.dist" or _logger()->die("You are missing $php_ini.dist from cpanel's php package. To correct this, try running /usr/local/cpanel/scripts/upcp --sync");
    unlink $php_ini if ( -l $php_ini );
    if ( -d _ ) {
        rmdir $php_ini;
        -e $php_ini and _logger()->die("Cannot create $php_ini because it's a populated directory");
    }
    require File::Copy;
    File::Copy::copy( "$php_ini.dist", $php_ini );
    -f $php_ini or _logger()->die('Unable to copy into $php_ini');

    # Read cpanel.config to get php.ini settings.
    my $cpconf_ref = Cpanel::Config::LoadCpConf::loadcpconf_not_copy();
    my %set_directives;

    # Set timezone
    my $server_timezone = Cpanel::Timezones::get_current_timezone();
    $set_directives{'date.timezone'} = $server_timezone;

    # Set directive in php.ini - max_execution_time
    if ( defined $cpconf_ref->{'php_max_execution_time'} ) {
        my $max_execution_time = $cpconf_ref->{'php_max_execution_time'};
        $max_execution_time =~ s/\s*(\d+).*?$/$1/ or $max_execution_time = 0;
        if ( $max_execution_time < 90 ) {
            _logger()->warn("Increasing set cPanel/WHM PHP max execution time from '$cpconf_ref->{php_max_execution_time}' to 90");
            $max_execution_time = 90;
        }
        $set_directives{'max_execution_time'} = $max_execution_time;
    }

    # Set directive in php.ini - post_max_size
    if ( defined $cpconf_ref->{'php_post_max_size'} ) {
        my $post_max_size = $cpconf_ref->{'php_post_max_size'};
        $post_max_size =~ s/\s*(\d+).*?$/$1/ or $post_max_size = 0;
        if ( $post_max_size < 55 ) {
            _logger()->warn("Increasing cPanel/WHM PHP maximum post size from '$cpconf_ref->{php_post_max_size}' to 55M");
            $post_max_size = 55;
        }
        $post_max_size .= 'M';
        $set_directives{'post_max_size'} = $post_max_size;
    }

    # Set directive in php.ini - post_max_size
    if ( defined $cpconf_ref->{'php_upload_max_filesize'} ) {
        my $upload_max_filesize = $cpconf_ref->{'php_upload_max_filesize'};
        $upload_max_filesize =~ s/\s*(\d+).*?$/$1/ or $upload_max_filesize = 0;
        if ( $upload_max_filesize < 50 ) {
            _logger()->warn("Increasing cPanel/WHM PHP maximum upload file size from '$cpconf_ref->{php_upload_max_filesize}' to 50M");
            $upload_max_filesize = 50;
        }
        $upload_max_filesize .= 'M';
        $set_directives{'upload_max_filesize'} = $upload_max_filesize;
    }

    Cpanel::PHPINI::set_directives( \%set_directives, $prefix_dir );

    # Stop if no phploader is set.
    return if ( !$cpconf_ref->{'phploader'} || $cpconf_ref->{'phploader'} eq 'none' );

    # Figure out what php loaders are set.
    my %php_loaders;
    @php_loaders{ split( /,/, $cpconf_ref->{'phploader'} ) } = ( 1 .. 200 );

    # Warn about expired setting
    if ( $php_loaders{'oldsourceguardian'} ) {
        _logger()->warn(q{Your cPanel PHP loader is set to 'oldsourceguardian'. Unfortunately, we have});
        _logger()->warn(q{discontinued this setting. To select a valid setting, navigate to WHM's Tweak});
        _logger()->warn(q{Settings feature.});
    }

    # Read in the php.ini file with locking.
    my $phplock = Cpanel::SafeFile::safeopen( \*PHPINI, '+<', $php_ini );
    if ( !$phplock ) {
        _logger()->warn("Could not edit $php_ini");
        return;
    }
    my $phpini = '';

    # Replace zend_extension and extension depending on phploader settings
    while ( my $line = <PHPINI> ) {
        next if $line =~ /ioncube_loader_lin|ixed\..+\.lin/;

        $phpini .= $line;
        if ( $line =~ /;\s*zend_extension\s*=\s*cpanel/ ) {
            if ( $php_loaders{'ioncube'} ) {
                $phpini .= qq{zend_extension\t="$unversioned_prefix/ioncube/ioncube_loader_lin_${php_version}.so"\n};
                output("IonCubeLoader is activated.");

            }
            if ( $php_loaders{'zend'} ) {
                output("ZendGuardLoader is specified, but not supported on PHP 7.2+. Ignoring...");
            }
        }
        elsif ( $line =~ /;\s*extension\s*=\s*cpanel/ ) {
            if ( $php_loaders{'sourceguardian'} ) {
                $phpini .= qq{extension="ixed.${php_version}.lin"\n\n};
                output("SourceGuardian is activated.");
            }
        }
    }

    # Write out the file.
    seek( PHPINI, 0, 0 );
    print PHPINI $phpini;
    truncate( PHPINI, tell(PHPINI) );
    Cpanel::SafeFile::safeclose( \*PHPINI, $phplock );
    return;
}

sub output {
    return unless $verbose;
    my $output = shift || '';
    print $output . "\n";
    return;
}

1;
