%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/clwpos/php/
Upload File :
Create Path :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/clwpos/php/base.py

from __future__ import absolute_import

import dataclasses
import os
import re
import subprocess
from pathlib import Path

from clwpos.cl_wpos_exceptions import PhpBrokenException
from clwpos.scoped_cache import cached_in_scope
from clwpos.utils import run_in_cagefs_if_needed


@dataclasses.dataclass
class PHP:
    # e.g. 'alt-php67', must be unique
    identifier: str

    # e.g. '5.6'
    version: str

    # e.g. '/opt/alt/php51/usr/lib64/php/modules/'
    modules_dir: str

    # e.g. '/opt/alt/php80/usr/bin/php'
    bin: str

    # e.g. '/opt/alt/php51/etc/php.ini'
    ini: str

    # e.g. '/opt/alt/php51/'
    dir: str

    def __hash__(self):
        return hash(self.identifier)

    def __eq__(self, other: 'PHP'):
        return self.identifier == other.identifier

    def __gt__(self, other):
        return self.identifier > other.identifier

    @cached_in_scope
    def is_extension_installed(self, extension: str):
        """
        Quick check that given extension is installed as
        so file in default extensions directory
        """
        is_present = bool(list(Path(self.modules_dir).glob(f"**/{extension}.so")))
        return is_present

    @cached_in_scope
    def is_extension_loaded(self, extension: str):
        """
        Complex check that given extension is loaded as
        part of the ini configuration.

        Be careful with this method because it actually runs
        php process and may be heavy.
        """
        if not self.is_extension_installed(extension):
            return False

        php_bin_path = self.bin
        if os.geteuid() == 0:
            exec_func = subprocess.run
        else:
            exec_func = run_in_cagefs_if_needed

        is_loaded = exec_func(
            f'{php_bin_path} -m | /bin/grep {extension}',
            shell=True,
            executable='/bin/bash',
            env={}
        ).returncode == 0
        return is_loaded


    def apply_php_selector(self) -> 'PHP':
        """
        PHP selector can replace path with symlink.
        It's a reason why we need normalization.
        """
        # there is no need to execute binary
        # when we see that it is not a link
        # TODO: uncomment and check how it works
        # if not os.path.islink(self.bin):
        #     return self

        command = [self.bin, '-r', 'echo php_ini_loaded_file();']
        result = run_in_cagefs_if_needed(command, env={})

        # example:
        # /opt/cpanel/ea-php74/root/etc/php.ini'
        if result.stderr and not result.stdout:
            raise PhpBrokenException(str(self.bin), result.stderr)

        # check for alt version and replace if found
        alt_pattern = re.compile(r"alt.*php[^/]*/")
        captured_version = alt_pattern.search(result.stdout)
        if captured_version:
            php_name = captured_version[0].strip("/").replace("/", "-")

            # we don't want to be dependent on
            # whether panel supports alt-php or not
            from clwpos.php.alt_php import create_generic_php
            return create_generic_php(php_name)

        return self

Zerion Mini Shell 1.0