????

Your IP : 13.59.178.179


Current Path : /usr/local/ssl/share/cagefs/
Upload File :
Current File : //usr/local/ssl/share/cagefs/phpinivalidator.py

#!/opt/cloudlinux/venv/bin/python3 -bb
# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT

"""
Module to validate the configuration file alt_phpXX.cfg
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
from builtins import *
import re
import os

ALTPHPVER_PATTERN = re.compile(r'alt_php(\d)(\d)\.cfg')


def get_php_ver(input_phpini_path):
    """
    function to get the version of the php file name alt_phpXX.cfg
    for example: 'alt_php55.cfg' => '5.5'
    """
    php_ver_searched = ALTPHPVER_PATTERN.search(os.path.basename(input_phpini_path))
    if php_ver_searched:
        return '.'.join(php_ver_searched.group(1, 2))


class PHPINIvalidator(object):

    DIRECTIVE_PATTERN = re.compile(r'(^Directive|Type|Range|Remark)\s*=\s*(.*\S)\s*$')
    CUSTOM_OPTIONS_DIRECTIVE_PATTERN = re.compile(r'^([a-zA-Z0-9_.]+)\s*=\s*([^;="]+[^;=" \t]|".+"|[^;="])\s*(;.*)?$')
    BOOLEAN_VARIANTS = ('On', 'Off', '0', '1', 'True', 'False')

    def __init__(self, phpconf_path='/etc/cl.selector/php.conf'):
        self.phpconf_path = phpconf_path
        self._phpconf_data = self._load_phpconf(self.phpconf_path)
        # List with unknown options:
        self.unknown_options = []
        # List options:
        self.invalid_values_options = []
        # List of invalid options (for example, options without values)
        self.invalid_options = []

    def _load_phpconf(self, phpconf_path):
        """
        Load reference data.
        Gets a dictionary of the form; example:
        {'upload_max_filesize': {'Default':'2M', 'Type':'list', 'Range'; '2M,4M,8M,16M,32M,64M,128M,256M,512M,1G'}
        """
        phpconf_dict = {}
        directive_title = None
        phpconf = open(phpconf_path)
        for phpconf_line in phpconf:
            if phpconf_line.startswith('#'):
                continue
            searched = self.DIRECTIVE_PATTERN.search(phpconf_line.rstrip())
            if not searched:
                continue
            directive_name, directive_val = searched.group(1, 2)
            if directive_name == 'Directive':
                directive_title = directive_val
                phpconf_dict[directive_title] = dict()
            else:
                phpconf_dict[directive_title][directive_name] = directive_val
        phpconf.close()
        return phpconf_dict

    # Use only full php_ver (e.g 5.4.11 instead of 5.4)
    def validate(self, input_phpini_lines, php_ver):
        output_phpini_lines = []
        # Clear lists of bad options
        self.unknown_options = []
        self.invalid_values_options = []
        self.invalid_options = []
        for input_phpini_line in input_phpini_lines:
            output_phpini_line = input_phpini_line
            if input_phpini_line.startswith(';'):
                output_phpini_lines.append(output_phpini_line)
                continue
            try:
                input_phpini_line1 = input_phpini_line.strip()
                if input_phpini_line1.endswith('='):
                    input_phpini_line1 += '0'
                directive_name, directive_val = self.CUSTOM_OPTIONS_DIRECTIVE_PATTERN.search(input_phpini_line1).group(1, 2)
                is_valid_directive, is_valid_value = self._validate_directive_val(directive_name=directive_name, directive_val=directive_val, php_ver=php_ver)
                if not is_valid_directive:
                    self.unknown_options.append(input_phpini_line.strip())
                else:
                    # Directive is valid, check value
                    if not is_valid_value:
                        self.invalid_values_options.append(input_phpini_line.strip())
            except AttributeError:
                is_valid_directive = False
                is_valid_value = False
                self.invalid_options.append(input_phpini_line.strip())
            if not (is_valid_directive and is_valid_value):
                output_phpini_line = ';' + input_phpini_line

            output_phpini_lines.append(output_phpini_line)
        return output_phpini_lines

    def _validate_directive_val(self, directive_name, directive_val, php_ver):
        """
        Validates directive for supplied PHP version
        :param directive_name: Directive name
        :param directive_val: Directive name
        :param php_ver: PHP version (3 digits) to check directive
        :return: Tuple (is_valid_directive, is_valid_value) - boolean flags validity of directive and value
        """
        directive_data_dict = self._phpconf_data.get(directive_name)
        if not directive_data_dict:
            return False, False
        directive_data_type = directive_data_dict['Type']
        remark = directive_data_dict.get('Remark')
        if remark:
            # Remark present
            if remark.startswith('>') or remark.startswith('<'):
                remark_znak = remark[0]
                remark_ver = remark[1:]

                if remark_znak == '<':
                    if php_ver.split('.') > remark_ver.split('.'):
                        # version mismatch
                        return False, False
                elif remark_znak == '>':
                    # return php_ver.split('.') > remark_ver.split('.'), False
                    if php_ver.split('.') < remark_ver.split('.'):
                        # version mismatch
                        return False, False
            else:
                # Remark: = xx.yy.zzz or Remark: = xx.yy
                # Form 2-digit versions from remark and checking alt-php version
                remark_ver_parts = remark.split('.')
                remark_ver_2digit = '%s.%s' % (remark_ver_parts[0], remark_ver_parts[1])
                php_ver_parts = php_ver.split('.')
                php_ver_2digit = '%s.%s' % (php_ver_parts[0], php_ver_parts[1])
                if remark_ver_2digit != php_ver_2digit:
                    # Invalid directive for supplied PHP version
                    return False, False

        if directive_name not in self._phpconf_data:
            # No such directive
            return False, False

        if directive_data_type == 'bool':
            if directive_val not in self.BOOLEAN_VARIANTS:
                # directive value is boolean (by php.conf), but directive_val not boolean
                return True, False
        elif directive_data_type == 'list':
            if directive_val not in directive_data_dict['Range'].split(','):
                # directive value is not from php.conf list
                return True, False
        return True, True