Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 240
FileController
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
2070
0.00% covered (danger)
0.00%
0 / 240
 __construct
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 5
 index
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 41
 view
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 9
 create
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 27
 delete
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 11
 download
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 26
 upload
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 19
 getJsArrayList
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 12
 getTree
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 29
 getFileList
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 2
 anonymous function
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 4
 normalizePath
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 checkDir
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 5
 convertStrFromServer
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 convertStrToServer
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
<?php
/*
 * This file is part of EC-CUBE
 *
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
 *
 * http://www.lockon.co.jp/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
namespace Eccube\Controller\Admin\Content;
use Eccube\Application;
use Eccube\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class FileController extends AbstractController
{
    const SJIS = 'sjis-win';
    const UTF = 'UTF-8';
    private $error = null;
    private $encode = '';
    public function __construct(){
        $this->encode = self::UTF;
        if ('\\' === DIRECTORY_SEPARATOR) {
            $this->encode = self::SJIS;
        }
    }
    public function index(Application $app, Request $request)
    {
        $form = $app['form.factory']->createBuilder('form')
            ->add('file', 'file')
            ->add('create_file', 'text')
            ->getForm();
        // user_data_dir
        $topDir = $this->normalizePath($app['config']['user_data_realdir']);
        // user_data_dirの親ディレクトリ
        $htmlDir = $this->normalizePath($topDir.'/../');
        // カレントディレクトリ
        $nowDir = $this->checkDir($request->get('tree_select_file'), $topDir)
            ? $this->normalizePath($request->get('tree_select_file'))
            : $topDir;
        // パンくず表示用データ
        $nowDirList = json_encode(explode('/', trim(str_replace($htmlDir, '', $nowDir), '/')));
        $isTopDir = ($topDir === $nowDir);
        $parentDir = substr($nowDir, 0, strrpos($nowDir, '/'));
        switch ($request->get('mode')) {
            case 'create':
                $this->create($app, $request);
                break;
            case 'upload':
                $this->upload($app, $request);
                break;
            default:
                break;
        }
        $tree = $this->getTree($topDir, $request);
        $arrFileList = $this->getFileList($app, $nowDir);
        $javascript = $this->getJsArrayList($tree);
        $onload = "eccube.fileManager.viewFileTree('tree', arrTree, '" . $nowDir . "', 'tree_select_file', 'tree_status', 'move');";
        return $app->render('Content/file.twig', array(
            'form' => $form->createView(),
            'tpl_onload' => $onload,
            'tpl_javascript' => $javascript,
            'top_dir' => $topDir,
            'tpl_is_top_dir' => $isTopDir,
            'tpl_now_dir' => $nowDir,
            'html_dir' => $htmlDir,
            'now_dir_list' => $nowDirList,
            'tpl_parent_dir' => $parentDir,
            'arrFileList' => $arrFileList,
            'error' => $this->error,
        ));
    }
    public function view(Application $app, Request $request)
    {
        $topDir = $app['config']['user_data_realdir'];
        if ($this->checkDir($this->convertStrToServer($request->get('file')), $topDir)) {
            $file = $this->convertStrToServer($request->get('file'));
            setlocale(LC_ALL, "ja_JP.UTF-8");
            return $app->sendFile($file);
        }
        throw new NotFoundHttpException();
    }
    public function create(Application $app, Request $request)
    {
        $form = $app['form.factory']->createBuilder('form')
            ->add('file', 'file')
            ->add('create_file', 'text')
            ->getForm();
        $form->handleRequest($request);
        if ($form->isValid()) {
            $fs = new Filesystem();
            $filename = $form->get('create_file')->getData();
            $pattern = "/[^[:alnum:]_.\\-]/";
            $pattern2 = "/^\.(.*)$/";
            if (empty($filename)) {
                $this->error = array('message' => 'フォルダ作成名が入力されていません。');
            } elseif (strlen($filename) > 0 && preg_match($pattern, $filename)) {
                $this->error = array('message' => 'フォルダ名には、英数字、記号(_ - .)のみを入力して下さい。');
            } elseif (strlen($filename) > 0 && preg_match($pattern2, $filename)) {
                $this->error = array('message' => '.から始まるフォルダ名は作成できません。');
            } else {
                $topDir = $app['config']['user_data_realdir'];
                $nowDir = $this->checkDir($request->get('now_dir'), $topDir)
                    ? $this->normalizePath($request->get('now_dir'))
                    : $topDir;
                $fs->mkdir($nowDir . '/' . $filename);
            }
        }
        return $app->redirect($app->url('admin_content_file'));
    }
    public function delete(Application $app, Request $request)
    {
        $this->isTokenValid($app);
        $topDir = $app['config']['user_data_realdir'];
        if ($this->checkDir($this->convertStrToServer($request->get('select_file')), $topDir)) {
            $fs = new Filesystem();
            if ($fs->exists($this->convertStrToServer($request->get('select_file')))) {
                $fs->remove($this->convertStrToServer($request->get('select_file')));
            }
        }
        return $app->redirect($app->url('admin_content_file'));
    }
    public function download(Application $app, Request $request)
    {
        $topDir = $app['config']['user_data_realdir'];
        $file = $this->convertStrToServer($request->get('select_file'));
        if ($this->checkDir($file, $topDir)) {
            if (!is_dir($file)) {
                $filename = $this->convertStrFromServer($file);
                setlocale(LC_ALL, 'ja_JP.UTF-8');
                $pathParts = pathinfo($file);
                $patterns = array(
                    '/[a-zA-Z0-9!"#$%&()=~^|@`:*;+{}]/',
                    '/[- ,.<>?_[\]\/\\\\]/',
                    "/['\r\n\t\v\f]/",
                );
                $str = preg_replace($patterns, '', $pathParts['basename']);
                if (strlen($str) === 0) {
                    return $app->sendFile($file)->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);
                } else {
                    return $app->sendFile($file, 200, array(
                        "Content-Type" => "aplication/octet-stream;",
                        "Content-Disposition" => "attachment; filename*=UTF-8\'\'".rawurlencode($this->convertStrFromServer($pathParts['basename']))
                    ));
                }
            }
        }
        throw new NotFoundHttpException();
    }
    public function upload(Application $app, Request $request)
    {
        $form = $app['form.factory']->createBuilder('form')
            ->add('file', 'file')
            ->add('create_file', 'text')
            ->getForm();
        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
            if (empty($data['file'])) {
                $this->error = array('message' => 'ファイルが選択されていません。');
            } else {
                $topDir = $app['config']['user_data_realdir'];
                if ($this->checkDir($request->get('now_dir'), $topDir)) {
                    $filename = $this->convertStrToServer($data['file']->getClientOriginalName());
                    $data['file']->move($request->get('now_dir'), $filename);
                }
            }
        }
    }
    private function getJsArrayList($tree)
    {
        $str = "arrTree = new Array();\n";
        foreach ($tree as $key => $val) {
            $str .= 'arrTree[' . $key . "] = new Array(" . $key . ", '" . $val['type'] . "', '" . $val['path'] . "', " . $val['rank'] . ',';
            if ($val['open']) {
                $str .= "true);\n";
            } else {
                $str .= "false);\n";
            }
        }
        return $str;
    }
    private function getTree($topDir, $request)
    {
        $finder = Finder::create()->in($topDir)
            ->directories()
            ->sortByName();
        $tree = array();
        $tree[] = array(
            'path' => $topDir,
            'type' => '_parent',
            'rank' => 0,
            'open' => true,
        );
        $defaultRank = count(explode('/', $topDir));
        $openDirs = array();
        if ($request->get('tree_status')) {
            $openDirs = explode('|', $request->get('tree_status'));
        }
        foreach ($finder as $dirs) {
            $path = $this->normalizePath($dirs->getRealPath());
            $type = (iterator_count(Finder::create()->in($path)->directories())) ? '_parent' : '_child';
            $rank = count(explode('/', $path)) - $defaultRank;
            $tree[] = array(
                'path' => $path,
                'type' => $type,
                'rank' => $rank,
                'open' => (in_array($path, $openDirs)) ? true : false,
            );
        }
        return $tree;
    }
    private function getFileList($app, $nowDir)
    {
        $topDir = $app['config']['user_data_realdir'];
        $filter = function (\SplFileInfo $file) use ($topDir) {
            $acceptPath = realpath($topDir);
            $targetPath = $file->getRealPath();
            return (strpos($targetPath, $acceptPath) === 0);
        };
        $dirFinder = Finder::create()
            ->filter($filter)
            ->in($nowDir)
            ->directories()
            ->sortByName()
            ->depth(0);
        $fileFinder = Finder::create()
            ->filter($filter)
            ->in($nowDir)
            ->files()
            ->sortByName()
            ->depth(0);
        $dirs = iterator_to_array($dirFinder);
        $files = iterator_to_array($fileFinder);
        $arrFileList = array();
        foreach ($dirs as $dir) {
            $arrFileList[] = array(
                'file_name' => $this->convertStrFromServer($dir->getFilename()),
                'file_path' => $this->convertStrFromServer($this->normalizePath($dir->getRealPath())),
                'file_size' => $dir->getSize(),
                'file_time' => date("Y/m/d", $dir->getmTime()),
                'is_dir' => true,
            );
        }
        foreach ($files as $file) {
            $arrFileList[] = array(
                'file_name' => $this->convertStrFromServer($file->getFilename()),
                'file_path' => $this->convertStrFromServer($this->normalizePath($file->getRealPath())),
                'file_size' => $file->getSize(),
                'file_time' => date("Y/m/d", $file->getmTime()),
                'is_dir' => false,
            );
        }
        return $arrFileList;
    }
    protected function normalizePath($path)
    {
        return str_replace('\\', '/', realpath($path));
    }
    protected function checkDir($targetDir, $topDir)
    {
        $targetDir = realpath($targetDir);
        $topDir = realpath($topDir);
        return (strpos($targetDir, $topDir) === 0);
    }
    private function convertStrFromServer($target)
    {
        if ($this->encode == self::SJIS) {
            return mb_convert_encoding($target, self::UTF, self::SJIS);
        }
        return $target;
    }
    private function convertStrToServer($target)
    {
        if ($this->encode == self::SJIS) {
            return mb_convert_encoding($target, self::SJIS, self::UTF);
        }
        return $target;
    }
}