piotrpolak/pepiscms

View on GitHub
pepiscms/application/controllers/admin/Ajaxfilemanager.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/**
 * PepisCMS
 *
 * Simple content management system
 *
 * @package             PepisCMS
 * @author              Piotr Polak
 * @copyright           Copyright (c) 2007-2018, Piotr Polak
 * @license             See license.txt
 * @link                http://www.polak.ro/
 */

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * Filemanager controller
 */
class Ajaxfilemanager extends AdminController
{

    private $uploadsPath = '';

    public function __construct()
    {
        parent::__construct();
        if ($this->config->item('cms_enable_filemanager') === false || !$this->config->item('feature_is_enabled_filemanager')) {
            show_error($this->lang->line('global_feature_not_enabled'));
        }

        $this->assign('is_editor', false);
        $this->load->language('filemanager');

        $this->assign('title', $this->lang->line('filemanager_label'));

        $this->uploadsPath = $this->config->item('uploads_path');
    }

    public function index()
    {
        redirect(admin_url() . 'ajaxfilemanager/browse/');
    }

    public function getjsonfilelist()
    {
        $files = $dirs = array();
        $user_files_dir = $this->uploadsPath;
        $current_path = isset($_POST['path']) ? str_replace('//', '/', str_replace('../', '', $_POST['path'] . '/')) : '/';

        if (is_dir($user_files_dir . $current_path)) {
            $directory = opendir($user_files_dir . $current_path);
            while ($file = readdir($directory)) {
                if ($file == '..' || $file == '.') {
                    continue;
                }
                $f = [
                    'mtime' => 0,
                    'ctime' => 0,
                    'size' => 0,
                ];
                $file_path = $user_files_dir . $current_path . $file;
                $f['name'] = htmlspecialchars($file);

                if (is_readable($file_path)){
                    $f['mtime'] = filemtime($file_path);
                    $f['ctime'] = filectime($file_path);
                    $f['size'] = filesize($file_path);
                }
                if (is_dir($file_path)) {
                    $dirs[$file] = $f;
                } else {
                    $files[$file] = $f;
                }
            }

            ksort($dirs);
            ksort($files);

            $response = array(
                'status' => 1,
                'message' => 'OK',
                'time' => time(),
                'path' => $current_path,
                'directories' => array(),
                'files' => array(),
            );

            foreach ($dirs as $f) {
                $response['directories'][] = array(
                    'name' => $f['name'],
                    'mtime' => $f['mtime'],
                    'ctime' => $f['ctime'],
                    'size' => '-1',
                );
            }
            foreach ($files as $f) {
                $response['files'][] = array(
                    'name' => $f['name'],
                    'mtime' => $f['mtime'],
                    'ctime' => $f['ctime'],
                    'size' => $f['size'],
                );
            }
        } else {
            $response = array(
                'status' => 0,
                'message' => $this->lang->line('filemanager_dialog_path_not_found_error'),
                'time' => time(),
                'path' => $current_path,
            );
        }
        //usleep(100000); // For interface testing only

        $this->output->set_header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT')
            ->set_header('Cache-Control: no-store, no-cache, must-revalidate')
            ->set_header('Cache-Control: post-check=0, pre-check=0')
            ->set_header('Pragma: no-cache')
            ->set_header('Content-type: application/x-javascript');


        $this->output->append_output(json_encode($response));
    }

    /**
     * This is page dedicated for editors
     */
    public function editorbrowse()
    {
        $this->assign('is_editor', true)
            ->assign('popup_layout', true)
            ->assign('adminmenu', '');

        $this->browse();
    }

    public function browse()
    {
        $this->assign('upload_allowed_types', explode('|', $this->config->item('upload_allowed_types')))
            ->display('admin/ajaxfilemanager_browse.php');
    }

    public function sendcommand()
    {
        $command = $_POST['command'];
        $currentRelativePath = $_POST['path'];

        /**
         * @var \PiotrPolak\PepisCMS\Filemanager\Command\CommandInterface[]
         */
        $commands = array(
            new \PiotrPolak\PepisCMS\Filemanager\Command\CreateCommand(),
            new \PiotrPolak\PepisCMS\Filemanager\Command\DeleteCommand(),
            new \PiotrPolak\PepisCMS\Filemanager\Command\MoveCommand(),
            new \PiotrPolak\PepisCMS\Filemanager\Command\RenameCommand(),
        );


        $command = $this->getMatchedCommand($commands, $command);

        try {
            $command->execute($this->uploadsPath, $currentRelativePath, $this->input);
        } catch (\PiotrPolak\PepisCMS\Filemanager\Command\CommandException $e) {
            return $this->sendStatus($e->getMessage());
        }

        $this->sendStatus();
    }

    public function upload()
    {
        if (!isset($_POST['path'])) {
            $this->sendStatus('Path not found');
            return;
        }

        if ($_POST['path'][0] == '/') {
            $_POST['path'] = substr($_POST['path'], 1);
        }

        echo $this->genericupload($_POST['path']);
    }

    private function genericupload($current_path = '', $file_field_name = 'file')
    {
        $make_filenames_nice = true;

        $error = false;

        $config['upload_path'] = $this->uploadsPath . $current_path;
        $config['allowed_types'] = $this->config->item('upload_allowed_types');

        $this->load->library('upload', $config);

        if (!$this->upload->do_upload($file_field_name)) {
            $error = $this->upload->display_errors('', '');
        }

        if (!$error) {
            if ($make_filenames_nice) {
                $this->load->helper('string');
                $udata = $this->upload->data();
                $filename = $udata['file_name'];

                $ext = strtolower(substr(strrchr($filename, '.'), 1));
                $fname_length = (strlen($filename) - strlen($ext) - 1);
                $fname = substr($filename, 0, $fname_length);

                $nice_file_name = niceuri($fname) . '.' . $ext;

                if ($nice_file_name != $filename) {
                    if (!file_exists($udata['file_path'] . $nice_file_name || strtolower($filename) == $nice_file_name)) {
                        rename($udata['full_path'], $udata['file_path'] . $nice_file_name);
                        $udata['file_name'] = $nice_file_name;
                    }
                }
            }

            LOGGER::info('Uploading file: ' . $current_path . $udata['file_name'], 'FILEMANAGER');
            return $this->sendStatus();
        } else {
            return $this->sendStatus($error);
        }
    }

