<?php
/**
 * @package     CMGiftCard
 * @subpackage  com_cmgiftcard
 * @copyright   Copyright (C) 2016-2024 CMExension
 * @license     GNU General Public License version 2 or later
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Filesystem\Path;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Session\Session;
use Joomla\CMS\MVC\Controller\BaseController;

/**
 * Controller class for tools.
 *
 * @package     CMGiftCard
 * @subpackage  com_cmgiftcard
 * @since       1.0.0
 */
class CMGiftCardControllerTools extends BaseController
{
	/**
	 * Upload gift card code.
	 *
	 * @return  boolean
	 *
	 * @since   1.0.0
	 */
	public function uploadCode()
	{
		Session::checkToken() or jexit(Text::_('JINVALID_TOKEN'));

		$this->setRedirect('index.php?option=com_cmgiftcard&view=tools');

		$app = Factory::getApplication();
		$jinput = $app->input;
		$file = $jinput->files->get('code_file', null, 'raw');

		if (empty($file) || empty($file['name']))
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_FILE_EMPTY'), 'error');

			return false;
		}

		$fileTypes = explode('.', $file['name']);

		if (count($fileTypes) < 2)
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_INVALID_FILE_TYPE'), 'error');

			return false;
		}

		array_shift($fileTypes);

		// Check if the file has an executable extension.
		$executable = array(
			'php', 'js', 'exe', 'phtml', 'java', 'perl', 'py', 'asp','dll', 'go', 'ade', 'adp', 'bat', 'chm', 'cmd', 'com', 'cpl', 'hta', 'ins', 'isp',
			'jse', 'lib', 'mde', 'msc', 'msp', 'mst', 'pif', 'scr', 'sct', 'shb', 'sys', 'vb', 'vbe', 'vbs', 'vxd', 'wsc', 'wsf', 'wsh'
		);

		$check = array_intersect($fileTypes, $executable);

		if (!empty($check))
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_INVALID_FILE_TYPE'), 'error');

			return false;
		}

		$fileType = array_pop($fileTypes);

		if ($fileType != 'txt')
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_INVALID_FILE_TYPE'), 'error');

			return false;
		}

		// Total length of post back data in bytes.
		$contentLength = (int) $_SERVER['CONTENT_LENGTH'];

		// Maximum allowed size of post back data in MB.
		$postMaxSize = (int) ini_get('post_max_size');

		// Maximum allowed size of script execution in MB.
		$memoryLimit = (int) ini_get('memory_limit');

		// Check for the total size of post back data.
		if (($postMaxSize > 0 && $contentLength > $postMaxSize * 1024 * 1024)
			|| ($memoryLimit != -1 && $contentLength > $memoryLimit * 1024 * 1024))
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_FILE_TOO_LARGE'), 'error');

			return false;
		}

		$uploadMaxFileSize = $this->toBytes(ini_get('upload_max_filesize'));

		if (($file['error'] == 1)
			|| ($uploadMaxFileSize > 0 && $file['size'] > $uploadMaxFileSize))
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_FILE_TOO_LARGE'), 'error');

			return false;
		}

		// Make the file name unique.
		$md5String = $file['name'] . Factory::getDate();
		$fileName = File::makeSafe('com_cmgiftcard_code_' . md5($md5String) . rand(1, 10000));
		$target = Path::clean(JPATH_ROOT . '/administrator/components/com_cmgiftcard/uploads/' . $fileName);

		$handle = fopen($file['tmp_name'], 'r');

		if ($handle)
		{
			$fileData = "";

			while (($line = fgets($handle)) !== false)
			{
				$line = strip_tags($line);

				if ($line != '')
					$fileData .= $line . "\n";
			}

			if (!File::write($target, $fileData))
			{
				$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_UPLOAD_FAILED'), 'error');

				return false;
			}
		}
		else
		{
			$this->setMessage(Text::_('COM_CMGIFTCARD_TOOLS_CODE_UPLOAD_FAILED'), 'error');

			return false;
		}

		fclose($handle);

		$app->setUserState('com_cmgiftcard.tools.code_file', $fileName);
		$this->setRedirect('index.php?option=com_cmgiftcard&view=tools&codeupload=1');

		return true;
	}

	/**
	 * Small helper function that properly converts any
	 * configuration options to their byte representation.
	 * From libraries/cms/helper/media.php
	 *
	 * @param   string|integer  $val  The value to be converted to bytes.
	 *
	 * @return  integer  The calculated bytes value from the input.
	 *
	 * @since 1.0.0
	 */
	protected function toBytes($val)
	{
		switch ($val[strlen($val) - 1])
		{
			case 'M':
			case 'm':
				return (int) $val * 1048576;
			case 'K':
			case 'k':
				return (int) $val * 1024;
			case 'G':
			case 'g':
				return (int) $val * 1073741824;
			default:
				return $val;
		}
	}
}
