25
2024
04
15:23:41

天澜 技术让生活更美! 开源作品-PHP写的在线文件管理工具(单文件绿色版)-SuExplorer_PHP

前言:
项目开发过程中,网站一般部署到远程服务器,所以文件管理就不能和本机操作一样方便。通常文件管理是用ftp下载到本地,修改后再上传,或者远程登录到服务器进行修改。但是这些操作都依赖于复杂的第三方软件。如果只是想简单修改网站中一个页面中的文字,或查看文件代码,相对于繁琐的使用第三方软件进行操作的流程,如果有一个小程序能在线操作文件,那就能方便快速达到自己的需求了。所以,SuExplorer就是在这样的需求中被开发出来。
秉承自己开发的小工具一贯的风格,首先是要尽可能绿色单文件,尽量不依赖其他文件,然后是容易部署。 这样才能方便在项目中提高生产力!

简介:
SuExplorer_PHP是一个用于在线管理文件的单文件绿色版PHP程序,和phpinfo.php一样可以方便放到项目中使用。 开发项目过程中,操作服务器上的文件是一个费时费力的流程,如果有一个通用管理程序,可以很简单而高效地管理服务器上的文件,那对项目的开发效率肯定有明显的提升,可以减少很多重复而单调的体力劳动。但是,管理服务器上的文件,首先要连接上服务器,然后用第三方工具进行操作,为了简单查看一下文件源码,却要安装一大堆不需要的依赖文件,而且还要开启和关闭第三方软件,效率有点低。于是决定自己抽出一点时间来开发一个自己用起来顺手的在线文件管理小工具,简单而高效,用起来还顺手~

特性:
1、单文件绿色版,无外部依赖,方便部署使用
2、支持登录验证
3、支持内置配置文件,使用更灵活

使用:
1. SuExplorer_PHP_2_0文件复制到您的项目中任意目录(本文件为单文件绿色版,方便使用_).<br /> 2. 修改配置内容为适合您需要的规则.
3. 运行本文件, 开始在线管理文件~

运行效果图:


项目主页:http://git.oschina.net/sutroon/SuExplorer_PHP_2_0
交流博客:http://www.cnblogs.com/sutroon/p/4744779.html



//下面是源码,另存为.php丢服务器就可以运行,默认用户名admin密码admin123,缺点是密码是明文的,手工修改


<?php
session_start();
/**
 * SuExplorer.php
 * 在线php/ini/conf/sh等脚本文件编辑器, 不依赖ftp和服务器帐号(单页绿色文件,方便部署)
 * @since 1.0 <2015-5-11> SoChishun <14507247@qq.com> Added.
 * @since 2.0 <2015-7-24> SoChishun 
 *      1.重命名为SuExplorer.php
 *      2.改进若干外观样式
 *      3.新增登录验证模块
 *      4.新增删除功能
 * @since 3.0 <2015-10-7> SoChishun
 *      1.新增在线压缩和解压功能
 *      2.新增chomd权限设置功能
 *      3.新增rename重命名功能
 *      4.新增新建文件和目录功能
 *      5.类SuFileEditor重构为SuExplorer,类方法改为静态方法
 *      6.新增主配置文件功能
 *      7.重构页面逻辑,改为脚本混合代码,便于阅读
 *      8.基于绝对路径操作改为基于网站根目录的相对路径操作
 *  @since 3.1 <2016-9-13> SoChishun
 *      1. 新增文件上传功能
 * @since 3.2 <2017-8-23> SoChishun
 *      1. 修正无法查看脚本文件的问题
 *      2. 对html输出增加htmlspecialchars过滤功能
 */
// 程序版本号 [2015-10-7] Added.
$version = '3.2';
// session键名 [2015-10-7] Added.
$sess_id = 'sess_suexplorer';

// 权限规则 [2015-10-7] Added.
$prules = array('delfile', 'deldir', 'savefile', 'newfile', 'mkdir', 'renamefile', 'renamedir', 'chomdfile', 'chomddir', 'zip', 'unzip');

// 主配置 [2015-10-7] Added.
$config = array(
    /* 用户配置 */
    'users' => array(
        'admin' => array('admin123', array('allow' => array(), 'forbit' => array())),
        'test' => array('testpwd', array('allow' => array(), 'forbit' => array())),
    ),
);

// 登录信息 [2015-10-7] Added.
$login_data = isset($_SESSION[$sess_id]) ? $_SESSION[$sess_id] : false;