    public function thumb()
    {
        return $this->genericthumb();
    }

    private function genericthumb($absolute = false, $size = 50, $current_path = false)
    {
        if (!$current_path) {
            $start_word = 'thumb';
            $pos = strpos($_SERVER['REQUEST_URI'], $start_word);
            $current_path = str_replace('/../', '', substr($_SERVER['REQUEST_URI'], $pos + strlen($start_word)) . '/');
            $current_path = str_replace('//', '/', $current_path);

            $i = strlen($current_path) - 1;
            if ($current_path[$i] == '/') {
                $current_path = substr($current_path, 0, $i);
            }
            if ($current_path[0] == '/') {
                $current_path = substr($current_path, 1);
            }
        }

        $image_path = $absolute ? '' : $this->uploadsPath;

        $cache_path = $this->config->item('cache_path');
        $cache_path = ($cache_path === '') ? 'application/cache/' : $cache_path;
        if ($cache_path[0] !== '/') {
            $cache_path = INSTALLATIONPATH . $cache_path;
        }
        $cache_path .= '_thumbs/';

        if (!file_exists($cache_path)) {
            if (!@mkdir($cache_path)) {
                LOGGER::warning('Unable to generate thumb cache directory', 'FILEMANAGER');
                show_error($this->lang->line('filemanager_unable_to_generate_thumb_directory'));
            }
        }

        $source_file = $image_path . $current_path;

        if (file_exists($source_file)) {
            $hash = md5(filemtime($source_file) . filesize($source_file));
            $thumb_file = $cache_path . $hash . '__s' . $size . '.jpg';

            if (!file_exists($thumb_file)) {
                $config = array();
                $config['source_image'] = $source_file;
                $config['new_image'] = $thumb_file;
                $config['width'] = $size;
                $config['height'] = $size;
                $config['image_library'] = 'gd2';

                $this->load->library('Image_lib', $config);
                if (!$this->image_lib->resize()) {
                    LOGGER::warning('Unable to generate thumb ' . $thumb_file . ' ' . strip_tags($this->image_lib->display_errors()), 'FILEMANAGER');
                    echo $thumb_file . ' - ';
                    echo strip_tags($this->image_lib->display_errors());
                    die();
                }
            }
        } else {
            $thumb_file = APPPATH . '../theme/img/ajaxfilemanager/broken_image_50.png';
        }

        $cache_seconds_valid = (3600 * 24);

        header_remove('Pragma');
        header('Content-type: image/jpg');
        header('Cache-Control: max-age=' . $cache_seconds_valid . ', private');
        header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_seconds_valid) . ' GMT');

        readfile($thumb_file);
        die();
    }

    public function getpathsjson()
    {
        parse_str(substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], '?') + 1), $_GET);
        $_GET['term'] = str_replace('../', '', $_GET['term']);
        $path = $this->uploadsPath . $_GET['term'] . '*';

        $len = strlen($this->uploadsPath);

        $paths = glob($path, GLOB_ONLYDIR);
        foreach ($paths as &$path) {
            $path = substr($path, $len);
        }

        echo json_encode($paths);
    }

    /**
     * File proxy for intranet systems
     */
    public function getfile()
    {
        $max = $this->uri->total_segments() + 1;
        $current_path = '';
        for ($i = 4; $i < $max; $i++) {
            $current_path .= '/' . $this->uri->segment($i);
        }

        $current_path = str_replace('/../', '', $current_path);
        $current_path = str_replace('//', '/', $current_path);

        $i = strlen($current_path) - 1;
        if ($current_path[$i] == '/') {
            $current_path = substr($current_path, 0, $i);
        }
        if ($current_path[0] == '/') {
            $current_path = substr($current_path, 1);
        }

        $current_path = INSTALLATIONPATH . $this->uploadsPath . $current_path;

        if (!file_exists($current_path)) {
            LOGGER::notice('Error 404, accessing inexisting file: ' . $current_path, 'FILEMANAGER');
            show_404();
        }

        LOGGER::info('Accessing file: ' . $current_path, 'FILEMANAGER');

        header('PepisCMS-intranet-secured: yes');

        $this->load->helper('file');
        $basename = basename($current_path);
        $mime = get_mime_by_extension(strtolower($basename));
        header('Content-type: ' . $mime);
        header('Content-Disposition: inline; filename="' . $basename . '"');
        readfile($current_path);
        die();
    }

    /**
     * @param array $commands
     * @param $command
     * @return \PiotrPolak\PepisCMS\Filemanager\Command\CommandInterface
     */
    private function getMatchedCommand(array $commands, $command)
    {
        foreach ($commands as $c) {
            if ($c->getName() == $command) {
                return $c;
            }
        }

        throw new \RuntimeException('No command handler found for ' . $command);
    }

    private function sendStatus($errorMessage = false)
    {
        $errors = array();
        if ($errorMessage) {
            $errors[] = $errorMessage;
        }

        $response = array(
            'status' => $errorMessage ? 0 : 1,
            'errors' => $errors,
        );

        header('Content-type: application/x-javascript');
        die(json_encode($response));
    }
}