name : ConfigurepermissionsModel.php
<?php
/**
 * @package   admintools
 * @copyright Copyright (c)2010-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AdminTools\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Component\AdminTools\Administrator\Helper\Storage;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;

#[\AllowDynamicProperties]
class ConfigurepermissionsModel extends BaseDatabaseModel
{
	public $list = [];

	/**
	 * Saves the default file permissions to the Admin Tools parameters storage
	 */
	public function saveDefaults()
	{
		$dirperms  = $this->getState('dirperms');
		$fileperms = $this->getState('fileperms');

		$dirperms = octdec($dirperms);

		if (($dirperms < 0600) || ($dirperms > 0777))
		{
			$dirperms = 0755;
		}

		$fileperms = octdec($fileperms);
		if (($fileperms < 0600) || ($fileperms > 0777))
		{
			$fileperms = 0755;
		}

		$params = Storage::getInstance();

		$params->setValue('dirperms', '0' . decoct($dirperms));
		$params->setValue('fileperms', '0' . decoct($fileperms));
		$params->setValue('perms_show_hidden', $this->getState('perms_show_hidden', 0));

		$params->save();
	}

	/**
	 * Updates the listing with the records matching the filter_path state
	 */
	public function applyPath(): void
	{
		// Get and clean up the path
		$path    = $this->getState('path', '');
		$relpath = $this->getRelativePath($path);

		$this->setState('filter_path', $relpath);

		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->quoteName('#__admintools_customperms'));

		$fltPath = $this->getState('filter_path');

		if (!empty($fltPath))
		{
			$fltPath = $fltPath . '%';
			$query->where($db->quoteName('path') . ' LIKE :path')
				->bind(':path', $fltPath);
		}

		$fltPerms = $this->getState('perms', null);

		if (!empty($fltPerms))
		{
			$query->where($db->qn('perms') . ' = :permissions')
				->bind(':permissions', $fltPerms);
		}

		$this->list = $db->setQuery($query)->loadAssocList() ?: [];
	}

	public function getRelativePath(string $pathRelativeToRoot): string
	{
		$path = JPATH_ROOT . '/' . $pathRelativeToRoot;
		$path = Path::clean($path, '/');

		// Clean up the root
		$root = Path::clean(JPATH_ROOT, '/');

		// Find the relative path and get the custom permissions
		return ltrim(substr($path, strlen($root)), '/');
	}

	public function getListing(): array
	{
		$this->applyPath();

		$siteLocalPath = $this->getState('filter_path', '');
		$absolutePath  = JPATH_ROOT . '/' . $siteLocalPath;
		$params        = Storage::getInstance();
		$excludeFilter = $params->getValue('perms_show_hidden', 0) ? ['.*~'] : ['^\..*', '.*~'];
		try
		{
			$folders = Folder::folders($absolutePath);
		}
		catch (\Exception $e)
		{
			$folders = [];
		}
		$folders_raw = $folders ?: [];
		try
		{
			$files = Folder::files(
				$absolutePath, '.', false, false, [
				'.svn',
				'CVS',
				'.DS_Store',
				'__MACOSX',
			], $excludeFilter
			);
		}
		catch (\Exception $e)
		{
			$files = [];
		}
		$files_raw = $files ?: [];

		return [
			'folders' => array_map([$this, 'convertIntoPathListing'], $folders_raw),
			'files'   => array_map([$this, 'convertIntoPathListing'], $files_raw),
			'crumbs'  => explode('/', $siteLocalPath),
		];
	}

	public function getPerms(string $pathRelativeToSiteRoot): string
	{
		$key = array_search($pathRelativeToSiteRoot, array_column($this->list, 'path'));

		return ($key === false) ? '' : $this->list[$key]['perms'];
	}

	public function savePermissions(bool $apply = false)
	{
		$this->applyAndSavePermissions($this->getState('folders', []) ?: [], $apply, 'folder');
		$this->applyAndSavePermissions($this->getState('files', []) ?: [], $apply, 'file');
	}

	private function applyAndSavePermissions(array $pathsAndPerms, bool $apply = false, string $type = 'folder')
	{
		if (empty($pathsAndPerms))
		{
			return;
		}

		// Delete all entries for the contained folders
		$db            = $this->getDatabase();
		$pathsToDelete = array_keys($pathsAndPerms);

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->delete($db->quoteName('#__admintools_customperms'))
			->whereIn($db->quoteName('path'), $pathsToDelete, ParameterType::STRING);
		$db->setQuery($query)->execute();

		// Fix permissions, if requested
		if ($apply)
		{
			$params       = Storage::getInstance();
			$defaultPerms = ($type === 'folder') ? 0755 : 0644;
			$defaultPerms = $params->getValue(($type === 'folder') ? 'dirperms' : 'fileperms', $defaultPerms);

			/** @var FixpermissionsModel $fixmodel */
			$fixmodel = $this->getMVCFactory()->createModel('Fixpermissions', 'Administrator');

			array_map(
				function ($path, $perms) use ($defaultPerms, $fixmodel) {
					$fixmodel->chmod($path, $perms ?: $defaultPerms);
				}, array_keys($pathsAndPerms), $pathsAndPerms
			);
		}

		// First, let's remove array items without custom permissions
		$pathsAndPerms = array_filter(
			$pathsAndPerms, function ($perms) {
			return !empty($perms);
		}
		);

		// Making sure there are any records with custom permissions left.
		if (empty($pathsAndPerms))
		{
			return;
		}

		// Save the remaining custom permissions to the database
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->insert($db->qn('#__admintools_customperms'))
			->columns(
				[
					$db->quoteName('path'),
					$db->quoteName('perms'),
				]
			);

		foreach ($pathsAndPerms as $folder => $perms)
		{
			$query->values($db->quote($folder) . ',' . $db->quote($perms));
		}

		$db->setQuery($query)->execute();
	}

	private function convertIntoPathListing(string $relativePath): array
	{
		$siteLocalPath      = $this->getState('filter_path', '');
		$siteLocalPath      .= empty($siteLocalPath) ? '' : '/';
		$perms              = $this->getPerms($siteLocalPath . $relativePath);
		$currentPermissions = @fileperms(JPATH_ROOT . '/' . $siteLocalPath . $relativePath);
		$ownerUser          = function_exists('fileowner') ? @fileowner(
			JPATH_ROOT . '/' . $siteLocalPath . $relativePath
		) : false;
		$ownerGroup         = function_exists('filegroup') ? @filegroup(
			JPATH_ROOT . '/' . $siteLocalPath . $relativePath
		) : false;

		return [
			'item'      => $relativePath,
			'path'      => $siteLocalPath . $relativePath,
			'perms'     => $perms,
			'realperms' => $currentPermissions,
			'uid'       => $ownerUser,
			'gid'       => $ownerGroup,
		];
	}
}

© 2025 Cubjrnet7