$action = I('action');
$view = I('view');
$path = I('path', '/'); // urldecode($_GET['path']) $_SERVER['DOCUMENT_ROOT']
$parent_path = path_getdir($path);
switch ($action) {
    case 'login': // 用户登录
        if (!SuExplorer::user_login($config, $sess_id, $msg)) {
            redirect('?r=fail', 1, $msg);
        } else {
            redirect('?r=ok');
        }
        break;
    case 'logout': // 注销登录
        SuExplorer::user_logout($sess_id);
        redirect('?r=ok');
        break;
    case 'del': // 删除路径(文件或目录)
        if (!SuExplorer::act_delete_path($path, $msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . path_getdir($path), 1, '恭喜,操作成功!');
        }
        break;
    case 'savefile': // 保存文件
    case 'save_newfile': // 新建文件
        if (!SuExplorer::act_save_file($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'save_newdir': // 新建目录
        if (!SuExplorer::act_save_newdir($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'upload_file': // 上传文件
        if (!SuExplorer::act_upload_file($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,文件上传成功!');
        }
        break;
    case 'rename_path': // 重命名路径(文件或目录)
        if (!SuExplorer::act_rename_path($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . pathinfo($path, PATHINFO_DIRNAME), 1, '恭喜,操作成功!');
        }
        break;
    case 'chmod_path': // 修改权限(文件或目录)
        if (!SuExplorer::act_chmod_path($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'zip': // 压缩
        if (!SuExplorer::act_zip($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'unzip': // 解压缩
        if (!SuExplorer::act_unzip($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
}
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SuExplorer-<?php echo $version ?></title>
        <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
        <style type="text/css">
            body {font-size:12px; color:#333;}
            a{text-decoration: none;}
            textarea{font-size:12px;line-height:18px; padding:5px;}
            th{font-weight: normal;}
            .userbar a:before{content: '['}
            .userbar a:after{content: ']'}
            .dir-contents{width:1050px; display:table;}
            .dir-contents a{ margin-right:20px;line-height:21px;text-decoration:none;float:left;}
            .blue{color:#0000DB}
            .lightblue{color:#1bd1a5}
            .purple{color:#9900ff}
            .green{color:#009900}
            .red{color:#F00}
            .grey {color:#999;}
            .nav { line-height: 18px;}
            .nav a { color:#333;}
            .nav a:before { content: ' » ' }
            .nav a:first-child:before {content: ''}
            .nav div { color:#CCC; border-bottom:solid 1px #CCC; margin-bottom:5px;}
        </style>
    </head>
    <body>
        <?php if ($login_data): ?>
            <!-- 用户信息栏 -->
            <div class="userbar">
                欢迎您, <?php echo $login_data['user_name'] ?> <a href="?action=logout">注销</a>
                <a href="?view=newfile&path=<?php echo $parent_path ?>">新建文件</a>
                <a href="?view=upload&path=<?php echo $parent_path ?>">上传文件</a>
                <a href="?view=newdir&path=<?php echo $parent_path ?>">新建目录</a>
                <a href="?view=zip&path=<?php echo $parent_path ?>">打包目录</a>
                <a href="?view=unzip&path=<?php echo $parent_path ?>">解压目录</a>
            </div>
            <!-- /用户信息栏 -->
            <!-- 路径栏 -->
            <div>
                <form method="get" action="#" id="frm-path">
                    <input type="text" name="path" value="<?php echo $path ?>" style="width:50%;color:#333;padding:0px 2px;" required="required" />
                    <input type="hidden" id="action" name="action" value="" />
                    <input type="hidden" id="do" name="do" value="" />
                    <button type="submit">转到</button>
                    <button type="button" onclick="return del_cofirm('frm-path', '删除');">删除</button>
                    <button type="button" data-path="<?php echo $path ?>" onclick="go_url(this, 'rename')">重命名</button>
                    <button type="button" data-path="<?php echo $path ?>" onclick="go_url(this, 'chmod')">权限</button>
                </form>
            </div>
            <!-- /路径栏 -->
            <div><?php SuExplorer::index($view, $path) ?></div>
            <!-- 脚本区 -->
            <script type="text/javascript">
                /**
                 * 删除确认
                 * @param {type} form_id
                 * @param {type} act_name
                 * @returns {Boolean}
                 * @since 1.0 <2015-10-7> SoChishun Added.
                 */
                function del_cofirm(form_id, act_name) {
                    if (!confirm('您确定要' + act_name + '吗?')) {
                        return false;
                    }
                    var i = 0;
                    function confirmx() {
                        i++;
                        return confirm(i + '.重要的操作要重复问三遍,您确定要' + act_name + '吗?');
                    }
                    while (i < 3) {
                        if (!confirmx()) {
                            return false;
                        }
                    }
                    document.getElementById("action").value = "del";
                    document.getElementById("do").value = "yes";
                    document.getElementById(form_id).submit();
                }
                /**
                 * 跳转到链接
                 * @param {HtmlButton} btn
                 * @since 1.0 <2015-10-9> SoChishun Added.
                 */
                function go_url(btn, view) {
                    location.href = '?path=' + $(btn).data('path') + '&view=' + view;
                }
            </script>
            <!-- /脚本区 -->
        <?php else: ?>
            <!-- 用户登录表单 -->
            <form method="post">
                <table>
                    <tr><th>用户名:</th><td><input type="text" name="uname" placeholder="用户名" required="required" /></td></tr>
                    <tr><th>密&nbsp;码:</th><td><input type="password" name="upwd" placeholder="密码" required="required" /></td></tr>
                </table>
                <input type="hidden" name="action" value="login" />
                <button type="submit">登录</button> <button type="reset">重置</button>
            </form>
            <!-- /用户登录表单 -->
        <?php endif; ?>
    </body>
</html>
<?php
/* * ****************************************************************************************************
  函数 :)
 * **************************************************************************************************** */

/**
 * 获取浏览器参数
 * @param string $name
 * @param mixed $defv
 * @return mixed
 * @since 1.0 <2015-8-13> SoChishun Added.
 */
function I($name, $defv = '') {
    if (isset($_GET[$name])) {
        return $_GET[$name];
    }
    return isset($_POST[$name]) ? $_POST[$name] : $defv;
}

/**
 * URL重定向
 * @param string $url 重定向的URL地址
 * @param integer $time 重定向的等待时间(秒)
 * @param string $msg 重定向前的提示信息
 * @return void
 * @since 1.0 <2015-10-7> from ThinkPHP
 */
function redirect($url, $time = 0, $msg = '') {
    //多行URL地址支持
    $url = str_replace(array("\n", "\r"), '', $url);
    if (empty($msg))
        $msg = "系统将在{$time}秒之后自动跳转到{$url}!";
    if (!headers_sent()) {
        // redirect
        if (0 === $time) {
            header('Location: ' . $url);
        } else {
            header("refresh:{$time};url={$url}");
            echo($msg);
        }
        exit();
    } else {
        $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
        if ($time != 0)
            $str .= $msg;
        exit($str);
    }
}

/**
 * 获取文件扩展名类型
 * @param string $exten 扩展名(不带.)
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function get_exten_catetory($exten) {
    if ($exten) {
        $filetypes = array('zip' => array('zip', 'rar', '7-zip', 'tar', 'gz', 'gzip'), 'doc' => array('txt', 'rtf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'wps', 'et'), 'script' => array('php', 'js', 'css', 'c'), 'image' => array('jpg', 'jpeg', 'png', 'gif', 'tiff', 'psd', 'bmp', 'ico'));
        foreach ($filetypes as $catetory => $extens) {
            if (in_array($exten, $extens)) {
                return $catetory;
            }
        }
    }
    return '';
}

/**
 * 绝对路径转相对路径
 * @param string $path
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_ator($path) {
    $root = $_SERVER['DOCUMENT_ROOT'];
    $path = substr($path, strlen($root));
    if ('/' != DIRECTORY_SEPARATOR) {
        $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
    }
    return $path;
}

/**
 * 相对路径转绝对路径
 * @param string $path
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_rtoa($path) {
    $root = $_SERVER['DOCUMENT_ROOT'];
    if ('/' != DIRECTORY_SEPARATOR) {
        $path = str_replace('/', DIRECTORY_SEPARATOR, $path);
    }
    return $root . $path;
}

/**
 * 获取文件的目录地址
 * @param string $path
 * @param boolean $is_r 是否相对路径
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_getdir($path, $is_r = true) {
    if (!$path || is_dir($is_r ? path_rtoa($path) : $path)) {
        return $path;
    }
    return pathinfo($path, PATHINFO_DIRNAME);
}

/**
 * 页面主类
 * @since 1.0 <2015-5-11> SoChishun <14507247@qq.com> Added.
 * @since 3.0 <2015-10-7> SoChishun 重构.
 */
class SuExplorer {

    /**
     * 版本号
     * @var string
     * @since 1.0 <2015-10-7> SoChishun Added.
     */
    CONST VERSION = '3.0.0';

    /**
     * 显示网站目录的项目内容
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function index($view, $path) {
        // 面包屑导航
        self::location_to_breadcrumb($path);
        // 视图显示
        switch ($view) {
            case 'newfile':
                self::view_create_file($path);
                break;
            case 'newdir':
                self::view_create_dir($path);
                break;
            case 'upload':
                self::view_upload_file($path);
                break;
            case 'rename':
                self::view_rename_path($path);
                break;
            case 'chmod':
                self::view_chmod_path($path);
                break;
            case 'zip':
                self::view_zip();
                break;
            case 'unzip':
                self::view_unzip();
                break;
            default:
                // 列出文件
                $sapath = path_rtoa($path);
                if (is_dir($sapath)) {
                    self::view_content_list($path);
                } else if (is_file($sapath)) {
                    self::view_edit_file($path);
                } else {
                    echo '<strong class="red">文件或目录不存在或已删除!</strong>';
                }
                break;
        }
    }

    /**
     * 用户登录操作
     * @param array $config
     * @param string $sess_id
     * @param string $msg 错误消息
     * @return boolean 
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function user_login($config, $sess_id, &$msg = '') {
        if (!$_POST || !isset($_POST['uname'])) {
            $msg = '表单数据无效!';
            return false;
        }
        $uname = $_POST['uname'];
        if (!array_key_exists($uname, $config['users'])) {
            $msg = '用户不存在';
            return false;
        }
        $login_data = $config['users'][$uname];
        if ($login_data[0] != $_POST['upwd']) {
            $msg = '密码错误!';
            return false;
        }
        $_SESSION[$sess_id] = array('user_name' => $uname, 'rules' => isset($login_data[1]) ? $login_data[1] : false);
        return true;
    }

    /**
     * 用户登出操作
     * @param string $sess_id
     * @return boolean 
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function user_logout($sess_id) {
        if (isset($_SESSION[$sess_id])) {
            unset($_SESSION[$sess_id]);
        }
        return true;
    }

    /**
     * 删除路径(文件或目录)
     * @param string $path 路径
     * @param string $msg 错误消息
     * @return boolean|string
     * @since 1.0 <2015-10-7> SoChishun Added.
     * @since 2.0 <2015-10-8> SoChishun 将delete_file和delete_dir合并到delete_path
     */
    static function act_delete_path($path, &$msg = '') {
        if ('yes' != I('do')) {
            // 为防止黑客破坏,删除操作需要手动增加参数do=yes
            $msg = '非法操作!';
            return false;
        }
        if ('/' == $path) {
            $msg = '根目录无法删除!';
            return false;
        }
        $path = path_rtoa($path);
        if (is_file($path)) {
            if (!@unlink($path)) {
                $msg = '文件删除失败!';
                return false;
            }
            return true;
        }
        if (is_dir($path)) {
            if (!@rmdir($path)) {
                $msg = '目录删除失败!(非空目录或权限不足)';
                return false;
            }
            return true;
        }
        $msg = '不是有效文件或目录!';
        return false;
    }

    /**
     * 保存(新)文件
     * @param type $msg
     * @return boolean
     * @since 1.0 <2015-10-7> SoChishun Added.
     */
    static function act_save_file(&$msg = '') {
        $filename = I('filename');
        if (!$filename || !strpos($filename, '.')) {
            $msg = '文件扩展名无效!';
            return false;
        }
        $content = I('content');
        $path = I('path');
        $path = path_rtoa($path);
        if (is_file($path)) {
            $path = path_getdir($path, false);
        }
        $newpath = $path . DIRECTORY_SEPARATOR . $filename;
        try {
            file_put_contents($newpath, $content);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 保存新目录
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function act_save_newdir(&$msg = '') {
        $filename = I('filename');
        if (!$filename) {
            $msg = '目录名称无效';
            return false;
        }
        $path = path_rtoa(I('path'));
        $newpath = $path . DIRECTORY_SEPARATOR . $filename;
        try {
            mkdir($newpath, I('mode'));
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 上传文件
     * @param type $msg
     * @return boolean
     * @since 1.0 <2016-9-13> SoChishun Added.
     */
    static function act_upload_file(&$msg = '') {
        if ($_FILES["file"]["error"] > 0) {
            $msg = $_FILES["file"]["error"];
            return false;
        }

        $path = I('path');
        $path = path_rtoa($path);
        $filename = $_FILES["file"]["name"];
        if (file_exists($path . $filename)) {
            $msg = $filename . " 文件已存在!";
            return false;
        }
        move_uploaded_file($_FILES["file"]["tmp_name"], $path . $filename);
        return true;
    }

    /**
     * 重命名路径操作
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_rename_path(&$msg = '') {
        $filename2 = I('filename2');
        if (!$filename2) {
            $msg = '新名称未填写!';
            return false;
        }
        $path = path_rtoa(I('path'));
        if (is_file($path) && !strpos($filename2, '.')) {
            $msg = '文件扩展名无效!';
            return false;
        }
        try {
            $newname = pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . $filename2;
            @rename($path, $newname);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 编辑权限操作
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_chmod_path(&$msg = '') {
        $mode = I('mode');
        if (!$mode) {
            $msg = '权限模式无效!';
            return false;
        }
        $path = path_rtoa(I('path'));
        try {
            chmod($path, $mode);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 压缩操作
     * @param string $msg
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_zip(&$msg = '') {
        $filename = I('filename');
        $content = I('content');
        if (!$filename || !strpos($filename, '.')) {
            $msg = '压缩文件名无效!';
            return false;
        }
        if (!$content) {
            $msg = '压缩内容无效!';
            return false;
        }
        $include = array();
        $exclude = array();
        $paths = explode(PHP_EOL, $content);
        foreach ($paths as $path) {
            if (0 === strpos($path, 'exclude ')) {
                $exclude[] = trim(substr($path, 8));
            } else {
                $include[] = $path;
            }
        }
        if (!$include) {
            $msg = '压缩内容无效!';
            return false;
        }
        $zip = new ZipHelper();
        return $zip->zip($filename, $msg, $include, $exclude, I('rootpath'));
    }

    /**
     * 解压缩文件
     * @param type $msg
     * @return type
     */
    static function act_unzip(&$msg = '') {
        $root = I('root');
        $filename = I('filename');
        if (!$filename) {
            $msg = '压缩文件路径无效!';
            return false;
        }
        if (!$root) {
            $msg = '解压缩路径无效!';
            return false;
        }
        $zip = new ZipHelper();
        return $zip->unzip($filename, $root, $msg);
    }

    /**
     * 目录内容视图
     * @param type $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function view_content_list($path) {
        $files = self::get_dir_contents($path, array('name' => true, 'path' => false, 'real_path' => false, 'relative_path' => true, 'exten' => false, 'ctime' => false, 'mtime' => false, 'size' => false, 'is_dir' => true, 'is_file' => false, 'is_link' => true, 'is_executable' => true, 'is_readable' => false, 'is_writable' => false, 'filetype' => true));
        echo '<div class="dir-contents" title="蓝色表示目录,绿色表示可执行文件,浅蓝色表示链接文件,红色表示压缩文件,紫色表示图形文件,灰色表示其他文件">';
        foreach ($files as $file) {
            if ($file['is_dir']) {
                echo '<a href="?path=' . $file['relative_path'] . '" class="blue"><strong>' . $file['name'] . '</strong></a>';
            } else {
                $class = '';
                if ($file['is_link']) {
                    $class = 'lightblue';
                } else if ($file['is_executable']) {
                    $class = 'green';
                } else {
                    switch ($file['filetype']) {
                        case 'zip':
                            $class = 'red';
                            break;
                        case 'image':
                            $class = 'purple';
                            break;
                        default:
                            $class = 'grey';
                            break;
                    }
                }
                echo '<a href="?path=' . $file['relative_path'] . '" class="' . $class . '">' . $file['name'] . '</a>';
            }
        }
        echo '<div style="clear:both"></div></div>';
    }

    /**
     * 文件内容编辑视图
     * @param type $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function view_edit_file($path) {
        $sapath = path_rtoa($path);
        if (!is_file($sapath)) {
            return;
        }
        $category = get_exten_catetory(pathinfo($path, PATHINFO_EXTENSION));
        switch ($category) {
            case 'doc':
            case 'script':
                $btns = '<button type="submit">保存</button><button type="reset">重置</button>';
                if (!is_writable($sapath)) {
                    echo '<div style="color:#F00">文件不可写</div>';
                    $btns = '';
                }
                echo '<div>
                    <form method="post">
                        ', $btns, '<div><textarea name="content" cols="60" rows="36" style="width:90%">' . htmlspecialchars(file_get_contents($sapath)) . '</textarea></div>', $btns, '
                        <input type="hidden" name="action" value="savefile" />
                        <input type="hidden" name="filename" value="' . basename($path) . '" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
                break;
            case 'image':
                echo '<img src="', $path, '" alt="" style="max-width:800px;max-height:640px;" /><br />';
                echo basename($path);
                echo ' <a href="', $path, '" target="_blank">[原图]</a>';
                break;
            default:
                echo basename($path);
                echo ' <a href="', $path, '" target="_blank">[下载]</a>';
                break;
        }
    }

    /**
     * 新增文件视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_create_file($path) {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>文件名:</th><td><input type="text" name="filename" required="required" placeholder="如:newfile.txt" /></td></tr>
                            <tr><th valign="top">内容:</th><td><textarea name="content" cols="90" rows="12"></textarea></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">创建文件</button><button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="save_newfile" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 新增目录视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_create_dir($path) {
        echo '<div>
                    <form method="post">
                        目录名:<input type="text" name="filename" required="required" /><br />
                        权限模式:<input type="text" name="mode" required="required" value="0777" /><br />
                        <button type="submit">创建目录</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="save_newdir" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    static function view_upload_file($path) {
        echo '<div>
                    <form method="post" enctype="multipart/form-data">
                        <table>
                            <tr><th>选择文件:</th><td><input type="file" name="file" required="required" /></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">立即上传</button> <button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="upload_file" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 重命名文件视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_rename_path($path) {
        echo '<div>
                    <form method="post">
                        原名称:<input type="hidden" name="filename" value="' . basename($path) . '" />' . basename($path) . '<br />
                        新名称:<input type="text" name="filename2" required="required" /><br />
                        <button type="submit">重命名</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="rename_path" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 编辑权限视图
     * @param string $path 路径
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_chmod_path($path) {
        echo '<div>
                    <form method="post">
                        名称:' . basename($path) . '<br />
                        权限模式:<input type="text" name="mode" required="required" value="0777" /><br />
                        <button type="submit">设置</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="chmod_path" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 压缩文件视图
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_zip() {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>压缩文件名:</th><td><input type="text" name="filename" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1\newfile.zip" /></td></tr>
                            <tr><th valign="top">压缩内容:</th><td><textarea name="content" cols="90" rows="12" placeholder="每个路径一行,必需是绝对路径"></textarea></td></tr>
                            <tr><th>去除根路径:</th><td><input type="text" name="rootpath" size="89" placeholder="绝对路径,如:C:\public\www\website1" /></td></tr>
                            <tr><td>&nbsp;</td><td class="red">
                            注意,所有路径都必需是绝对路径!<br />
                            包含路径示例:C:\public\www\website1\app<br />
                            排除路径示例: exclude C:\public\www\website1\app\runtime<br />
                            如果填写跟路径地址,则压缩内容会自动去除跟路径信息(解压缩的时候,可以解压缩到任意目录下),如果根路径为空则保留根路径信息(解压缩的时候,无法解压缩到任意目录下,系统会自动创建和压缩前路径一样的目录)
                            </td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">创建压缩文件</button><button type="reset">重置</button></td></tr>
                        </table>                        
                        <input type="hidden" name="action" value="zip" />
                    </form>
                </div>';
    }

    /**
     * 解压缩文件视图
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_unzip() {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>压缩文件名:</th><td><input type="text" name="filename" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1\newfile.zip" /></td></tr>
                            <tr><th>解压缩路径:</th><td><input type="text" name="root" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1" /></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">解压缩文件</button><button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="unzip" />
                    </form>
                </div>';
    }

    /**
     * 返回指定路径下的内容
     * @param string $directory 路径
     * @param array $config 选项
     * @return array
     * @throws Exception
     * @since 1.0 <2015-5-11> SoChishun Added.
     * @since 1.1 <2015-10-8> SoChishun 新增filetype文件类别属性
     */
    static function get_dir_contents($directory, $options = array()) {
        $config = array('name' => true, 'path' => true, 'real_path' => true, 'relative_path' => false, 'exten' => false, 'ctime' => false, 'mtime' => false, 'size' => false, 'is_dir' => true, 'is_file' => false, 'is_link' => false, 'is_executable' => false, 'is_readable' => false, 'is_writable' => false, 'filetype' => false);
        if ($options) {
            $config = array_merge($config, $options);
        }
        try {
            $dir = new DirectoryIterator(path_rtoa($directory));
        } catch (Exception $e) {
            throw new Exception($directory . ' is not readable');
        }
        $files = array();
        foreach ($dir as $file) {
            if ($file->isDot()) {
                continue;
            }
            if ($config['name']) {
                $item['name'] = $file->getFileName();
            }
            if ($config['path']) {
                $item['path'] = $file->getPath();
            }
            if ($config['real_path']) {
                $item['real_path'] = $file->getRealPath();
            }
            if ($config['relative_path']) {
                $item['relative_path'] = path_ator($file->getRealPath());
            }
            $exten = $file->getExtension();
            if ($config['exten']) {
                $item['exten'] = $exten;
            }
            if ($config['filetype']) {
                $item['filetype'] = get_exten_catetory($exten);
            }
            if ($config['mtime']) {
                $item['mtime'] = $file->getMTime();
            }
            if ($config['ctime']) {
                $item['ctime'] = $file->getCTime();
            }
            if ($config['size']) {
                $item['size'] = $file->getSize();
            }
            if ($config['is_dir']) {
                $item['is_dir'] = $file->isDir();
            }
            if ($config['is_file']) {
                $item['is_file'] = $file->isFile();
            }
            if ($config['is_link']) {
                $item['is_link'] = $file->isLink();
            }
            if ($config['is_executable']) {
                $item['is_executable'] = $file->isExecutable();
            }
            if ($config['is_readable']) {
                $item['is_readable'] = $file->isReadable();
            }
            if ($config['is_writable']) {
                $item['is_writable'] = $file->isWritable();
            }
            $files[] = $item;
        }
        return $files;
    }

    /**
     * 路径转为导航
     * @param string $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function location_to_breadcrumb($path) {
        echo '<div class="nav"><a href="?path=/">/</a>';
        if ('/' != $path) {
            $asubpath = explode('/', substr($path, 1));
            if ($asubpath) {
                $str = '';
                foreach ($asubpath as $sub) {
                    $str .= '/' . $sub;
                    echo '<a href="?path=', $str, '">', $sub, '</a>';
                }
            }
        }
        echo '<div>', path_rtoa($path), '</div>';
        echo '</div>';
    }

}

/**
 * 压缩类
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
class ZipHelper {

    /**
     * 解压缩之
     * @param type $filename
     * @param type $root
     * @param type $msg
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    function unzip($filename, $root, &$msg = '') {
        if (!$filename) {
            $msg = '压缩文件名无效!';
            return false;
        }
        $zip = new ZipArchive();
        $msg = $zip->open($filename);
        if (true !== $msg) {
            $msg = var_export($msg, true);
            return false;
        }
        $zip->extractTo($root);
        $zip->close();
        return true;
    }

    /**
     * 压缩之
     * @param type $filename
     * @param type $msg
     * @param type $include
     * @param type $exclude
     * @param string $trimpath
     * @param string $comment
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    function zip($filename, &$msg = '', $include = array(), $exclude = array(), $trimpath = '', $comment = 'default') {
        if (!$filename) {
            $msg = '压缩文件名无效!';
            return false;
        }
        if (!$include) {
            $msg = '压缩内容无效!';
            return false;
        }
        if ('default' == $comment) {
            $comment = basename($filename) . PHP_EOL . 'Generate at ' . date('Y-m-d H:i:s') . PHP_EOL . 'Powerd by SuExplorer.'; // 注释内容
        }
        try {
            $zip = new ZipArchive();
            $msg = $zip->open($filename, ZIPARCHIVE::OVERWRITE);
            if (true !== $msg) {
                $msg = var_export($msg, true);
                return false;
            }
            if ($comment) {
                $zip->setArchiveComment($comment);
            }
            if ($trimpath) {
                $trimpath = rtrim($trimpath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
            }
            $substart = strlen($trimpath);
            foreach ($include as $source) {
                $this->zip_dir($zip, $source, $exclude, $substart);
            }
            $zip->close();
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 递归压缩整个目录
     * @param ZipArchive $zip
     * @param string $source 包含的路径
     * @param array $exclude 排除的路径
     * @param int $substart 开始截取的路径字符串(用于去除路径中的根目录路径)
     * @since 1.0 <2015-8-28> SoChishun Added.
     */
    function zip_dir(&$zip, $source, $exclude, $substart = 0) {
        if (is_dir($source)) {
            $source = rtrim($source, DIRECTORY_SEPARATOR);
            if ($handle = opendir($source)) {
                while (false !== ( $f = readdir($handle) )) {
                    if ('.' == $f || '..' == $f) {
                        continue;
                    }
                    $filename = $source . DIRECTORY_SEPARATOR . $f;
                    if (is_dir($filename)) {
                        if ($exclude && in_array($filename, $exclude)) {
                            continue;
                        }
                        $this->zip_dir($zip, $filename, $exclude, $substart);
                    } else {
                        if ($exclude && in_array($filename, $exclude)) {
                            continue;
                        }
                        $zip->addFile($filename, substr($filename, $substart));
                    }
                }
                closedir($handle);
            }
        } else {
            if ($exclude && in_array($source, $exclude)) {
                return;
            }
            $zip->addFile($source);
        }
    }
}<?php
session_start();
/**
 * SuExplorer.php
 * 在线php/ini/conf/sh等脚本文件编辑器, 不依赖ftp和服务器帐号(单页绿色文件,方便部署)
 * @since 1.0 <2015-5-11> SoChishun <14507247@qq.com> Added.
 * @since 2.0 <2015-7-24> SoChishun 
 *      1.重命名为SuExplorer.php
 *      2.改进若干外观样式
 *      3.新增登录验证模块
 *      4.新增删除功能
 * @since 3.0 <2015-10-7> SoChishun
 *      1.新增在线压缩和解压功能
 *      2.新增chomd权限设置功能
 *      3.新增rename重命名功能
 *      4.新增新建文件和目录功能
 *      5.类SuFileEditor重构为SuExplorer,类方法改为静态方法
 *      6.新增主配置文件功能
 *      7.重构页面逻辑,改为脚本混合代码,便于阅读
 *      8.基于绝对路径操作改为基于网站根目录的相对路径操作
 *  @since 3.1 <2016-9-13> SoChishun
 *      1. 新增文件上传功能
 * @since 3.2 <2017-8-23> SoChishun
 *      1. 修正无法查看脚本文件的问题
 *      2. 对html输出增加htmlspecialchars过滤功能
 */
// 程序版本号 [2015-10-7] Added.
$version = '3.2';
// session键名 [2015-10-7] Added.
$sess_id = 'sess_suexplorer';

// 权限规则 [2015-10-7] Added.
$prules = array('delfile', 'deldir', 'savefile', 'newfile', 'mkdir', 'renamefile', 'renamedir', 'chomdfile', 'chomddir', 'zip', 'unzip');

// 主配置 [2015-10-7] Added.
$config = array(
    /* 用户配置 */
    'users' => array(
        'admin' => array('admin123', array('allow' => array(), 'forbit' => array())),
        'test' => array('testpwd', array('allow' => array(), 'forbit' => array())),
    ),
);

// 登录信息 [2015-10-7] Added.
$login_data = isset($_SESSION[$sess_id]) ? $_SESSION[$sess_id] : false;

$action = I('action');
$view = I('view');
$path = I('path', '/'); // urldecode($_GET['path']) $_SERVER['DOCUMENT_ROOT']
$parent_path = path_getdir($path);
switch ($action) {
    case 'login': // 用户登录
        if (!SuExplorer::user_login($config, $sess_id, $msg)) {
            redirect('?r=fail', 1, $msg);
        } else {
            redirect('?r=ok');
        }
        break;
    case 'logout': // 注销登录
        SuExplorer::user_logout($sess_id);
        redirect('?r=ok');
        break;
    case 'del': // 删除路径(文件或目录)
        if (!SuExplorer::act_delete_path($path, $msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . path_getdir($path), 1, '恭喜,操作成功!');
        }
        break;
    case 'savefile': // 保存文件
    case 'save_newfile': // 新建文件
        if (!SuExplorer::act_save_file($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'save_newdir': // 新建目录
        if (!SuExplorer::act_save_newdir($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'upload_file': // 上传文件
        if (!SuExplorer::act_upload_file($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,文件上传成功!');
        }
        break;
    case 'rename_path': // 重命名路径(文件或目录)
        if (!SuExplorer::act_rename_path($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . pathinfo($path, PATHINFO_DIRNAME), 1, '恭喜,操作成功!');
        }
        break;
    case 'chmod_path': // 修改权限(文件或目录)
        if (!SuExplorer::act_chmod_path($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'zip': // 压缩
        if (!SuExplorer::act_zip($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
    case 'unzip': // 解压缩
        if (!SuExplorer::act_unzip($msg)) {
            redirect('?path=' . $path, 1, $msg);
        } else {
            redirect('?path=' . $path, 1, '恭喜,操作成功!');
        }
        break;
}
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SuExplorer-<?php echo $version ?></title>
        <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
        <style type="text/css">
            body {font-size:12px; color:#333;}
            a{text-decoration: none;}
            textarea{font-size:12px;line-height:18px; padding:5px;}
            th{font-weight: normal;}
            .userbar a:before{content: '['}
            .userbar a:after{content: ']'}
            .dir-contents{width:1050px; display:table;}
            .dir-contents a{ margin-right:20px;line-height:21px;text-decoration:none;float:left;}
            .blue{color:#0000DB}
            .lightblue{color:#1bd1a5}
            .purple{color:#9900ff}
            .green{color:#009900}
            .red{color:#F00}
            .grey {color:#999;}
            .nav { line-height: 18px;}
            .nav a { color:#333;}
            .nav a:before { content: ' » ' }
            .nav a:first-child:before {content: ''}
            .nav div { color:#CCC; border-bottom:solid 1px #CCC; margin-bottom:5px;}
        </style>
    </head>
    <body>
        <?php if ($login_data): ?>
            <!-- 用户信息栏 -->
            <div class="userbar">
                欢迎您, <?php echo $login_data['user_name'] ?> <a href="?action=logout">注销</a>
                <a href="?view=newfile&path=<?php echo $parent_path ?>">新建文件</a>
                <a href="?view=upload&path=<?php echo $parent_path ?>">上传文件</a>
                <a href="?view=newdir&path=<?php echo $parent_path ?>">新建目录</a>
                <a href="?view=zip&path=<?php echo $parent_path ?>">打包目录</a>
                <a href="?view=unzip&path=<?php echo $parent_path ?>">解压目录</a>
            </div>
            <!-- /用户信息栏 -->
            <!-- 路径栏 -->
            <div>
                <form method="get" action="#" id="frm-path">
                    <input type="text" name="path" value="<?php echo $path ?>" style="width:50%;color:#333;padding:0px 2px;" required="required" />
                    <input type="hidden" id="action" name="action" value="" />
                    <input type="hidden" id="do" name="do" value="" />
                    <button type="submit">转到</button>
                    <button type="button" onclick="return del_cofirm('frm-path', '删除');">删除</button>
                    <button type="button" data-path="<?php echo $path ?>" onclick="go_url(this, 'rename')">重命名</button>
                    <button type="button" data-path="<?php echo $path ?>" onclick="go_url(this, 'chmod')">权限</button>
                </form>
            </div>
            <!-- /路径栏 -->
            <div><?php SuExplorer::index($view, $path) ?></div>
            <!-- 脚本区 -->
            <script type="text/javascript">
                /**
                 * 删除确认
                 * @param {type} form_id
                 * @param {type} act_name
                 * @returns {Boolean}
                 * @since 1.0 <2015-10-7> SoChishun Added.
                 */
                function del_cofirm(form_id, act_name) {
                    if (!confirm('您确定要' + act_name + '吗?')) {
                        return false;
                    }
                    var i = 0;
                    function confirmx() {
                        i++;
                        return confirm(i + '.重要的操作要重复问三遍,您确定要' + act_name + '吗?');
                    }
                    while (i < 3) {
                        if (!confirmx()) {
                            return false;
                        }
                    }
                    document.getElementById("action").value = "del";
                    document.getElementById("do").value = "yes";
                    document.getElementById(form_id).submit();
                }
                /**
                 * 跳转到链接
                 * @param {HtmlButton} btn
                 * @since 1.0 <2015-10-9> SoChishun Added.
                 */
                function go_url(btn, view) {
                    location.href = '?path=' + $(btn).data('path') + '&view=' + view;
                }
            </script>
            <!-- /脚本区 -->
        <?php else: ?>
            <!-- 用户登录表单 -->
            <form method="post">
                <table>
                    <tr><th>用户名:</th><td><input type="text" name="uname" placeholder="用户名" required="required" /></td></tr>
                    <tr><th>密&nbsp;码:</th><td><input type="password" name="upwd" placeholder="密码" required="required" /></td></tr>
                </table>
                <input type="hidden" name="action" value="login" />
                <button type="submit">登录</button> <button type="reset">重置</button>
            </form>
            <!-- /用户登录表单 -->
        <?php endif; ?>
    </body>
</html>
<?php
/* * ****************************************************************************************************
  函数 :)
 * **************************************************************************************************** */

/**
 * 获取浏览器参数
 * @param string $name
 * @param mixed $defv
 * @return mixed
 * @since 1.0 <2015-8-13> SoChishun Added.
 */
function I($name, $defv = '') {
    if (isset($_GET[$name])) {
        return $_GET[$name];
    }
    return isset($_POST[$name]) ? $_POST[$name] : $defv;
}

/**
 * URL重定向
 * @param string $url 重定向的URL地址
 * @param integer $time 重定向的等待时间(秒)
 * @param string $msg 重定向前的提示信息
 * @return void
 * @since 1.0 <2015-10-7> from ThinkPHP
 */
function redirect($url, $time = 0, $msg = '') {
    //多行URL地址支持
    $url = str_replace(array("\n", "\r"), '', $url);
    if (empty($msg))
        $msg = "系统将在{$time}秒之后自动跳转到{$url}!";
    if (!headers_sent()) {
        // redirect
        if (0 === $time) {
            header('Location: ' . $url);
        } else {
            header("refresh:{$time};url={$url}");
            echo($msg);
        }
        exit();
    } else {
        $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
        if ($time != 0)
            $str .= $msg;
        exit($str);
    }
}

/**
 * 获取文件扩展名类型
 * @param string $exten 扩展名(不带.)
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function get_exten_catetory($exten) {
    if ($exten) {
        $filetypes = array('zip' => array('zip', 'rar', '7-zip', 'tar', 'gz', 'gzip'), 'doc' => array('txt', 'rtf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'wps', 'et'), 'script' => array('php', 'js', 'css', 'c'), 'image' => array('jpg', 'jpeg', 'png', 'gif', 'tiff', 'psd', 'bmp', 'ico'));
        foreach ($filetypes as $catetory => $extens) {
            if (in_array($exten, $extens)) {
                return $catetory;
            }
        }
    }
    return '';
}

/**
 * 绝对路径转相对路径
 * @param string $path
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_ator($path) {
    $root = $_SERVER['DOCUMENT_ROOT'];
    $path = substr($path, strlen($root));
    if ('/' != DIRECTORY_SEPARATOR) {
        $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
    }
    return $path;
}

/**
 * 相对路径转绝对路径
 * @param string $path
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_rtoa($path) {
    $root = $_SERVER['DOCUMENT_ROOT'];
    if ('/' != DIRECTORY_SEPARATOR) {
        $path = str_replace('/', DIRECTORY_SEPARATOR, $path);
    }
    return $root . $path;
}

/**
 * 获取文件的目录地址
 * @param string $path
 * @param boolean $is_r 是否相对路径
 * @return string
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
function path_getdir($path, $is_r = true) {
    if (!$path || is_dir($is_r ? path_rtoa($path) : $path)) {
        return $path;
    }
    return pathinfo($path, PATHINFO_DIRNAME);
}

/**
 * 页面主类
 * @since 1.0 <2015-5-11> SoChishun <14507247@qq.com> Added.
 * @since 3.0 <2015-10-7> SoChishun 重构.
 */
class SuExplorer {

    /**
     * 版本号
     * @var string
     * @since 1.0 <2015-10-7> SoChishun Added.
     */
    CONST VERSION = '3.0.0';

    /**
     * 显示网站目录的项目内容
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function index($view, $path) {
        // 面包屑导航
        self::location_to_breadcrumb($path);
        // 视图显示
        switch ($view) {
            case 'newfile':
                self::view_create_file($path);
                break;
            case 'newdir':
                self::view_create_dir($path);
                break;
            case 'upload':
                self::view_upload_file($path);
                break;
            case 'rename':
                self::view_rename_path($path);
                break;
            case 'chmod':
                self::view_chmod_path($path);
                break;
            case 'zip':
                self::view_zip();
                break;
            case 'unzip':
                self::view_unzip();
                break;
            default:
                // 列出文件
                $sapath = path_rtoa($path);
                if (is_dir($sapath)) {
                    self::view_content_list($path);
                } else if (is_file($sapath)) {
                    self::view_edit_file($path);
                } else {
                    echo '<strong class="red">文件或目录不存在或已删除!</strong>';
                }
                break;
        }
    }

    /**
     * 用户登录操作
     * @param array $config
     * @param string $sess_id
     * @param string $msg 错误消息
     * @return boolean 
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function user_login($config, $sess_id, &$msg = '') {
        if (!$_POST || !isset($_POST['uname'])) {
            $msg = '表单数据无效!';
            return false;
        }
        $uname = $_POST['uname'];
        if (!array_key_exists($uname, $config['users'])) {
            $msg = '用户不存在';
            return false;
        }
        $login_data = $config['users'][$uname];
        if ($login_data[0] != $_POST['upwd']) {
            $msg = '密码错误!';
            return false;
        }
        $_SESSION[$sess_id] = array('user_name' => $uname, 'rules' => isset($login_data[1]) ? $login_data[1] : false);
        return true;
    }

    /**
     * 用户登出操作
     * @param string $sess_id
     * @return boolean 
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function user_logout($sess_id) {
        if (isset($_SESSION[$sess_id])) {
            unset($_SESSION[$sess_id]);
        }
        return true;
    }

    /**
     * 删除路径(文件或目录)
     * @param string $path 路径
     * @param string $msg 错误消息
     * @return boolean|string
     * @since 1.0 <2015-10-7> SoChishun Added.
     * @since 2.0 <2015-10-8> SoChishun 将delete_file和delete_dir合并到delete_path
     */
    static function act_delete_path($path, &$msg = '') {
        if ('yes' != I('do')) {
            // 为防止黑客破坏,删除操作需要手动增加参数do=yes
            $msg = '非法操作!';
            return false;
        }
        if ('/' == $path) {
            $msg = '根目录无法删除!';
            return false;
        }
        $path = path_rtoa($path);
        if (is_file($path)) {
            if (!@unlink($path)) {
                $msg = '文件删除失败!';
                return false;
            }
            return true;
        }
        if (is_dir($path)) {
            if (!@rmdir($path)) {
                $msg = '目录删除失败!(非空目录或权限不足)';
                return false;
            }
            return true;
        }
        $msg = '不是有效文件或目录!';
        return false;
    }

    /**
     * 保存(新)文件
     * @param type $msg
     * @return boolean
     * @since 1.0 <2015-10-7> SoChishun Added.
     */
    static function act_save_file(&$msg = '') {
        $filename = I('filename');
        if (!$filename || !strpos($filename, '.')) {
            $msg = '文件扩展名无效!';
            return false;
        }
        $content = I('content');
        $path = I('path');
        $path = path_rtoa($path);
        if (is_file($path)) {
            $path = path_getdir($path, false);
        }
        $newpath = $path . DIRECTORY_SEPARATOR . $filename;
        try {
            file_put_contents($newpath, $content);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 保存新目录
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function act_save_newdir(&$msg = '') {
        $filename = I('filename');
        if (!$filename) {
            $msg = '目录名称无效';
            return false;
        }
        $path = path_rtoa(I('path'));
        $newpath = $path . DIRECTORY_SEPARATOR . $filename;
        try {
            mkdir($newpath, I('mode'));
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 上传文件
     * @param type $msg
     * @return boolean
     * @since 1.0 <2016-9-13> SoChishun Added.
     */
    static function act_upload_file(&$msg = '') {
        if ($_FILES["file"]["error"] > 0) {
            $msg = $_FILES["file"]["error"];
            return false;
        }

        $path = I('path');
        $path = path_rtoa($path);
        $filename = $_FILES["file"]["name"];
        if (file_exists($path . $filename)) {
            $msg = $filename . " 文件已存在!";
            return false;
        }
        move_uploaded_file($_FILES["file"]["tmp_name"], $path . $filename);
        return true;
    }

    /**
     * 重命名路径操作
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_rename_path(&$msg = '') {
        $filename2 = I('filename2');
        if (!$filename2) {
            $msg = '新名称未填写!';
            return false;
        }
        $path = path_rtoa(I('path'));
        if (is_file($path) && !strpos($filename2, '.')) {
            $msg = '文件扩展名无效!';
            return false;
        }
        try {
            $newname = pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . $filename2;
            @rename($path, $newname);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 编辑权限操作
     * @param string $msg 错误消息
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_chmod_path(&$msg = '') {
        $mode = I('mode');
        if (!$mode) {
            $msg = '权限模式无效!';
            return false;
        }
        $path = path_rtoa(I('path'));
        try {
            chmod($path, $mode);
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 压缩操作
     * @param string $msg
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function act_zip(&$msg = '') {
        $filename = I('filename');
        $content = I('content');
        if (!$filename || !strpos($filename, '.')) {
            $msg = '压缩文件名无效!';
            return false;
        }
        if (!$content) {
            $msg = '压缩内容无效!';
            return false;
        }
        $include = array();
        $exclude = array();
        $paths = explode(PHP_EOL, $content);
        foreach ($paths as $path) {
            if (0 === strpos($path, 'exclude ')) {
                $exclude[] = trim(substr($path, 8));
            } else {
                $include[] = $path;
            }
        }
        if (!$include) {
            $msg = '压缩内容无效!';
            return false;
        }
        $zip = new ZipHelper();
        return $zip->zip($filename, $msg, $include, $exclude, I('rootpath'));
    }

    /**
     * 解压缩文件
     * @param type $msg
     * @return type
     */
    static function act_unzip(&$msg = '') {
        $root = I('root');
        $filename = I('filename');
        if (!$filename) {
            $msg = '压缩文件路径无效!';
            return false;
        }
        if (!$root) {
            $msg = '解压缩路径无效!';
            return false;
        }
        $zip = new ZipHelper();
        return $zip->unzip($filename, $root, $msg);
    }

    /**
     * 目录内容视图
     * @param type $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function view_content_list($path) {
        $files = self::get_dir_contents($path, array('name' => true, 'path' => false, 'real_path' => false, 'relative_path' => true, 'exten' => false, 'ctime' => false, 'mtime' => false, 'size' => false, 'is_dir' => true, 'is_file' => false, 'is_link' => true, 'is_executable' => true, 'is_readable' => false, 'is_writable' => false, 'filetype' => true));
        echo '<div class="dir-contents" title="蓝色表示目录,绿色表示可执行文件,浅蓝色表示链接文件,红色表示压缩文件,紫色表示图形文件,灰色表示其他文件">';
        foreach ($files as $file) {
            if ($file['is_dir']) {
                echo '<a href="?path=' . $file['relative_path'] . '" class="blue"><strong>' . $file['name'] . '</strong></a>';
            } else {
                $class = '';
                if ($file['is_link']) {
                    $class = 'lightblue';
                } else if ($file['is_executable']) {
                    $class = 'green';
                } else {
                    switch ($file['filetype']) {
                        case 'zip':
                            $class = 'red';
                            break;
                        case 'image':
                            $class = 'purple';
                            break;
                        default:
                            $class = 'grey';
                            break;
                    }
                }
                echo '<a href="?path=' . $file['relative_path'] . '" class="' . $class . '">' . $file['name'] . '</a>';
            }
        }
        echo '<div style="clear:both"></div></div>';
    }

    /**
     * 文件内容编辑视图
     * @param type $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function view_edit_file($path) {
        $sapath = path_rtoa($path);
        if (!is_file($sapath)) {
            return;
        }
        $category = get_exten_catetory(pathinfo($path, PATHINFO_EXTENSION));
        switch ($category) {
            case 'doc':
            case 'script':
                $btns = '<button type="submit">保存</button><button type="reset">重置</button>';
                if (!is_writable($sapath)) {
                    echo '<div style="color:#F00">文件不可写</div>';
                    $btns = '';
                }
                echo '<div>
                    <form method="post">
                        ', $btns, '<div><textarea name="content" cols="60" rows="36" style="width:90%">' . htmlspecialchars(file_get_contents($sapath)) . '</textarea></div>', $btns, '
                        <input type="hidden" name="action" value="savefile" />
                        <input type="hidden" name="filename" value="' . basename($path) . '" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
                break;
            case 'image':
                echo '<img src="', $path, '" alt="" style="max-width:800px;max-height:640px;" /><br />';
                echo basename($path);
                echo ' <a href="', $path, '" target="_blank">[原图]</a>';
                break;
            default:
                echo basename($path);
                echo ' <a href="', $path, '" target="_blank">[下载]</a>';
                break;
        }
    }

    /**
     * 新增文件视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_create_file($path) {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>文件名:</th><td><input type="text" name="filename" required="required" placeholder="如:newfile.txt" /></td></tr>
                            <tr><th valign="top">内容:</th><td><textarea name="content" cols="90" rows="12"></textarea></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">创建文件</button><button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="save_newfile" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 新增目录视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_create_dir($path) {
        echo '<div>
                    <form method="post">
                        目录名:<input type="text" name="filename" required="required" /><br />
                        权限模式:<input type="text" name="mode" required="required" value="0777" /><br />
                        <button type="submit">创建目录</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="save_newdir" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    static function view_upload_file($path) {
        echo '<div>
                    <form method="post" enctype="multipart/form-data">
                        <table>
                            <tr><th>选择文件:</th><td><input type="file" name="file" required="required" /></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">立即上传</button> <button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="upload_file" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 重命名文件视图
     * @param string $path 路径
     * @since 1.0 <2015-10-8> SoChishun Added.
     */
    static function view_rename_path($path) {
        echo '<div>
                    <form method="post">
                        原名称:<input type="hidden" name="filename" value="' . basename($path) . '" />' . basename($path) . '<br />
                        新名称:<input type="text" name="filename2" required="required" /><br />
                        <button type="submit">重命名</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="rename_path" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 编辑权限视图
     * @param string $path 路径
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_chmod_path($path) {
        echo '<div>
                    <form method="post">
                        名称:' . basename($path) . '<br />
                        权限模式:<input type="text" name="mode" required="required" value="0777" /><br />
                        <button type="submit">设置</button> <button type="reset">重置</button>
                        <input type="hidden" name="action" value="chmod_path" />
                        <input type="hidden" name="path" value="' . $path . '" />
                    </form>
                </div>';
    }

    /**
     * 压缩文件视图
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_zip() {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>压缩文件名:</th><td><input type="text" name="filename" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1\newfile.zip" /></td></tr>
                            <tr><th valign="top">压缩内容:</th><td><textarea name="content" cols="90" rows="12" placeholder="每个路径一行,必需是绝对路径"></textarea></td></tr>
                            <tr><th>去除根路径:</th><td><input type="text" name="rootpath" size="89" placeholder="绝对路径,如:C:\public\www\website1" /></td></tr>
                            <tr><td>&nbsp;</td><td class="red">
                            注意,所有路径都必需是绝对路径!<br />
                            包含路径示例:C:\public\www\website1\app<br />
                            排除路径示例: exclude C:\public\www\website1\app\runtime<br />
                            如果填写跟路径地址,则压缩内容会自动去除跟路径信息(解压缩的时候,可以解压缩到任意目录下),如果根路径为空则保留根路径信息(解压缩的时候,无法解压缩到任意目录下,系统会自动创建和压缩前路径一样的目录)
                            </td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">创建压缩文件</button><button type="reset">重置</button></td></tr>
                        </table>                        
                        <input type="hidden" name="action" value="zip" />
                    </form>
                </div>';
    }

    /**
     * 解压缩文件视图
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    static function view_unzip() {
        echo '<div>
                    <form method="post">
                        <table>
                            <tr><th>压缩文件名:</th><td><input type="text" name="filename" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1\newfile.zip" /></td></tr>
                            <tr><th>解压缩路径:</th><td><input type="text" name="root" required="required" size="89" placeholder="绝对路径,如:C:\public\www\website1" /></td></tr>
                            <tr><td>&nbsp;</td><td><button type="submit">解压缩文件</button><button type="reset">重置</button></td></tr>
                        </table>
                        <input type="hidden" name="action" value="unzip" />
                    </form>
                </div>';
    }

    /**
     * 返回指定路径下的内容
     * @param string $directory 路径
     * @param array $config 选项
     * @return array
     * @throws Exception
     * @since 1.0 <2015-5-11> SoChishun Added.
     * @since 1.1 <2015-10-8> SoChishun 新增filetype文件类别属性
     */
    static function get_dir_contents($directory, $options = array()) {
        $config = array('name' => true, 'path' => true, 'real_path' => true, 'relative_path' => false, 'exten' => false, 'ctime' => false, 'mtime' => false, 'size' => false, 'is_dir' => true, 'is_file' => false, 'is_link' => false, 'is_executable' => false, 'is_readable' => false, 'is_writable' => false, 'filetype' => false);
        if ($options) {
            $config = array_merge($config, $options);
        }
        try {
            $dir = new DirectoryIterator(path_rtoa($directory));
        } catch (Exception $e) {
            throw new Exception($directory . ' is not readable');
        }
        $files = array();
        foreach ($dir as $file) {
            if ($file->isDot()) {
                continue;
            }
            if ($config['name']) {
                $item['name'] = $file->getFileName();
            }
            if ($config['path']) {
                $item['path'] = $file->getPath();
            }
            if ($config['real_path']) {
                $item['real_path'] = $file->getRealPath();
            }
            if ($config['relative_path']) {
                $item['relative_path'] = path_ator($file->getRealPath());
            }
            $exten = $file->getExtension();
            if ($config['exten']) {
                $item['exten'] = $exten;
            }
            if ($config['filetype']) {
                $item['filetype'] = get_exten_catetory($exten);
            }
            if ($config['mtime']) {
                $item['mtime'] = $file->getMTime();
            }
            if ($config['ctime']) {
                $item['ctime'] = $file->getCTime();
            }
            if ($config['size']) {
                $item['size'] = $file->getSize();
            }
            if ($config['is_dir']) {
                $item['is_dir'] = $file->isDir();
            }
            if ($config['is_file']) {
                $item['is_file'] = $file->isFile();
            }
            if ($config['is_link']) {
                $item['is_link'] = $file->isLink();
            }
            if ($config['is_executable']) {
                $item['is_executable'] = $file->isExecutable();
            }
            if ($config['is_readable']) {
                $item['is_readable'] = $file->isReadable();
            }
            if ($config['is_writable']) {
                $item['is_writable'] = $file->isWritable();
            }
            $files[] = $item;
        }
        return $files;
    }

    /**
     * 路径转为导航
     * @param string $path
     * @since 1.0 <2015-5-11> SoChishun Added.
     */
    static function location_to_breadcrumb($path) {
        echo '<div class="nav"><a href="?path=/">/</a>';
        if ('/' != $path) {
            $asubpath = explode('/', substr($path, 1));
            if ($asubpath) {
                $str = '';
                foreach ($asubpath as $sub) {
                    $str .= '/' . $sub;
                    echo '<a href="?path=', $str, '">', $sub, '</a>';
                }
            }
        }
        echo '<div>', path_rtoa($path), '</div>';
        echo '</div>';
    }

}

/**
 * 压缩类
 * @since 1.0 <2015-10-9> SoChishun Added.
 */
class ZipHelper {

    /**
     * 解压缩之
     * @param type $filename
     * @param type $root
     * @param type $msg
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    function unzip($filename, $root, &$msg = '') {
        if (!$filename) {
            $msg = '压缩文件名无效!';
            return false;
        }
        $zip = new ZipArchive();
        $msg = $zip->open($filename);
        if (true !== $msg) {
            $msg = var_export($msg, true);
            return false;
        }
        $zip->extractTo($root);
        $zip->close();
        return true;
    }

    /**
     * 压缩之
     * @param type $filename
     * @param type $msg
     * @param type $include
     * @param type $exclude
     * @param string $trimpath
     * @param string $comment
     * @return boolean
     * @since 1.0 <2015-10-9> SoChishun Added.
     */
    function zip($filename, &$msg = '', $include = array(), $exclude = array(), $trimpath = '', $comment = 'default') {
        if (!$filename) {
            $msg = '压缩文件名无效!';
            return false;
        }
        if (!$include) {
            $msg = '压缩内容无效!';
            return false;
        }
        if ('default' == $comment) {
            $comment = basename($filename) . PHP_EOL . 'Generate at ' . date('Y-m-d H:i:s') . PHP_EOL . 'Powerd by SuExplorer.'; // 注释内容
        }
        try {
            $zip = new ZipArchive();
            $msg = $zip->open($filename, ZIPARCHIVE::OVERWRITE);
            if (true !== $msg) {
                $msg = var_export($msg, true);
                return false;
            }
            if ($comment) {
                $zip->setArchiveComment($comment);
            }
            if ($trimpath) {
                $trimpath = rtrim($trimpath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
            }
            $substart = strlen($trimpath);
            foreach ($include as $source) {
                $this->zip_dir($zip, $source, $exclude, $substart);
            }
            $zip->close();
            return true;
        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            return false;
        }
    }

    /**
     * 递归压缩整个目录
     * @param ZipArchive $zip
     * @param string $source 包含的路径
     * @param array $exclude 排除的路径
     * @param int $substart 开始截取的路径字符串(用于去除路径中的根目录路径)
     * @since 1.0 <2015-8-28> SoChishun Added.
     */
    function zip_dir(&$zip, $source, $exclude, $substart = 0) {
        if (is_dir($source)) {
            $source = rtrim($source, DIRECTORY_SEPARATOR);
            if ($handle = opendir($source)) {
                while (false !== ( $f = readdir($handle) )) {
                    if ('.' == $f || '..' == $f) {
                        continue;
                    }
                    $filename = $source . DIRECTORY_SEPARATOR . $f;
                    if (is_dir($filename)) {
                        if ($exclude && in_array($filename, $exclude)) {
                            continue;
                        }
                        $this->zip_dir($zip, $filename, $exclude, $substart);
                    } else {
                        if ($exclude && in_array($filename, $exclude)) {
                            continue;
                        }
                        $zip->addFile($filename, substr($filename, $substart));
                    }
                }
                closedir($handle);
            }
        } else {
            if ($exclude && in_array($source, $exclude)) {
                return;
            }
            $zip->addFile($source);
        }
    }
}






推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/5911.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: