<?php

/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Filesystem;

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
 * File system helper
 *
 * Holds support functions for the filesystem, particularly the stream
 *
 * @since  1.7.0
 * @deprecated  4.4 will be removed in 6.0
 *              Use Joomla\Filesystem\Helper instead.
 */
class FilesystemHelper
{
    /**
     * Remote file size function for streams that don't support it
     *
     * @param   string  $url  Link identifier
     *
     * @return  mixed
     *
     * @link    https://www.php.net/manual/en/function.filesize.php
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::remotefsize() instead.
     */
    public static function remotefsize($url)
    {
        $sch = parse_url($url, PHP_URL_SCHEME);

        if (($sch !== 'http') && ($sch !== 'https') && ($sch !== 'ftp') && ($sch !== 'ftps')) {
            return false;
        }

        if (($sch === 'http') || ($sch === 'https')) {
            $headers = get_headers($url, 1);

            if ((!\array_key_exists('Content-Length', $headers))) {
                return false;
            }

            return $headers['Content-Length'];
        }

        if (($sch === 'ftp') || ($sch === 'ftps')) {
            $server = parse_url($url, PHP_URL_HOST);
            $port   = parse_url($url, PHP_URL_PORT);
            $path   = parse_url($url, PHP_URL_PATH);
            $user   = parse_url($url, PHP_URL_USER);
            $pass   = parse_url($url, PHP_URL_PASS);

            if ((!$server) || (!$path)) {
                return false;
            }

            if (!$port) {
                $port = 21;
            }

            if (!$user) {
                $user = 'anonymous';
            }

            if (!$pass) {
                $pass = '';
            }

            switch ($sch) {
                case 'ftp':
                    $ftpid = ftp_connect($server, $port);
                    break;

                case 'ftps':
                    $ftpid = ftp_ssl_connect($server, $port);
                    break;
            }

            if (!$ftpid) {
                return false;
            }

            $login = ftp_login($ftpid, $user, $pass);

            if (!$login) {
                return false;
            }

            $ftpsize = ftp_size($ftpid, $path);
            ftp_close($ftpid);

            if ($ftpsize == -1) {
                return false;
            }

            return $ftpsize;
        }
    }

    /**
     * Quick FTP chmod
     *
     * @param   string   $url   Link identifier
     * @param   integer  $mode  The new permissions, given as an octal value.
     *
     * @return  mixed
     *
     * @link    https://www.php.net/manual/en/function.ftp-chmod.php
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::ftpChmod() instead.
     */
    public static function ftpChmod($url, $mode)
    {
        $sch = parse_url($url, PHP_URL_SCHEME);

        if (($sch !== 'ftp') && ($sch !== 'ftps')) {
            return false;
        }

        $server = parse_url($url, PHP_URL_HOST);
        $port   = parse_url($url, PHP_URL_PORT);
        $path   = parse_url($url, PHP_URL_PATH);
        $user   = parse_url($url, PHP_URL_USER);
        $pass   = parse_url($url, PHP_URL_PASS);

        if ((!$server) || (!$path)) {
            return false;
        }

        if (!$port) {
            $port = 21;
        }

        if (!$user) {
            $user = 'anonymous';
        }

        if (!$pass) {
            $pass = '';
        }

        switch ($sch) {
            case 'ftp':
                $ftpid = ftp_connect($server, $port);
                break;

            case 'ftps':
                $ftpid = ftp_ssl_connect($server, $port);
                break;
        }

        if (!$ftpid) {
            return false;
        }

        $login = ftp_login($ftpid, $user, $pass);

        if (!$login) {
            return false;
        }

        $res = ftp_chmod($ftpid, $mode, $path);
        ftp_close($ftpid);

        return $res;
    }

    /**
     * Modes that require a write operation
     *
     * @return  array
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::getWriteModes() instead.
     */
    public static function getWriteModes()
    {
        return ['w', 'w+', 'a', 'a+', 'r+', 'x', 'x+'];
    }

