mirror of
				https://github.com/usmannasir/cyberpanel.git
				synced 2025-10-31 18:36:17 +01:00 
			
		
		
		
	Update PHP version references and improve AlmaLinux 9 compatibility
- Changed PHP symlink from version 8.0 to 8.3 in various scripts to ensure compatibility with the latest PHP version. - Updated documentation links in the FAQ to point to the new community support page. - Added checks and fixes for MariaDB installation issues specific to AlmaLinux 9. - Enhanced the installation script to support additional PHP versions and improve overall installation reliability.
This commit is contained in:
		| @@ -39,9 +39,9 @@ CyberPanel supports a wide range of PHP versions across different operating syst | ||||
|  | ||||
| ### ☑️ **Currently Supported PHP Versions** | ||||
|  | ||||
| - **PHP 8.5** - Latest stable version (EOL: Dec 2028) | ||||
| - **PHP 8.5** - Latest stable version (EOL: Dec 2028) ⭐ **NEW!** | ||||
| - **PHP 8.4** - Stable version (EOL: Dec 2027) | ||||
| - **PHP 8.3** - Stable version (EOL: Dec 2027) | ||||
| - **PHP 8.3** - **Default version** - Stable version (EOL: Dec 2027) 🎯 | ||||
| - **PHP 8.2** - Stable version (EOL: Dec 2026) | ||||
| - **PHP 8.1** - Stable version (EOL: Dec 2025) | ||||
| - **PHP 8.0** - Legacy support (EOL: Nov 2023) | ||||
|   | ||||
| @@ -2278,7 +2278,7 @@ echo "echo \$@ > /etc/cyberpanel/adminPass" >> /usr/bin/adminPass | ||||
| chmod 700 /usr/bin/adminPass | ||||
|  | ||||
| rm -f /usr/bin/php | ||||
| ln -s /usr/local/lsws/lsphp80/bin/php /usr/bin/php | ||||
| ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php | ||||
|  | ||||
| if [[ "$Server_OS" = "CentOS" ]] ; then | ||||
| #all centos 7/8 post change goes here | ||||
|   | ||||
							
								
								
									
										14
									
								
								faq.sh
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								faq.sh
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| ${PURPLE}3.${NC} How to access LiteSpeed webadmin console ? | ||||
|  | ||||
| Please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/87/tutorial-how-to-setup-and-login-to-openlitespeed-webadmin-console/p1${NC} | ||||
| Please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||
|  | ||||
| ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| @@ -52,9 +52,9 @@ ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| ${PURPLE}6.${NC} How to raise upload limit for cyberpanel's phpMyAdmin and File Manager? | ||||
|  | ||||
| edit file ${RED}/usr/local/lsws/lsphp73/etc/php.ini${NC} for CentOS or openEuler | ||||
| edit file ${RED}/usr/local/lsws/lsphp83/etc/php.ini${NC} for CentOS or openEuler | ||||
|  | ||||
| ${RED}/usr/local/lsws/lsphp73/etc/php/7.3/litespeed/php.ini${NC} for Ubbuntu | ||||
| ${RED}/usr/local/lsws/lsphp83/etc/php/8.3/litespeed/php.ini${NC} for Ubuntu | ||||
|  | ||||
| find 2 configurations: | ||||
|  | ||||
| @@ -66,9 +66,9 @@ ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| ${PURPLE}7.${NC} How to add more IPs to my website(s) ? | ||||
|  | ||||
| For OpenLiteSpeed, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/126/tutorial-how-to-add-2nd-ip-for-websites/p1${NC} | ||||
| For OpenLiteSpeed, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||
|  | ||||
| For LiteSpeed Enterprise, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/3745/tutorial-how-to-add-2nd-ip-for-litespeed-enterprise/p1${NC} | ||||
| For LiteSpeed Enterprise, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||
|  | ||||
| ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| @@ -80,7 +80,7 @@ ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| ${PURPLE}9.${NC} How to enable Auto-Index for my site ? | ||||
|  | ||||
| Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3850/tutorial-how-to-enable-auto-index-on-openlitespeed-and-litespeed-enterprise${NC} | ||||
| Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||
|  | ||||
| ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| @@ -111,5 +111,5 @@ ${BLUE}------------------------------------------------------------${NC} | ||||
|  | ||||
| ${PURPLE}13.${NC} How to enable PHP error log ? | ||||
|  | ||||
| Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3977/tutorial-how-to-enable-php-error-log/p1${NC} | ||||
| Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||
| " | ||||
| @@ -1,190 +0,0 @@ | ||||
| import os | ||||
| import shutil | ||||
| import pathlib | ||||
| import stat | ||||
|  | ||||
|  | ||||
| def mkdir_p(path, exist_ok=True): | ||||
|     """ | ||||
|     Creates the directory and paths leading up to it like unix mkdir -p . | ||||
|     Defaults to exist_ok so if it exists were not throwing fatal errors | ||||
|     https://docs.python.org/3.7/library/os.html#os.makedirs | ||||
|     """ | ||||
|     if not os.path.exists(path): | ||||
|         print('creating directory: ' + path) | ||||
|         os.makedirs(path, exist_ok) | ||||
|  | ||||
|  | ||||
| def chmod_digit(file_path, perms): | ||||
|     """ | ||||
|     Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself. | ||||
|     Credits: https://stackoverflow.com/a/60052847/1621381 | ||||
|     """ | ||||
|     try: | ||||
|         os.chmod(file_path, int(str(perms), base=8)) | ||||
|     except: | ||||
|         print(f'Could not chmod : {file_path} to {perms}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def touch(filepath: str, exist_ok=True): | ||||
|     """ | ||||
|     Touches a file like unix `touch somefile` would. | ||||
|     """ | ||||
|     try: | ||||
|         pathlib.Path(filepath).touch(exist_ok) | ||||
|     except FileExistsError: | ||||
|         print('Could touch : ' + filepath) | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def symlink(src, dst): | ||||
|     """ | ||||
|     Symlink a path to another if the src exists. | ||||
|     """ | ||||
|     try: | ||||
|         if os.access(src, os.R_OK): | ||||
|             os.symlink(src, dst) | ||||
|     except: | ||||
|         print(f'Could not symlink Source: {src} > Destination: {dst}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def chown(path, user, group=-1): | ||||
|     """ | ||||
|     Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged. | ||||
|     Useful if just changing user or group vs both. | ||||
|     """ | ||||
|     try: | ||||
|         shutil.chown(path, user, group) | ||||
|     except PermissionError: | ||||
|         print(f'Could not change permissions for: {path} to {user}:{group}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def recursive_chown(path, owner, group=-1): | ||||
|     """ | ||||
|     Recursively chown a path and contents to owner. | ||||
|     https://docs.python.org/3/library/shutil.html | ||||
|     """ | ||||
|     for dirpath, dirnames, filenames in os.walk(path): | ||||
|         try: | ||||
|             shutil.chown(dirpath, owner, group) | ||||
|         except PermissionError: | ||||
|             print('Could not change permissions for: ' + dirpath + ' to: ' + owner) | ||||
|             pass | ||||
|         for filename in filenames: | ||||
|             try: | ||||
|                 shutil.chown(os.path.join(dirpath, filename), owner, group) | ||||
|             except PermissionError: | ||||
|                 print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner) | ||||
|                 pass | ||||
|  | ||||
|  | ||||
| def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True): | ||||
|     """ | ||||
|     Recursively chmod a path and contents to mode. | ||||
|     Defaults to chmod top level directory but can be optionally | ||||
|     toggled off when you want to chmod only contents of like a user's homedir vs homedir itself | ||||
|     https://docs.python.org/3.6/library/os.html#os.walk | ||||
|     """ | ||||
|  | ||||
|     # Here we are converting the integers to string and then to octal. | ||||
|     # so this function doesn't need to be called with 0o prefixed for the file and dir mode | ||||
|     dir_mode = int(str(dir_mode), base=8) | ||||
|     file_mode = int(str(file_mode), base=8) | ||||
|  | ||||
|     if topdir: | ||||
|         # Set chmod on top level path | ||||
|         try: | ||||
|             os.chmod(path, dir_mode) | ||||
|         except: | ||||
|             print('Could not chmod :' + path + ' to ' + str(dir_mode)) | ||||
|     for root, dirs, files in os.walk(path): | ||||
|         for d in dirs: | ||||
|             try: | ||||
|                 os.chmod(os.path.join(root, d), dir_mode) | ||||
|             except: | ||||
|                 print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode)) | ||||
|                 pass | ||||
|         for f in files: | ||||
|             try: | ||||
|                 os.chmod(os.path.join(root, f), file_mode) | ||||
|             except: | ||||
|                 print('Could not chmod :' + path + ' to ' + str(file_mode)) | ||||
|                 pass | ||||
|  | ||||
|  | ||||
| # Left intentionally here for reference. | ||||
| # Set recursive chown for a path | ||||
| # recursive_chown(my_path, 'root', 'root') | ||||
| # for changing group recursively without affecting user | ||||
| # recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd') | ||||
|  | ||||
| # explicitly set permissions for directories/folders to 0755 and files to 0644 | ||||
| # recursive_permissions(my_path, 755, 644) | ||||
|  | ||||
| # Fix permissions and use default values | ||||
| # recursive_permissions(my_path) | ||||
| # ========================================================= | ||||
| # Below is a helper class for getting and working with permissions | ||||
| # Original credits to : https://github.com/keysemble/perfm | ||||
|  | ||||
| def perm_octal_digit(rwx): | ||||
|     digit = 0 | ||||
|     if rwx[0] == 'r': | ||||
|         digit += 4 | ||||
|     if rwx[1] == 'w': | ||||
|         digit += 2 | ||||
|     if rwx[2] == 'x': | ||||
|         digit += 1 | ||||
|     return digit | ||||
|  | ||||
|  | ||||
| class FilePerm: | ||||
|     def __init__(self, filepath): | ||||
|         filemode = stat.filemode(os.stat(filepath).st_mode) | ||||
|         permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)] | ||||
|         self.filepath = filepath | ||||
|         self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions])) | ||||
|  | ||||
|     def mode(self): | ||||
|         mode = 0 | ||||
|         for shift, digit in enumerate(self.octal()[::-1]): | ||||
|             mode += digit << (shift * 3) | ||||
|         return mode | ||||
|  | ||||
|     def digits(self): | ||||
|         """Get the octal chmod equivalent value 755 in single string""" | ||||
|         return "".join(map(str, self.octal())) | ||||
|  | ||||
|     def octal(self): | ||||
|         """Get the octal value in a list [7, 5, 5]""" | ||||
|         return [perm_octal_digit(p) for p in self.access_dict.values()] | ||||
|  | ||||
|     def access_bits(self, access): | ||||
|         if access in self.access_dict.keys(): | ||||
|             r, w, x = self.access_dict[access] | ||||
|             return [r == 'r', w == 'w', x == 'x'] | ||||
|  | ||||
|     def update_bitwise(self, settings): | ||||
|         def perm_list(read=False, write=False, execute=False): | ||||
|             pl = ['-', '-', '-'] | ||||
|             if read: | ||||
|                 pl[0] = 'r' | ||||
|             if write: | ||||
|                 pl[1] = 'w' | ||||
|             if execute: | ||||
|                 pl[2] = 'x' | ||||
|             return pl | ||||
|  | ||||
|         self.access_dict = dict( | ||||
|             [(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()]) | ||||
|         os.chmod(self.filepath, self.mode()) | ||||
|  | ||||
| # project_directory = os.path.abspath(os.path.dirname(sys.argv[0])) | ||||
| # home_directory = os.path.expanduser('~') | ||||
| # print(f'Path: {home_directory}  Mode: {FilePerm(home_directory).mode()}  Octal: {FilePerm(home_directory).octal()} ' | ||||
| #      f'Digits: {FilePerm(home_directory).digits()}') | ||||
| # Example: Output | ||||
| # Path: /home/cooluser  Mode: 493  Octal: [7, 5, 5] Digits: 755 | ||||
| @@ -2969,7 +2969,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | ||||
|         writeToFile.write(content) | ||||
|         writeToFile.close() | ||||
|  | ||||
|         command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|         command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|         subprocess.call(shlex.split(command)) | ||||
|  | ||||
|         command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/data" | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -44,6 +44,62 @@ FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVers | ||||
| class InstallCyberPanel: | ||||
|     mysql_Root_password = "" | ||||
|     mysqlPassword = "" | ||||
|      | ||||
|     def is_almalinux9(self): | ||||
|         """Check if running on AlmaLinux 9""" | ||||
|         if os.path.exists('/etc/almalinux-release'): | ||||
|             try: | ||||
|                 with open('/etc/almalinux-release', 'r') as f: | ||||
|                     content = f.read() | ||||
|                     return 'release 9' in content | ||||
|             except: | ||||
|                 return False | ||||
|         return False | ||||
|      | ||||
|     def fix_almalinux9_mariadb(self): | ||||
|         """Fix AlmaLinux 9 MariaDB installation issues""" | ||||
|         if not self.is_almalinux9(): | ||||
|             return | ||||
|          | ||||
|         self.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1) | ||||
|          | ||||
|         try: | ||||
|             # Disable problematic MariaDB MaxScale repository | ||||
|             self.stdOut("Disabling problematic MariaDB MaxScale repository...", 1) | ||||
|             command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true" | ||||
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||
|              | ||||
|             # Remove problematic repository files | ||||
|             self.stdOut("Removing problematic repository files...", 1) | ||||
|             problematic_repos = [ | ||||
|                 '/etc/yum.repos.d/mariadb-maxscale.repo', | ||||
|                 '/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew' | ||||
|             ] | ||||
|             for repo_file in problematic_repos: | ||||
|                 if os.path.exists(repo_file): | ||||
|                     os.remove(repo_file) | ||||
|                     self.stdOut(f"Removed {repo_file}", 1) | ||||
|              | ||||
|             # Clean DNF cache | ||||
|             self.stdOut("Cleaning DNF cache...", 1) | ||||
|             command = "dnf clean all" | ||||
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||
|              | ||||
|             # Install MariaDB from official repository | ||||
|             self.stdOut("Setting up official MariaDB repository...", 1) | ||||
|             command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'" | ||||
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||
|              | ||||
|             # Install MariaDB packages | ||||
|             self.stdOut("Installing MariaDB packages...", 1) | ||||
|             mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel" | ||||
|             command = f"dnf install -y {mariadb_packages}" | ||||
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||
|              | ||||
|             self.stdOut("AlmaLinux 9 MariaDB fixes completed", 1) | ||||
|              | ||||
|         except Exception as e: | ||||
|             self.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0) | ||||
|     CloudLinux8 = 0 | ||||
|  | ||||
|     def install_package(self, package_name, options=""): | ||||
| @@ -335,7 +391,7 @@ class InstallCyberPanel: | ||||
|         return self.reStartLiteSpeed() | ||||
|  | ||||
|     def installAllPHPVersions(self): | ||||
|         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83'] | ||||
|         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||
|          | ||||
|         if self.distro == ubuntu: | ||||
|             # Install base PHP 7.x packages | ||||
| @@ -563,6 +619,12 @@ gpgcheck=1 | ||||
|  | ||||
|         if self.remotemysql == 'OFF': | ||||
|             ############## Start mariadb ###################### | ||||
|              | ||||
|             # Check if AlmaLinux 9 and apply fixes | ||||
|             if self.is_almalinux9(): | ||||
|                 self.stdOut("AlmaLinux 9 detected - applying MariaDB fixes", 1) | ||||
|                 self.fix_almalinux9_mariadb() | ||||
|              | ||||
|             self.manage_service('mariadb', 'start') | ||||
|  | ||||
|             ############## Enable mariadb at system startup ###################### | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,121 +0,0 @@ | ||||
| {% extends "baseTemplate/index.html" %} | ||||
| {% load i18n %} | ||||
| {% block title %}{% trans "Mail Functions - CyberPanel" %}{% endblock %} | ||||
| {% block content %} | ||||
|  | ||||
|     {% load static %} | ||||
|     {% get_current_language as LANGUAGE_CODE %} | ||||
|     <!-- Current language: {{ LANGUAGE_CODE }} --> | ||||
|  | ||||
|     <div class="container"> | ||||
|         <div id="page-title"> | ||||
|             <h2>{% trans "Mail Functions" %}</h2> | ||||
|             <p>{% trans "Manage email accounts on this page." %}</p> | ||||
|         </div> | ||||
|  | ||||
|         <div class="panel col-md-12"> | ||||
|             <div class="panel-body"> | ||||
|                 <h3 class="content-box-header"> | ||||
|                     {% trans "Available Functions" %} | ||||
|                 </h3> | ||||
|  | ||||
|                 <div class="example-box-wrapper"> | ||||
|                     <div class="row"> | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'createEmailAccount' %}" title="{% trans 'Create Email' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "Create Email" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-plus-square"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|                          | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'listEmails' %}" title="{% trans 'List Emails' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "List Emails" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-plus-square"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|  | ||||
|  | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'deleteEmailAccount' %}" title="{% trans 'Delete Email' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "Delete Email" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-trash"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|                          | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'emailForwarding' %}" title="{% trans 'Email Forwarding' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "Email Forwarding" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-plus-square"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|  | ||||
|  | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'changeEmailAccountPassword' %}" title="{% trans 'Change Password' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "Change Password" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-key"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|                          | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="{% url 'dkimManager' %}" title="{% trans 'DKIM Manager' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "DKIM Manager" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-key"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|                          | ||||
|                         <div class="col-md-3 btn-min-width"> | ||||
|                             <a href="/snappymail/index.php" title="{% trans 'Access Webmail' %}" | ||||
|                                class="tile-box tile-box-shortcut btn-primary"> | ||||
|                                 <div class="tile-header"> | ||||
|                                     {% trans "Access Webmail" %} | ||||
|                                 </div> | ||||
|                                 <div class="tile-content-wrapper"> | ||||
|                                     <i class="fa fa-key"></i> | ||||
|                                 </div> | ||||
|                             </a> | ||||
|                         </div> | ||||
|  | ||||
|  | ||||
|                     </div> | ||||
|  | ||||
|  | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|     </div> | ||||
|  | ||||
|  | ||||
| {% endblock %} | ||||
| @@ -1372,7 +1372,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | ||||
|             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' | ||||
|             ProcessUtilities.executioner(command, 'root', True) | ||||
|  | ||||
|             command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|             command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|             ProcessUtilities.executioner(command, 'root', True) | ||||
|  | ||||
|             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' | ||||
|   | ||||
| @@ -1,190 +0,0 @@ | ||||
| import os | ||||
| import shutil | ||||
| import pathlib | ||||
| import stat | ||||
|  | ||||
|  | ||||
| def mkdir_p(path, exist_ok=True): | ||||
|     """ | ||||
|     Creates the directory and paths leading up to it like unix mkdir -p . | ||||
|     Defaults to exist_ok so if it exists were not throwing fatal errors | ||||
|     https://docs.python.org/3.7/library/os.html#os.makedirs | ||||
|     """ | ||||
|     if not os.path.exists(path): | ||||
|         print('creating directory: ' + path) | ||||
|         os.makedirs(path, exist_ok) | ||||
|  | ||||
|  | ||||
| def chmod_digit(file_path, perms): | ||||
|     """ | ||||
|     Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself. | ||||
|     Credits: https://stackoverflow.com/a/60052847/1621381 | ||||
|     """ | ||||
|     try: | ||||
|         os.chmod(file_path, int(str(perms), base=8)) | ||||
|     except: | ||||
|         print(f'Could not chmod : {file_path} to {perms}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def touch(filepath: str, exist_ok=True): | ||||
|     """ | ||||
|     Touches a file like unix `touch somefile` would. | ||||
|     """ | ||||
|     try: | ||||
|         pathlib.Path(filepath).touch(exist_ok) | ||||
|     except FileExistsError: | ||||
|         print('Could touch : ' + filepath) | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def symlink(src, dst): | ||||
|     """ | ||||
|     Symlink a path to another if the src exists. | ||||
|     """ | ||||
|     try: | ||||
|         if os.access(src, os.R_OK): | ||||
|             os.symlink(src, dst) | ||||
|     except: | ||||
|         print(f'Could not symlink Source: {src} > Destination: {dst}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def chown(path, user, group=-1): | ||||
|     """ | ||||
|     Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged. | ||||
|     Useful if just changing user or group vs both. | ||||
|     """ | ||||
|     try: | ||||
|         shutil.chown(path, user, group) | ||||
|     except PermissionError: | ||||
|         print(f'Could not change permissions for: {path} to {user}:{group}') | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def recursive_chown(path, owner, group=-1): | ||||
|     """ | ||||
|     Recursively chown a path and contents to owner. | ||||
|     https://docs.python.org/3/library/shutil.html | ||||
|     """ | ||||
|     for dirpath, dirnames, filenames in os.walk(path): | ||||
|         try: | ||||
|             shutil.chown(dirpath, owner, group) | ||||
|         except PermissionError: | ||||
|             print('Could not change permissions for: ' + dirpath + ' to: ' + owner) | ||||
|             pass | ||||
|         for filename in filenames: | ||||
|             try: | ||||
|                 shutil.chown(os.path.join(dirpath, filename), owner, group) | ||||
|             except PermissionError: | ||||
|                 print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner) | ||||
|                 pass | ||||
|  | ||||
|  | ||||
| def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True): | ||||
|     """ | ||||
|     Recursively chmod a path and contents to mode. | ||||
|     Defaults to chmod top level directory but can be optionally | ||||
|     toggled off when you want to chmod only contents of like a user's homedir vs homedir itself | ||||
|     https://docs.python.org/3.6/library/os.html#os.walk | ||||
|     """ | ||||
|  | ||||
|     # Here we are converting the integers to string and then to octal. | ||||
|     # so this function doesn't need to be called with 0o prefixed for the file and dir mode | ||||
|     dir_mode = int(str(dir_mode), base=8) | ||||
|     file_mode = int(str(file_mode), base=8) | ||||
|  | ||||
|     if topdir: | ||||
|         # Set chmod on top level path | ||||
|         try: | ||||
|             os.chmod(path, dir_mode) | ||||
|         except: | ||||
|             print('Could not chmod :' + path + ' to ' + str(dir_mode)) | ||||
|     for root, dirs, files in os.walk(path): | ||||
|         for d in dirs: | ||||
|             try: | ||||
|                 os.chmod(os.path.join(root, d), dir_mode) | ||||
|             except: | ||||
|                 print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode)) | ||||
|                 pass | ||||
|         for f in files: | ||||
|             try: | ||||
|                 os.chmod(os.path.join(root, f), file_mode) | ||||
|             except: | ||||
|                 print('Could not chmod :' + path + ' to ' + str(file_mode)) | ||||
|                 pass | ||||
|  | ||||
|  | ||||
| # Left intentionally here for reference. | ||||
| # Set recursive chown for a path | ||||
| # recursive_chown(my_path, 'root', 'root') | ||||
| # for changing group recursively without affecting user | ||||
| # recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd') | ||||
|  | ||||
| # explicitly set permissions for directories/folders to 0755 and files to 0644 | ||||
| # recursive_permissions(my_path, 755, 644) | ||||
|  | ||||
| # Fix permissions and use default values | ||||
| # recursive_permissions(my_path) | ||||
| # ========================================================= | ||||
| # Below is a helper class for getting and working with permissions | ||||
| # Original credits to : https://github.com/keysemble/perfm | ||||
|  | ||||
| def perm_octal_digit(rwx): | ||||
|     digit = 0 | ||||
|     if rwx[0] == 'r': | ||||
|         digit += 4 | ||||
|     if rwx[1] == 'w': | ||||
|         digit += 2 | ||||
|     if rwx[2] == 'x': | ||||
|         digit += 1 | ||||
|     return digit | ||||
|  | ||||
|  | ||||
| class FilePerm: | ||||
|     def __init__(self, filepath): | ||||
|         filemode = stat.filemode(os.stat(filepath).st_mode) | ||||
|         permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)] | ||||
|         self.filepath = filepath | ||||
|         self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions])) | ||||
|  | ||||
|     def mode(self): | ||||
|         mode = 0 | ||||
|         for shift, digit in enumerate(self.octal()[::-1]): | ||||
|             mode += digit << (shift * 3) | ||||
|         return mode | ||||
|  | ||||
|     def digits(self): | ||||
|         """Get the octal chmod equivalent value 755 in single string""" | ||||
|         return "".join(map(str, self.octal())) | ||||
|  | ||||
|     def octal(self): | ||||
|         """Get the octal value in a list [7, 5, 5]""" | ||||
|         return [perm_octal_digit(p) for p in self.access_dict.values()] | ||||
|  | ||||
|     def access_bits(self, access): | ||||
|         if access in self.access_dict.keys(): | ||||
|             r, w, x = self.access_dict[access] | ||||
|             return [r == 'r', w == 'w', x == 'x'] | ||||
|  | ||||
|     def update_bitwise(self, settings): | ||||
|         def perm_list(read=False, write=False, execute=False): | ||||
|             pl = ['-', '-', '-'] | ||||
|             if read: | ||||
|                 pl[0] = 'r' | ||||
|             if write: | ||||
|                 pl[1] = 'w' | ||||
|             if execute: | ||||
|                 pl[2] = 'x' | ||||
|             return pl | ||||
|  | ||||
|         self.access_dict = dict( | ||||
|             [(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()]) | ||||
|         os.chmod(self.filepath, self.mode()) | ||||
|  | ||||
| # project_directory = os.path.abspath(os.path.dirname(sys.argv[0])) | ||||
| # home_directory = os.path.expanduser('~') | ||||
| # print(f'Path: {home_directory}  Mode: {FilePerm(home_directory).mode()}  Octal: {FilePerm(home_directory).octal()} ' | ||||
| #      f'Digits: {FilePerm(home_directory).digits()}') | ||||
| # Example: Output | ||||
| # Path: /home/cooluser  Mode: 493  Octal: [7, 5, 5] Digits: 755 | ||||
| @@ -861,7 +861,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; | ||||
|             command = f'wget -q -O /usr/local/CyberCP/snappymail_cyberpanel.php  https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php' | ||||
|             Upgrade.executioner_silent(command, 'verify certificate', 0) | ||||
|  | ||||
|             command = f'/usr/local/lsws/lsphp80/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php' | ||||
|             command = f'/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php' | ||||
|             Upgrade.executioner_silent(command, 'verify certificate', 0) | ||||
|  | ||||
|             # labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini' | ||||
| @@ -3121,7 +3121,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | ||||
|             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' | ||||
|             Upgrade.executioner(command, 0) | ||||
|  | ||||
|             command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|             command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||
|             Upgrade.executioner_silent(command, 'Configure SnappyMail') | ||||
|  | ||||
|             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' | ||||
| @@ -3182,44 +3182,221 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | ||||
|         command = '/root/.acme.sh/acme.sh --set-default-ca  --server  letsencrypt' | ||||
|         Upgrade.executioner(command, command, 0) | ||||
|  | ||||
|     @staticmethod | ||||
|     def check_package_availability(package_name): | ||||
|         """Check if a package is available in the repositories""" | ||||
|         try: | ||||
|             # Try to search for the package without installing | ||||
|             if os.path.exists('/etc/yum.repos.d/') or os.path.exists('/etc/dnf/dnf.conf'): | ||||
|                 # RHEL-based systems | ||||
|                 command = f"dnf search --quiet {package_name} 2>/dev/null | grep -q '^Last metadata expiration' || yum search --quiet {package_name} 2>/dev/null | head -1" | ||||
|                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||
|                 return result.returncode == 0 | ||||
|             else: | ||||
|                 # Ubuntu/Debian systems | ||||
|                 command = f"apt-cache search {package_name} 2>/dev/null | head -1" | ||||
|                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||
|                 return result.returncode == 0 and result.stdout.strip() != "" | ||||
|         except Exception as e: | ||||
|             Upgrade.stdOut(f"Error checking package availability for {package_name}: {str(e)}", 0) | ||||
|             return False | ||||
|  | ||||
|     @staticmethod | ||||
|     def is_almalinux9(): | ||||
|         """Check if running on AlmaLinux 9""" | ||||
|         if os.path.exists('/etc/almalinux-release'): | ||||
|             try: | ||||
|                 with open('/etc/almalinux-release', 'r') as f: | ||||
|                     content = f.read() | ||||
|                     return 'release 9' in content | ||||
|             except: | ||||
|                 return False | ||||
|         return False | ||||
|  | ||||
|     @staticmethod | ||||
|     def fix_almalinux9_mariadb(): | ||||
|         """Fix AlmaLinux 9 MariaDB installation issues""" | ||||
|         if not Upgrade.is_almalinux9(): | ||||
|             return | ||||
|          | ||||
|         Upgrade.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1) | ||||
|          | ||||
|         try: | ||||
|             # Disable problematic MariaDB MaxScale repository | ||||
|             Upgrade.stdOut("Disabling problematic MariaDB MaxScale repository...", 1) | ||||
|             command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true" | ||||
|             subprocess.run(command, shell=True, capture_output=True) | ||||
|              | ||||
|             # Remove problematic repository files | ||||
|             Upgrade.stdOut("Removing problematic repository files...", 1) | ||||
|             problematic_repos = [ | ||||
|                 '/etc/yum.repos.d/mariadb-maxscale.repo', | ||||
|                 '/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew' | ||||
|             ] | ||||
|             for repo_file in problematic_repos: | ||||
|                 if os.path.exists(repo_file): | ||||
|                     os.remove(repo_file) | ||||
|                     Upgrade.stdOut(f"Removed {repo_file}", 1) | ||||
|              | ||||
|             # Clean DNF cache | ||||
|             Upgrade.stdOut("Cleaning DNF cache...", 1) | ||||
|             command = "dnf clean all" | ||||
|             subprocess.run(command, shell=True, capture_output=True) | ||||
|              | ||||
|             # Install MariaDB from official repository | ||||
|             Upgrade.stdOut("Setting up official MariaDB repository...", 1) | ||||
|             command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'" | ||||
|             result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||
|             if result.returncode != 0: | ||||
|                 Upgrade.stdOut(f"Warning: MariaDB repo setup failed: {result.stderr}", 0) | ||||
|              | ||||
|             # Install MariaDB packages | ||||
|             Upgrade.stdOut("Installing MariaDB packages...", 1) | ||||
|             mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel" | ||||
|             command = f"dnf install -y {mariadb_packages}" | ||||
|             result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||
|             if result.returncode != 0: | ||||
|                 Upgrade.stdOut(f"Warning: MariaDB installation issues: {result.stderr}", 0) | ||||
|              | ||||
|             # Start and enable MariaDB service | ||||
|             Upgrade.stdOut("Starting MariaDB service...", 1) | ||||
|             services = ['mariadb', 'mysql', 'mysqld'] | ||||
|             for service in services: | ||||
|                 try: | ||||
|                     command = f"systemctl start {service}" | ||||
|                     result = subprocess.run(command, shell=True, capture_output=True) | ||||
|                     if result.returncode == 0: | ||||
|                         command = f"systemctl enable {service}" | ||||
|                         subprocess.run(command, shell=True, capture_output=True) | ||||
|                         Upgrade.stdOut(f"MariaDB service started as {service}", 1) | ||||
|                         break | ||||
|                 except: | ||||
|                     continue | ||||
|              | ||||
|             Upgrade.stdOut("AlmaLinux 9 MariaDB fixes completed", 1) | ||||
|              | ||||
|         except Exception as e: | ||||
|             Upgrade.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_available_php_versions(): | ||||
|         """Get list of available PHP versions based on OS""" | ||||
|         # Check for AlmaLinux 9+ first | ||||
|         if os.path.exists('/etc/almalinux-release'): | ||||
|             try: | ||||
|                 with open('/etc/almalinux-release', 'r') as f: | ||||
|                     content = f.read() | ||||
|                     if 'release 9' in content or 'release 10' in content: | ||||
|                         Upgrade.stdOut("AlmaLinux 9+ detected - checking available PHP versions", 1) | ||||
|                         # AlmaLinux 9+ doesn't have PHP 7.1, 7.2, 7.3 | ||||
|                         php_versions = ['74', '80', '81', '82', '83', '84', '85'] | ||||
|                     else: | ||||
|                         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||
|             except: | ||||
|                 php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||
|         else: | ||||
|             # Check other OS versions | ||||
|             os_info = Upgrade.findOperatingSytem() | ||||
|             if os_info in [Ubuntu24, CENTOS8]: | ||||
|                 php_versions = ['74', '80', '81', '82', '83', '84', '85'] | ||||
|             else: | ||||
|                 php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||
|          | ||||
|         # Check availability of each version | ||||
|         available_versions = [] | ||||
|         for version in php_versions: | ||||
|             if Upgrade.check_package_availability(f'lsphp{version}'): | ||||
|                 available_versions.append(version) | ||||
|             else: | ||||
|                 Upgrade.stdOut(f"PHP {version} not available on this OS", 0) | ||||
|          | ||||
|         return available_versions | ||||
|  | ||||
|     @staticmethod | ||||
|     def fixLiteSpeedConfig(): | ||||
|         """Fix LiteSpeed configuration issues by creating missing files""" | ||||
|         try: | ||||
|             Upgrade.stdOut("Checking and fixing LiteSpeed configuration...", 1) | ||||
|              | ||||
|             # Check if LiteSpeed is installed | ||||
|             if not os.path.exists('/usr/local/lsws'): | ||||
|                 Upgrade.stdOut("LiteSpeed not found at /usr/local/lsws", 0) | ||||
|                 return | ||||
|              | ||||
|             # Create missing configuration files | ||||
|             config_files = [ | ||||
|                 "/usr/local/lsws/conf/httpd_config.xml", | ||||
|                 "/usr/local/lsws/conf/httpd.conf", | ||||
|                 "/usr/local/lsws/conf/modsec.conf" | ||||
|             ] | ||||
|              | ||||
|             for config_file in config_files: | ||||
|                 if not os.path.exists(config_file): | ||||
|                     Upgrade.stdOut(f"Missing LiteSpeed config: {config_file}", 0) | ||||
|                      | ||||
|                     # Create directory if it doesn't exist | ||||
|                     os.makedirs(os.path.dirname(config_file), exist_ok=True) | ||||
|                      | ||||
|                     # Create minimal config file | ||||
|                     if config_file.endswith('httpd_config.xml'): | ||||
|                         with open(config_file, 'w') as f: | ||||
|                             f.write('<?xml version="1.0" encoding="UTF-8"?>\n') | ||||
|                             f.write('<httpServerConfig>\n') | ||||
|                             f.write('    <!-- Minimal LiteSpeed configuration -->\n') | ||||
|                             f.write('    <listener>\n') | ||||
|                             f.write('        <name>Default</name>\n') | ||||
|                             f.write('        <address>*:8088</address>\n') | ||||
|                             f.write('    </listener>\n') | ||||
|                             f.write('</httpServerConfig>\n') | ||||
|                     elif config_file.endswith('httpd.conf'): | ||||
|                         with open(config_file, 'w') as f: | ||||
|                             f.write('# Minimal LiteSpeed HTTP configuration\n') | ||||
|                             f.write('# This file will be updated by CyberPanel\n') | ||||
|                     elif config_file.endswith('modsec.conf'): | ||||
|                         with open(config_file, 'w') as f: | ||||
|                             f.write('# ModSecurity configuration\n') | ||||
|                             f.write('# This file will be updated by CyberPanel\n') | ||||
|                      | ||||
|                     Upgrade.stdOut(f"Created minimal config: {config_file}", 1) | ||||
|                 else: | ||||
|                     Upgrade.stdOut(f"LiteSpeed config exists: {config_file}", 1) | ||||
|                      | ||||
|         except Exception as e: | ||||
|             Upgrade.stdOut(f"Error fixing LiteSpeed config: {str(e)}", 0) | ||||
|  | ||||
|     @staticmethod | ||||
|     def installPHP73(): | ||||
|         try: | ||||
|             if Upgrade.installedOutput.find('lsphp73') == -1: | ||||
|                 command = 'yum install -y lsphp73 lsphp73-json lsphp73-xmlrpc lsphp73-xml lsphp73-tidy lsphp73-soap lsphp73-snmp ' \ | ||||
|                           'lsphp73-recode lsphp73-pspell lsphp73-process lsphp73-pgsql lsphp73-pear lsphp73-pdo lsphp73-opcache ' \ | ||||
|                           'lsphp73-odbc lsphp73-mysqlnd lsphp73-mcrypt lsphp73-mbstring lsphp73-ldap lsphp73-intl lsphp73-imap ' \ | ||||
|                           'lsphp73-gmp lsphp73-gd lsphp73-enchant lsphp73-dba  lsphp73-common  lsphp73-bcmath' | ||||
|                 Upgrade.executioner(command, 'Install PHP 73, 0') | ||||
|  | ||||
|             if Upgrade.installedOutput.find('lsphp74') == -1: | ||||
|                 command = 'yum install -y lsphp74 lsphp74-json lsphp74-xmlrpc lsphp74-xml lsphp74-tidy lsphp74-soap lsphp74-snmp ' \ | ||||
|                           'lsphp74-recode lsphp74-pspell lsphp74-process lsphp74-pgsql lsphp74-pear lsphp74-pdo lsphp74-opcache ' \ | ||||
|                           'lsphp74-odbc lsphp74-mysqlnd lsphp74-mcrypt lsphp74-mbstring lsphp74-ldap lsphp74-intl lsphp74-imap ' \ | ||||
|                           'lsphp74-gmp lsphp74-gd lsphp74-enchant lsphp74-dba lsphp74-common  lsphp74-bcmath' | ||||
|  | ||||
|                 Upgrade.executioner(command, 'Install PHP 74, 0') | ||||
|  | ||||
|             if Upgrade.installedOutput.find('lsphp80') == -1: | ||||
|                 command = 'yum install lsphp80* -y' | ||||
|                 subprocess.call(command, shell=True) | ||||
|  | ||||
|             if Upgrade.installedOutput.find('lsphp81') == -1: | ||||
|                 command = 'yum install lsphp81* -y' | ||||
|                 subprocess.call(command, shell=True) | ||||
|  | ||||
|             if Upgrade.installedOutput.find('lsphp82') == -1: | ||||
|                 command = 'yum install lsphp82* -y' | ||||
|                 subprocess.call(command, shell=True) | ||||
|  | ||||
|             command = 'yum install lsphp83* -y' | ||||
|             subprocess.call(command, shell=True) | ||||
|  | ||||
|             command = 'yum install lsphp84* -y' | ||||
|             subprocess.call(command, shell=True) | ||||
|  | ||||
|             command = 'yum install lsphp85* -y' | ||||
|             Upgrade.stdOut("Installing PHP versions based on OS compatibility...", 1) | ||||
|              | ||||
|             # Get available PHP versions | ||||
|             available_versions = Upgrade.get_available_php_versions() | ||||
|              | ||||
|             if not available_versions: | ||||
|                 Upgrade.stdOut("No PHP versions available for installation", 0) | ||||
|                 return | ||||
|              | ||||
|             Upgrade.stdOut(f"Installing available PHP versions: {', '.join(available_versions)}", 1) | ||||
|              | ||||
|             for version in available_versions: | ||||
|                 try: | ||||
|                     if version in ['71', '72', '73', '74']: | ||||
|                         # PHP 7.x versions with specific extensions | ||||
|                         if Upgrade.installedOutput.find(f'lsphp{version}') == -1: | ||||
|                             extensions = ['json', 'xmlrpc', 'xml', 'tidy', 'soap', 'snmp', 'recode', 'pspell', 'process', 'pgsql', 'pear', 'pdo', 'opcache', 'odbc', 'mysqlnd', 'mcrypt', 'mbstring', 'ldap', 'intl', 'imap', 'gmp', 'gd', 'enchant', 'dba', 'common', 'bcmath'] | ||||
|                             package_list = f"lsphp{version} " + " ".join([f"lsphp{version}-{ext}" for ext in extensions]) | ||||
|                             command = f"yum install -y {package_list}" | ||||
|                             Upgrade.executioner(command, f'Install PHP {version}', 0) | ||||
|                     else: | ||||
|                         # PHP 8.x versions | ||||
|                         if Upgrade.installedOutput.find(f'lsphp{version}') == -1: | ||||
|                             command = f"yum install lsphp{version}* -y" | ||||
|             subprocess.call(command, shell=True) | ||||
|                             Upgrade.stdOut(f"Installed PHP {version}", 1) | ||||
|                          | ||||
|                 except Exception as e: | ||||
|                     Upgrade.stdOut(f"Error installing PHP {version}: {str(e)}", 0) | ||||
|                     continue | ||||
|  | ||||
|         except: | ||||
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \ | ||||
| @@ -3997,9 +4174,20 @@ pm.max_spare_servers = 3 | ||||
|     @staticmethod | ||||
|     def setupPHPSymlink(): | ||||
|         try: | ||||
|             # Check if PHP 8.3 exists | ||||
|             if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'): | ||||
|                 Upgrade.stdOut("PHP 8.3 not found, installing it first...") | ||||
|             # Try to find available PHP version (prioritize modern stable versions) | ||||
|             # Priority: 8.3 (recommended), 8.2, 8.4, 8.5, 8.1, 8.0, then older versions | ||||
|             php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71'] | ||||
|             selected_php = None | ||||
|              | ||||
|             for version in php_versions: | ||||
|                 if os.path.exists(f'/usr/local/lsws/lsphp{version}/bin/php'): | ||||
|                     selected_php = version | ||||
|                     Upgrade.stdOut(f"Found PHP {version}, using as default", 1) | ||||
|                     break | ||||
|              | ||||
|             if not selected_php: | ||||
|                 # Try to install PHP 8.3 as fallback (modern stable version) | ||||
|                 Upgrade.stdOut("No PHP found, installing PHP 8.3 as fallback...") | ||||
|                  | ||||
|                 # Install PHP 8.3 based on OS | ||||
|                 if os.path.exists(Upgrade.CentOSPath) or os.path.exists(Upgrade.openEulerPath): | ||||
| @@ -4013,16 +4201,17 @@ pm.max_spare_servers = 3 | ||||
|                 if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'): | ||||
|                     Upgrade.stdOut('[ERROR] Failed to install PHP 8.3') | ||||
|                     return 0 | ||||
|                 selected_php = '83' | ||||
|              | ||||
|             # Remove existing PHP symlink if it exists | ||||
|             if os.path.exists('/usr/bin/php'): | ||||
|                 os.remove('/usr/bin/php') | ||||
|  | ||||
|             # Create symlink to PHP 8.3 | ||||
|             command = 'ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php' | ||||
|             Upgrade.executioner(command, 'Setup PHP Symlink to 8.3', 0) | ||||
|             # Create symlink to selected PHP version | ||||
|             command = f'ln -s /usr/local/lsws/lsphp{selected_php}/bin/php /usr/bin/php' | ||||
|             Upgrade.executioner(command, f'Setup PHP Symlink to {selected_php}', 0) | ||||
|  | ||||
|             Upgrade.stdOut("PHP symlink updated to PHP 8.3 successfully.") | ||||
|             Upgrade.stdOut(f"PHP symlink updated to PHP {selected_php} successfully.") | ||||
|  | ||||
|         except BaseException as msg: | ||||
|             Upgrade.stdOut('[ERROR] ' + str(msg) + " [setupPHPSymlink]") | ||||
| @@ -4150,6 +4339,9 @@ pm.max_spare_servers = 3 | ||||
|         Upgrade.manageServiceMigrations() | ||||
|         Upgrade.enableServices() | ||||
|  | ||||
|         # Apply AlmaLinux 9 fixes before other installations | ||||
|         Upgrade.fix_almalinux9_mariadb() | ||||
|  | ||||
|         Upgrade.installPHP73() | ||||
|         Upgrade.setupCLI() | ||||
|         Upgrade.someDirectories() | ||||
| @@ -4158,6 +4350,9 @@ pm.max_spare_servers = 3 | ||||
|          | ||||
|         ## Fix Apache configuration issues after upgrade | ||||
|         Upgrade.fixApacheConfiguration() | ||||
|          | ||||
|         # Fix LiteSpeed configuration files if missing | ||||
|         Upgrade.fixLiteSpeedConfig() | ||||
|  | ||||
|         ### General migrations are not needed any more | ||||
|  | ||||
| @@ -4191,8 +4386,32 @@ pm.max_spare_servers = 3 | ||||
|         except: | ||||
|             pass | ||||
|  | ||||
|         command = 'cp /usr/local/lsws/lsphp80/bin/lsphp %s' % (phpPath) | ||||
|         # Try to find available PHP binary in order of preference (modern stable first) | ||||
|         php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71'] | ||||
|         php_binary_found = False | ||||
|          | ||||
|         for version in php_versions: | ||||
|             php_binary = f'/usr/local/lsws/lsphp{version}/bin/lsphp' | ||||
|             if os.path.exists(php_binary): | ||||
|                 command = f'cp {php_binary} {phpPath}' | ||||
|         Upgrade.executioner(command, 0) | ||||
|                 Upgrade.stdOut(f"Using PHP {version} for LSCPD", 1) | ||||
|                 php_binary_found = True | ||||
|                 break | ||||
|          | ||||
|         if not php_binary_found: | ||||
|             Upgrade.stdOut("Warning: No PHP binary found for LSCPD", 0) | ||||
|             # Try to create a symlink to any available PHP | ||||
|             try: | ||||
|                 command = 'find /usr/local/lsws -name "lsphp" -type f 2>/dev/null | head -1' | ||||
|                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||
|                 if result.stdout.strip(): | ||||
|                     php_binary = result.stdout.strip() | ||||
|                     command = f'cp {php_binary} {phpPath}' | ||||
|                     Upgrade.executioner(command, 0) | ||||
|                     Upgrade.stdOut(f"Using found PHP binary: {php_binary}", 1) | ||||
|             except: | ||||
|                 pass | ||||
|  | ||||
|         if Upgrade.SoftUpgrade == 0: | ||||
|             try: | ||||
| @@ -4200,6 +4419,42 @@ pm.max_spare_servers = 3 | ||||
|                 Upgrade.executioner(command, 'Start LSCPD', 0) | ||||
|             except: | ||||
|                 pass | ||||
|              | ||||
|             # Try to start other services if they exist | ||||
|             # Enhanced service startup with AlmaLinux 9 support | ||||
|             services_to_start = ['fastapi_ssh_server', 'cyberpanel'] | ||||
|              | ||||
|             # Special handling for AlmaLinux 9 MariaDB service | ||||
|             if Upgrade.is_almalinux9(): | ||||
|                 Upgrade.stdOut("AlmaLinux 9 detected - applying enhanced service management", 1) | ||||
|                 mariadb_services = ['mariadb', 'mysql', 'mysqld'] | ||||
|                 for service in mariadb_services: | ||||
|                     try: | ||||
|                         check_command = f"systemctl list-unit-files | grep -q {service}" | ||||
|                         result = subprocess.run(check_command, shell=True, capture_output=True) | ||||
|                         if result.returncode == 0: | ||||
|                             command = f"systemctl restart {service}" | ||||
|                             Upgrade.executioner(command, f'Restart {service} for AlmaLinux 9', 0) | ||||
|                             command = f"systemctl enable {service}" | ||||
|                             Upgrade.executioner(command, f'Enable {service} for AlmaLinux 9', 0) | ||||
|                             Upgrade.stdOut(f"MariaDB service managed as {service} on AlmaLinux 9", 1) | ||||
|                             break | ||||
|                     except Exception as e: | ||||
|                         Upgrade.stdOut(f"Could not manage MariaDB service {service}: {str(e)}", 0) | ||||
|                         continue | ||||
|              | ||||
|             for service in services_to_start: | ||||
|                 try: | ||||
|                     # Check if service exists | ||||
|                     check_command = f"systemctl list-unit-files | grep -q {service}" | ||||
|                     result = subprocess.run(check_command, shell=True, capture_output=True) | ||||
|                     if result.returncode == 0: | ||||
|                         command = f"systemctl start {service}" | ||||
|                         Upgrade.executioner(command, f'Start {service}', 0) | ||||
|                     else: | ||||
|                         Upgrade.stdOut(f"Service {service} not found, skipping", 0) | ||||
|                 except Exception as e: | ||||
|                     Upgrade.stdOut(f"Could not start {service}: {str(e)}", 0) | ||||
|  | ||||
|         # Remove CSF if installed and restore firewalld (CSF is being discontinued on August 31, 2025) | ||||
|         if os.path.exists('/etc/csf'): | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user