/
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
clwpos
/
php
/
Upload Filee
HOME
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