    /**
     * Stream and Filter Support Operations
     *
     * Returns the supported streams, in addition to direct file access
     * Also includes Joomla! streams as well as PHP streams
     *
     * @return  array  Streams
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::getSupported() instead.
     */
    public static function getSupported()
    {
        // Really quite cool what php can do with arrays when you let it...
        static $streams;

        if (!$streams) {
            $streams = array_merge(stream_get_wrappers(), self::getJStreams());
        }

        return $streams;
    }

    /**
     * Returns a list of transports
     *
     * @return  array
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::getTransports() instead.
     */
    public static function getTransports()
    {
        // Is this overkill?
        return stream_get_transports();
    }

    /**
     * Returns a list of filters
     *
     * @return  array
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::getFilters() instead.
     */
    public static function getFilters()
    {
        // Note: This will look like the getSupported() function with J! filters.
        // @todo: add user space filter loading like user space stream loading
        return stream_get_filters();
    }

    /**
     * Returns a list of J! streams
     *
     * @return  array
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::getJStreams() instead.
     */
    public static function getJStreams()
    {
        static $streams = [];

        if (!$streams) {
            $files = new \DirectoryIterator(__DIR__ . '/Streams');

            /** @var  $file  \DirectoryIterator */
            foreach ($files as $file) {
                // Only load for php files.
                if (!$file->isFile() || $file->getExtension() !== 'php') {
                    continue;
                }

                $streams[] = str_replace('stream', '', strtolower($file->getBasename('.php')));
            }
        }

        return $streams;
    }

    /**
     * Determine if a stream is a Joomla stream.
     *
     * @param   string  $streamname  The name of a stream
     *
     * @return  boolean  True for a Joomla Stream
     *
     * @since   1.7.0
     * @deprecated  4.4 will be removed in 6.0
     *              Use Joomla\Filesystem\Helper::isJoomlaStream() instead.
     */
    public static function isJoomlaStream($streamname)
    {
        return \in_array($streamname, self::getJStreams());
    }

    /**
     * Calculates the maximum upload file size and returns string with unit or the size in bytes
     *
     * Call it with JFilesystemHelper::fileUploadMaxSize();
     *
     * @param   bool  $unitOutput  This parameter determines whether the return value should be a string with a unit
     *
     * @return  float|string The maximum upload size of files with the appropriate unit or in bytes
     *
     * @since   3.4
     */
    public static function fileUploadMaxSize($unitOutput = true)
    {
        static $max_size    = false;
        static $output_type = true;

        if ($max_size === false || $output_type != $unitOutput) {
            $max_size   = self::parseSize(\ini_get('post_max_size'));
            $upload_max = self::parseSize(\ini_get('upload_max_filesize'));

            if ($upload_max > 0 && ($upload_max < $max_size || $max_size == 0)) {
                $max_size = $upload_max;
            }

            if ($unitOutput) {
                $max_size = self::parseSizeUnit($max_size);
            }

            $output_type = $unitOutput;
        }

        return $max_size;
    }

    /**
     * Returns the size in bytes without the unit for the comparison
     *
     * @param   string  $size  The size which is received from the PHP settings
     *
     * @return  float The size in bytes without the unit
     *
     * @since   3.4
     */
    private static function parseSize($size)
    {
        $unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
        $size = preg_replace('/[^0-9\.]/', '', $size);

        $return = round($size);

        if ($unit) {
            $return = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
        }

        return $return;
    }

    /**
     * Creates the rounded size of the size with the appropriate unit
     *
     * @param   float  $maxSize  The maximum size which is allowed for the uploads
     *
     * @return  string String with the size and the appropriate unit
     *
     * @since   3.4
     */
    private static function parseSizeUnit($maxSize)
    {
        $base     = log($maxSize) / log(1024);
        $suffixes = ['', 'k', 'M', 'G', 'T'];

        return round(pow(1024, $base - floor($base)), 0) . $suffixes[floor($base)];
    }
}
