<?php

/**
 * HILLS在线PHP压缩/解压程序(zip) Version-1.0.423 (RelyHills Online CDEC V1.0.423)
 */

date_default_timezone_set('prc');

$zip    = new engine_compress_decompress();

if (isset($_POST))
{
    $sourcePath = '';    //默认位置
    
    if (isset($_FILES['upfile']))   //上传文件
    {
        $stmp           = $zip->fileUpload('upfile');
        $sourcePath     = $stmp['sourcefile'];
        $upfileError    = $stmp['error'];
    }
    elseif (isset($_POST['inputfile'])) //输入目录或者文件
    {
        $sourcePath = $_POST['inputfile'];
    }
    elseif (isset($_POST['decompresssourcefiles'])) //解压缩提交
    {
        $isDecompress   = $zip->decompress($_POST['decompresssourcefiles'], $_POST['topath']);
        if (!empty($isDecompress['filelist']))
        {
            $href   = '<script type="text/javascript" language="javascript">window.location.href=\'#decompress\'</script>';
        }
        
    }
    
    $fileList           = $zip->fileArray($sourcePath); //解压缩文件列表
    
    if (isset($_POST['compressinputfileorfolder'])) //压缩文件目录或者文件输入
    {
        $sourcePath = $_POST['compressinputfileorfolder'];
        $href   = '<script type="text/javascript" language="javascript">window.location.href=\'#compress\'</script>';
        $compressFilelist   = $zip->compressFileArray($sourcePath); //压缩文件列表
    }
    elseif ((isset($_POST['selectcompressfilelist'])) && (isset($_POST['compresssavefilename'])))
    {
        $compressFiles  = $zip->compress($_POST['selectcompressfilelist'], $_POST['compresssavefilename']); //真实检测
        $isCompress     = $zip->CompileZipFile($compressFiles, $zip->savePath, 'all');
        if (!empty($isCompress))
        {
            $href   = '<script type="text/javascript" language="javascript">window.location.href=\'#compress\'</script>';
        }
    }
}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Language" content="zh-cn" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="author" content="hills" />
<meta name="keywords" content="keywords" />
<meta name="description" content="description" />
<title>RelyHills在线PHP压缩/解压程序(zip) | RelyHills Online CDEC V1.0.423</title>
<?php
echo (isset($href)) ? $href : '';
?>
<style>
<!--
body, div, form, input, select, h1, h2, h3, hr, span, ul, li
{
    margin: 0px;
    padding: 0px;
    border: none;
}
body
{
    font-size: 12px;
}
h2
{
    height: 30px;
    color: white;
    background-color: #0FB1FF;
    border-bottom: 2px solid #B0D8FF;
    margin: 2px auto 8px auto;
}
form
{
    margin: 14px 0px;
}
input
{
    border: 1px solid silver;
}
a
{
     text-decoration: none;
}
#decompress, #compress, .header, .copyright
{
    width: 820px;
    padding: 10px;
    margin: 2% auto;
    background-color: #F2F9FF;
    border: 4px solid #B0D8FF;
}
.header
{
    text-align: center;
}
.succeed, .notsucceed
{
    font-size: 14px;
    margin: 0px;
    padding: 10px;
}
.succeed h4, .notsucceed h4
{
    margin: 0px;
    padding: 4px;
    border: 1px solid blue;
}
.succeed
{
    color: green;
}
.succeed h4, .notsucceed h4
{
    border-bottom: 3px;
}
.succeed pre
{
    margin: 0px;
    padding: 10px;
    border: 1px solid blue;
    border-left: 4px solid blue;
    line-height: 22px;
}
.notsucceed
{
    color: red;
}
.copyright, .copyright a
{
    color: #bbbbbb;
}
.copyright a
{
    font-weight: bold;
}
.copyright:hover
{
    background-color: #004000;
    color: #ffffff;
}
-->
</style>
<script type="text/javascript" language="javascript">
<!--
function checkAll(inputname) //全选
{
    var hills   = document.getElementsByTagName('input');
    var leg     = hills.length;
    var i;
    for (i = 0; i < leg; i++)
    {
        if ((hills[i].type == 'checkbox') && (hills[i].name == inputname))
        {
            hills[i].checked    = true;
        }
    }
}

function uncheckAll(inputname)   // 取消全选
{
    var hills   = document.getElementsByTagName('input');
    var leg     = hills.length;
    var i;
    for (i = 0; i < leg; i++)
    {
        if ((hills[i].type == 'checkbox') && (hills[i].name == inputname))
        {
            hills[i].checked    = false;
        }
    }
}

function reverseCheckAll(inputname)  //反选
{
    var hills   = document.getElementsByTagName('input');
    var leg     = hills.length;
    var i;
    for (i = 0; i < leg; i++)
    {
        if ((hills[i].type == 'checkbox') && (hills[i].name == inputname))
        {
            hills[i].checked    = !hills[i].checked;
        }
    }
}

function checkForm(checkboxname, inputtextname) //提交表单检测checkForm(复选框控件名, 要检测的ID名称)
{
    if (checkboxname != '')
    {
        var hillsc  = document.getElementsByTagName('input');
        var leg     = hillsc.length;
        var i;
        var ckbox   = false;
            
        for (i = 0; i < leg; i++)
        {
            if ((hillsc[i].type == 'checkbox') && (hillsc[i].name == checkboxname))
            {
                if (hillsc[i].checked == true)
                {
                    ckbox   = true;
                }
            }
        }
        
        if (ckbox == false)
        {
            alert('至少选择一个文件');
            return false;
        }
    }
    
    if (inputtextname != '')
    {
        var hills   = document.getElementById(inputtextname);
        
        if (hills.value == '')
        {
            alert('必填项目,不能为空!');
            return false
        }
    }
}
-->
</script>
</head>
<body>
<div class="header"><h1>HILLS在线PHP压缩/解压程序(zip)</h1></div>
<div id="decompress">
    <h2>解压缩(请使用标准ZIP压缩包)</h2>
    <form name="uploadcompressform" action="" method="post" enctype="multipart/form-data">
        <h3>方式一:</h3>
        <span>上传一个压缩包文件(仅支持ZIP格式,大小超过2M的文件只能通过FTP上传)</span>
        <br />
        <input type="file" name="upfile" />
        <input type="submit" value="确定上传" />
        <span><?php echo (isset($upfileError)) ? $upfileError : '';?></span>
    </form>
    <form name="inputcompressform" action="" method="post">
        <h3>方式二:</h3>
        <span>直接输入文件位置(可以是完整文件名路径也可以使是目录, 相对于域名根目录)</span>
        <br />
        <input type="text" name="inputfile" value="/" />
        <input type="submit" value="确定输入" />
    </form>
    <form name="selectcompressform" action="" method="post">
        <br />
        <h3>选择压缩文件</h3>
        <br />
        <span>选择来源文件:</span>
<?php
if (isset($fileList))
{
    if (is_array($fileList))
    {
        if (!isset($fileList['pleaseinput']))
        {
            echo '        <select name="decompresssourcefiles">' . "\n";
            foreach ($fileList as $select)
            {
                echo '            <option value="' . $select . '">' . $select . '</option>' . "\n";
            }
            echo '        </select>' . "\n";
        }
        else
        {
            echo '        <span style="color:red;">' . $fileList['pleaseinput'] . '</span>' . "\n";
        }
    }
}
?>
        <br />
        <br />
        <span>填写解压缩目标目录:</span>
        <br />
        <input type="text" name="topath" value="__decompress__" />
        <input type="submit" value="确定解压" />
        <span>(不存在尝试自动创建,相对于域名根目录, 默认为域名根目录下的 __decompress__ )</span>
    </form>
<?php
if (isset($isDecompress))
{
    if (empty($isDecompress['error']))
    {
        $filelistTemp   = $isDecompress;
?>
    <div class="succeed" name="decompress">
        <h4>解压缩成功&nbsp;&nbsp;&nbsp;&nbsp;共创建: <font color="red"><?php echo (isset($filelistTemp['totalfolder'])) ? $filelistTemp['totalfolder'] : ''?></font>个目录,<font color="blue"><?php echo (isset($filelistTemp['totalfiles'])) ? $filelistTemp['totalfiles'] : ''?></font>个文件 </h4>
<?php
        if (is_array($filelistTemp['filelist']))
        {
?>
        <form name="listfiledecompressform" action="" method="post" onsubmit="return checkForm('listfiledecompress[]');">
        <pre>
<?php
            if (!empty($filelistTemp['filelist']))
            {
                foreach ($filelistTemp['filelist'] as $key => $value)
                {
                    echo '<input type="checkbox" name="listfiledecompress[]" value="' . $filelistTemp['fileroot'] . $key . '" />';
                    if ($value  == 1)
                    {
                        echo '文件:';
                    }
                    else
                    {
                        echo '目录:';
                    }
                    echo '<a href="' . $filelistTemp['linkurl'] . $key . '">';
                    echo $filelistTemp['fileroot'] . $key . "</a>\n";
                    
                }
            }
?>
        </pre>
        <h4>
            <input type="button" value="返回" onclick="window.location.href='<?php echo $_SERVER['PHP_SELF'];?>';" />
            &nbsp;&nbsp;&nbsp;&nbsp;
            <input type="button" value="全选" onclick="checkAll('listfiledecompress[]');" />
            <input type="button" value="反选" onclick="reverseCheckAll('listfiledecompress[]');" />
            <input type="button" value="取消选择" onclick="uncheckAll('listfiledecompress[]');" />
            &nbsp;&nbsp;&nbsp;&nbsp;
            <input type="submit" value="删 除选中" />
        </h4>
        </form>
<?php
        }
?>
    </div>
<?php
    }
    else
    {
?>
    <div class="notsucceed">
        <h4>解压缩失败</h4>
    </div>
<?php
    }
}
elseif (isset($_POST['listfiledecompress']))  //删除文件操作
{
    $deleteList = $_POST['listfiledecompress'];
    if (!empty($deleteList))
    {
        if (is_array($deleteList))
        {
?>
    <pre>
<?php
            foreach ($deleteList as $dkey => $dvalue)
            {
                $delete[$dkey]   = $_SERVER['DOCUMENT_ROOT'] . $deleteList[$dkey];
                if (is_file($delete[$dkey]))
                {
                    if (@unlink($delete[$dkey]))
                    {
                        echo '<font color="blue">文件: ' . $deleteList[$dkey] . ' 已删除</font>' . "\n";
                    }
                    else
                    {
                        echo '<font color="red">文件: ' . $deleteList[$dkey] . ' 删除失败</font>' . "\n";
                    }
                }
                elseif (is_dir($delete[$dkey]))
                {
                    if (@rmdir($delete[$dkey]))
                    {
                        echo '<font color="blue">目录: ' . $deleteList[$dkey] . ' 已删除</font>' . "\n";
                    }
                    else
                    {
                        echo '<font color="red">目录: ' . $deleteList[$dkey] . ' 删除失败(目录非空)</font>' . "\n";
                    }
                 }
            }
            
            echo '<input type="button" value="操作完成,点击这里返回" onclick="window.location.href=\'' . $_SERVER['PHP_SELF'] . '\'" />';
?>
    </pre>
<?php
        }
    }
}
?>
</div>

<div id="compress" name="compress">
    <h2>压缩,打包</h2>
    <form name="inputcompressorfileform" action="" method="post">
        <h3>第一步:输入需要打包的文件夹:</h3>
        <span>(相对本程序目录,如果不输入则为相对本程序目录下的所有文件及文件夹)</span>
        <br />
        <input type="text" name="compressinputfileorfolder" value="" />
        <input type="submit" value="确认目录" />
    </form>
    <form name="compressselectfileorfolder" action="" method="post" onsubmit="return checkForm('selectcompressfilelist[]', 'compresssavefilename');">
        <h3>第二步:选择要打包的文件, 并填写压缩文件名</h3>
        压缩文件名(相对本程序目录, 可使用路径+文件名):
        <input type="text" name="compresssavefilename" id="compresssavefilename" value="hillsOnlineCompress.zip" />
        <input type="submit" value="确认打包" />
        <br /><br /><br />
<?php
if (isset($compressFilelist['files']))
{
?>
        <input type="button" value="全选" onclick="checkAll('selectcompressfilelist[]'); window.location.href='#compress'" />
        <input type="button" value="反选" onclick="reverseCheckAll('selectcompressfilelist[]'); window.location.href='#compress'" />
        <input type="button" value="取消选择" onclick="uncheckAll('selectcompressfilelist[]'); window.location.href='#compress'" />
        <br />
<?php
    if (is_array($compressFilelist['files']))
    {
        echo "        <pre>\n";
        foreach ($compressFilelist['files'] as $cvalue)
        {
?>
<input type="checkbox" name="selectcompressfilelist[]" value="<?php echo $cvalue;?>" checked="checked" /><?php echo $cvalue . "\n";?>
<?php
        }
        echo "        </pre>\n";
    }
}
?>
    </form>
<?php
if (isset($compressFilelist['error']))
{
    echo '        <font color="red">' . $compressFilelist['error'] . '</font>';
}
if (isset($isCompress))
{
    if ($isCompress > 0)
    {
?>
    <div class="succeed">
        <h4>压缩成功, 共压缩 <?php echo $isCompress;?> 个文件</h4>
        <br /><br />
        <input type="button" value="操作完成,返回" onclick="window.location.href='<?php echo $_SERVER['PHP_SELF'] ;?>'" />
    </div>
<?php
    }
    elseif ($isCompress == 0)
    {
?>
    <div class="notsucceed">
        <h4>压缩失败</h4>
        <br /><br />
        <input type="button" value="操作错误,返回" onclick="window.location.href='<?php echo $_SERVER['PHP_SELF'] ;?>'" />
    </div>
<?php
    }
}
?>
</div>
<div class="copyright">
    <ul>
        <li>Copyright:&copy;2010 RelyHills(abzz.net).All rights reserved.</li>
        <li>Powered by <a href="http://abzz.net/">abzz.net</a>. </li>
        <li>Author/hills. Contact way/Tencent QQ : 3303911, Email : <a href="mailto:hackhgs@qq.com" target="_blank">hackhgs@qq.com</a></li>
        <li>Release date: 2010-04-23, Versions: RelyHills Online CDEC V1.0.423</li>
    </ul>
</div>
</body>
</html>
<?php

/**
 * @class     engine_compress_decompress
 * @function  压缩文件操作引擎
 * @version   1.0.4
 * @date      2010-4-19 19:50
 * @author    hills
 * @copyright 2010-2012 RelyHills All rights reserved.
 */

class engine_compress_decompress
{
    public      $sourcePath     = '';       //文件操作源路径
    public      $savePath       = '';       //文件操作目标路径
    public      $object         = false;    //wscript.shell实例对象
    public      $resultInfo     = array();  //返回信息
    public      $documentRoot   = '';       //站点根目录
    
    public $datasec, $ctrl_dir = array();
    public $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
    public $old_offset = 0;
    public $dirs = array(".");
    
    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->documentRoot = $_SERVER['DOCUMENT_ROOT'];    //站点本目录
    }
    
    /**
     * decompress($sourcePath, $toPath)
     * $sourcePath : 来源文件路径
     * $toPath     : 解压缩目标
     * 作用:解压缩文件
     */
    public function decompress($sourceFile, $toPath)
    {
        $sourceFile         = $this->documentRoot . $sourceFile;    //转换为绝对目录
        $toPath             = ((substr($toPath, 0, 1) == '/') || (substr($toPath, 0, 1) == '\\')) ? $toPath : '/' . $toPath;
        $toPath             = $this->documentRoot . str_replace($this->documentRoot, '', $toPath);  //转换为绝对目录
        
        $errorTmp   = null;
        
        if (is_file($sourceFile) == false)
        {
            $errorTmp   = '不是有效文件 : ' . $this->sourcePath;
        }
        else
        {
            $this->sourcePath   = $this->replacePath($sourceFile);
            $fileName   = @strtolower(@substr(@strrchr($this->sourcePath, '/'), 1));  //取最后一个反斜线以后的字符串,文件名
            $fileRoot   = @substr($this->sourcePath, 0, (@strlen($this->sourcePath) - @strlen($fileName)));   //获得源文件目录路径
        }
        
        if (is_dir($toPath) == false)    //判断目标目录是否存在
        {
            $isToPath   = $this->dirCreate($toPath);  //创建不存在的目录
            if ($isToPath !== true)
            {
                $errorTmp   = '无法自动创建目录 : ' . $toPath;   //无法创建目标目录错误信息
            }
        }
        
        if (is_dir($toPath) == false)
        {
            $errorTmp   = '目标目录不正确';
        }
        else
        {
            if (substr($toPath, 0, -1) != '/')
            {
                $toPath = $this->replacePath($toPath);
            }
            $this->savePath = $toPath;
        }
        
        if (empty($errorTmp))
        {
            $resultTemp    = $this->ExtractAll($this->sourcePath, $this->savePath); //执行解压
            if ($resultTemp == -1)
            {
                $this->resultInfo['error']  = '文件: ' . $fileName . ' 解压缩失败';
            }
            else
            {
                $this->resultInfo['filelist']   = $resultTemp;
                $totalFolder    = 0;
                $totalFiles     = 0;
                foreach ($this->resultInfo['filelist'] as $value)
                {
                    if ($value == (1))
                    {
                        $totalFiles     += 1;
                    }
                    if ($value === (-1))
                    {
                        $totalFolder    += 1;
                    }
                }
                $this->resultInfo['totalfolder']    = $totalFolder; //解压的总目录数
                $this->resultInfo['totalfiles']     = $totalFiles;  //解压的总文件数
                $this->resultInfo['linkurl']        = 'http://' . $_SERVER['HTTP_HOST'] . str_replace($this->documentRoot, '', $this->savePath);  //文件解压缩目标路径
                $this->resultInfo['fileroot']       = str_replace($this->documentRoot, '', $this->savePath);
            }
        }
        else
        {
            $this->resultInfo['error']  = $errorTmp;
        }
        
        return $this->resultInfo;
    }
    
    /**
     * compress($sourcePath = '', $toPath = '')
     * $sourceFileName : 来源文件路径
     * $toPath         : 保存目标路径
     * 作用:压缩文件
     */
    public function compress($sourcePath = array(), $toPath = '')
    {
        $errorC     = null;
        $filesA     = array();
        //$fileList   = '';
        if ((!empty($sourcePath)) && (!empty($toPath)))
        {
            //修正输入的不规则目录
            $toPath = str_replace('\\', '/', $toPath);
            if (substr($toPath, 0, 1) == '/')
            {
                $toPath = substr($toPath, 1);
            }
            $this->savePath = str_replace($this->documentRoot . dirname($_SERVER['PHP_SELF']), '', $toPath);
            
            if (is_array($sourcePath))  //是数组
            {
                if (!empty($sourcePath))    //不为空
                {
                    foreach ($sourcePath as $value)
                    {
                        if (file_exists($value))  //文件存在
                        {
                            if ((is_dir($value)) && (substr($value, 0, -1) != '/'))
                            {
                                $value  = $value . '/';
                            }
                            $filesA[]   = $value;
                        }
                        else
                        {
                            $errorC   = '文件' . $value . '不存在';
                        }
                    }
                }
            }
        }
        else
        {
            $errorC   = '请完整输入';
        }
        
        if ((empty($errorC)) && (!empty($filesA)))  //条件都成立时执行打包压缩
        {
            return $filesA;
        }
        
    }
    
    /**
     * fileUpload($inputName = '')
     * $inputName : 文件上传表单控件名
     * 作用:文件上传
     */
    public function fileUpload($inputName = '')
    {
        $fuResult   = array();
        $sourcePath = '';   //上传移动后的文件名路径
        if ($inputName == '')
        {
            $inputName  = 'upfile';
        }
        
        if ($this->fileext($_FILES["{$inputName}"]['name']) == 'zip')
        {
            $sourceFile = $_FILES["{$inputName}"]['tmp_name'];
            $targetFile = dirname($_SERVER['PHP_SELF']) . '/' . $_FILES["{$inputName}"]['name'];
            
            $isMove = @move_uploaded_file($sourceFile, $_SERVER['DOCUMENT_ROOT'] . $targetFile);
            if ($isMove != false)
            {
                $sourcePath = $targetFile;
                $upfileError    = '<font color="green">文件上传成功</font>';
            }
            else
            {
                /*
                UPLOAD_ERR_OK
                其值为 0，没有错误发生，文件上传成功。 
                UPLOAD_ERR_INI_SIZE
                其值为 1，上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。 
                UPLOAD_ERR_FORM_SIZE
                其值为 2，上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。 
                UPLOAD_ERR_PARTIAL
                其值为 3，文件只有部分被上传。 
                UPLOAD_ERR_NO_FILE
                其值为 4，没有文件被上传。 
                UPLOAD_ERR_NO_TMP_DIR
                其值为 6，找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。 
                UPLOAD_ERR_CANT_WRITE
                其值为 7，文件写入失败。PHP 5.1.0 引进。 
                */
                if ($_FILES["{$inputName}"]['error'] == 4)
                {
                    $upfileError    = '<font color="red">上传文件不能为空</font>';
                }
                elseif (($_FILES["{$inputName}"]['error'] == 1) || $_FILES["{$inputName}"]['error'] == 2)
                {
                    $upfileError    = '<font color="red">上传文件大小超过限制</font>';
                }
                elseif ($_FILES["{$inputName}"]['error'] == 6)
                {
                    $upfileError    = '<font color="red">上传文件转移时发生错误</font>';
                }
                elseif ($_FILES["{$inputName}"]['error'] == 7)
                {
                    $upfileError    = '<font color="red">上传文件写入失败</font>';
                }
                elseif ($_FILES["{$inputName}"]['error'] == 3)
                {
                    $upfileError    = '<font color="red">只有部分文件被上传</font>';
                }
                else
                {
                    $upfileError    = '<font color="red">上传失败,未知错误</font>';
                }
            }
        }
        else
        {
            $upfileError= '<font color="red">文件只能是ZIP类型</font>';
        }
        $fuResult['sourcefile'] = $sourcePath;
        $fuResult['error']      = $upfileError;
        return $fuResult;
    }
    
    /**
     * fileArray($sourceFile = '')
     * $sourceFile : 来源文件名(可包括完整物理路径)
     * 获得文件(数组)
     */
    public function fileArray($sourceFile = '')
    {
        $filearray  = array();  //文件列表
        
        if (!empty($sourceFile))
        {
            if (stristr($sourceFile, $this->documentRoot) != false)
            {
                $sourceFile = str_replace($this->documentRoot, '', $sourceFile);
            }
            
            if (substr($sourceFile, 0, 1) != '/')
            {
                $sourceFile = '/' . $sourceFile;
            }
            
            if (is_file($this->documentRoot . $sourceFile))   //文件存在时
            {
                if ($this->fileext($sourceFile) == 'zip')  //找出ZIP类型文件
                {
                    $filearray[]    = str_replace($this->documentRoot, '', $sourceFile);   //得到文件列表(数组)
                }
                else
                {
                    $filearray['pleaseinput']    = '文件只能是ZIP类型';
                }
            }
            else    //指定文件不存在则尝试在本文件目录搜索压缩格式文件,并列表
            {
                if (is_dir($this->documentRoot . $sourceFile))
                {
                    $flieList   = $this->fileList($this->documentRoot . $sourceFile);
                    foreach ($flieList as $value)   //遍历文件列表数组
                    {
                        if ($this->fileext($value) == 'zip')  //找出ZIP类型文件
                        {
                            $filearray[] = str_replace($this->documentRoot, '', $value);   //得到文件列表(数组)
                        }
                    }
                }
                else
                {
                    $filearray['pleaseinput']    = '不是有效文件或目录, 请重新输入';
                }
            }
        }
        else
        {
            $filearray['pleaseinput']    = '请在上一步骤输入需要操作的文件路径或者文件夹来获取文件';
        }
        
        if (empty($filearray))
        {
            $filearray['pleaseinput']    = '该目录没有任何可解压缩的文件';
        }
        return $filearray;
    }
    
    /**
     * compressFileArray($sourceFile = '')
     $sourceFile : 来源文件名(可包括完整物理路径)
     * 获得文件(数组)
     */
    public function compressFileArray($sourceFile)
    {
        $resultArray= array();  //返回值
        $filearray  = array();  //文件列表
        $errorarray = '';  //错误信息
        
        if (isset($sourceFile))
        {
            if (stristr($sourceFile, $this->documentRoot) != false) //检测是否是绝对路径
            {
                $sourceFile = str_replace($this->documentRoot, '', $sourceFile);
            }
            
            if (($sourceFile == '/') || ($sourceFile == ''))
            {
                $sourceFile = './';
            }
            
            $this->sourcePath   = $sourceFile;
            
            if (is_file($this->sourcePath))   //文件存在时
            {
                $filearray[]    = $this->sourcePath;   //得到文件列表(数组)
            }
            else    //指定文件不存在则尝试在本文件目录搜索压缩格式文件,并列表
            {
                if (is_dir($this->sourcePath))
                {
                    $flieList   = $this->fileListC($this->sourcePath);
                    foreach ($flieList as $value)   //遍历文件列表数组
                    {
                        $newValue = str_replace($this->documentRoot, '', $value);   //得到文件列表(数组)
                        if (substr($newValue, 0, 3) == '../')
                        {
                            continue;
                        }
                        /*
                        elseif (is_dir($newValue))
                        {
                            continue;
                        }
                        */
                        elseif (substr($newValue, 0, 2) == './')
                        {
                            $newValue   = substr($newValue, 2);
                        }
                        $filearray[]    = $newValue;
                    }
                }
                else
                {
                    $errorarray    = '不是有效文件或目录, 请重新输入';
                }
            }
        }
        else
        {
            $errorarray    = '请在上一步骤输入需要操作的文件路径或者文件夹来获取文件';
        }
        
        if ((empty($filearray)) && (empty($errorarray)))
        {
            $resultArray['error']   = '该目录没有任何可解压缩的文件';
        }
        elseif (!empty($errorarray))
        {
            $resultArray['error']   = $errorarray;
        }
        else
        {
            $resultArray['files']    = $filearray;
        }
        
        return $resultArray;
    }
    
     /**
     * fileext($filename);
     * $filename :    完整文件名
     * 作用:获得文件扩展名
     */
    public function fileext($filename)
    {
        return @strtolower(@substr(@strrchr($filename, '.'), 1,10));
    }
    
     /**
     * dirReplace($dirString)
     * $dirString : 路径字符串
     * 作用:替换WINDOWS目录路径中的反斜线"\"为"/", 并返回最后带"/"的路径字符串
     */
    public function replacePath($dirString)
    {
        $temp   = str_replace('\\', '/', $dirString);
        
        if ((substr($temp, 0, -1) != '/') && (is_file($temp) == false))
        {
            $temp   .= '/';
        }
        $temp   = str_replace('//', '/', $temp);
        $temp   = str_replace('\\/', '/', $temp);
        $temp   = str_replace('/\\', '/', $temp);
        return $temp;
    }
    
    /**
     * dirCreate($dirName)
     * $dirName : 目录名
     * 作用:创建目录, 支持多级目录,直接输入root1/root2/root3....
     * 发生错误返回错误数组否则返回true
     */
    public function dirCreate($dirName)
    {
        $dirName        = $this->replacePath($dirName);
        $dirTemp        = explode('/', $dirName);
        $dirCount       = count($dirTemp) - 1;
        $dirCur         = '';
        $dirCreateError = array();
        
        for ($j = 0; $j < $dirCount; $j++)
        {
            $dirCur .= $dirTemp[$j] . '/';
            if (is_dir($dirCur))    //如果目录存在,跳出本次循环
            {
                continue;
            }
            $isMkdir    = @mkdir($dirCur, 0777);
            if ($isMkdir == false)
            {
                $dirCreateError[$j] = $dirTemp[$j];
            }
        }
        
        if (empty($dirCreateError))
        {
            return true;
        }
        else
        {
            return $dirCreateError;
        }
    }
    
    /**
     * fileList($dir, $list = array())
     * 作用:获得目录及子目录的压缩格式文件列表数组
     */
    public function fileList($dir, $list = array())
    {
        if (!is_array($list))
        {
            $list   = array();
        }
        
        if (empty($dir))    //路径为空转换为当前
        {
            $dir    = './';
        }
        
        $dir    = str_replace('//', '/', $this->replacePath($dir));
        
        $files  = glob($dir . '*');
        
        foreach ($files as $value)
        {
            $list[] = $value;
            if (is_dir($value))
            {
                $list   = $this->fileList($value, $list);
            }
        }
        return $list;
    }
    
    /**
     * fileListC($dir, $list = array())
     * 作用:获得目录及子目录的压缩格式文件列表数组
     */
    public function fileListC($dir, $list = array())
    {
        if (!is_array($list))
        {
            $list   = array();
        }
        
        $dir    = str_replace('//', '/', $this->replacePath($dir));
        
        $files  = glob($dir . '*');
        
        foreach ($files as $value)
        {
            if (is_dir($value))
            {
                $list = $this->fileList($value, $list);
            }
            else
            {
                $list[] = $value;
            }
        }
        return $list;
    }
    
    /**
     * 网友的方法
     */
    public function get_List($zip_name)
    {
        $ret = '';
        $zip = @fopen($zip_name, 'rb');
        if (!$zip)
        {
            return (0);
        }
        $centd = $this->ReadCentralDir($zip, $zip_name);
        @rewind($zip);
        @fseek($zip, $centd['offset']);
        for ($i = 0; $i < $centd['entries']; $i++)
        {
            $header = $this->ReadCentralFileHeaders($zip);
            $header['index'] = $i;
            $info['filename'] = $header['filename'];
            $info['stored_filename'] = $header['stored_filename'];
            $info['size'] = $header['size'];
            $info['compressed_size'] = $header['compressed_size'];
            $info['crc'] = strtoupper(dechex($header['crc']));
            $info['mtime'] = $header['mtime'];
            $info['comment'] = $header['comment'];
            $info['folder'] = ($header['external'] == 0x41FF0010 || $header['external'] == 16) ? 1 : 0;
            $info['index'] = $header['index'];
            $info['status'] = $header['status'];
            $ret[] = $info;
            unset($header);
        }
        return $ret;
    }

    public function Add($files, $compact)
    {
        if (!is_array($files[0]))
        {
            $files = array($files);
        }
        for ($i = 0; $files[$i]; $i++)
        {
            $fn = $files[$i];
            if (!in_Array(dirname($fn[0]), $this->dirs))
            {
                $this->add_Dir(dirname($fn[0]));
            }
            if (basename($fn[0]))
            {
                $ret[basename($fn[0])] = $this->add_File($fn[1], $fn[0], $compact);
            }
        }
        return $ret;
    }

    public function get_file()
    {
        $data = implode('', $this->datasec);
        $ctrldir = implode('', $this->ctrl_dir);
        return $data . $ctrldir . $this->eof_ctrl_dir . pack('v', sizeof($this->ctrl_dir)) . pack('v', sizeof($this->ctrl_dir)) . pack('V', strlen($ctrldir)) . pack('V', strlen($data)) . "\x00\x00";
    }

    public function add_dir($name)
    {
        $name = str_replace("\\", "/", $name);
        $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
        $fr .= pack("V", 0) . pack("V", 0) . pack("V", 0) . pack("v", strlen($name));
        $fr .= pack("v", 0) . $name . pack("V", 0) . pack("V", 0) . pack("V", 0);
        $this->datasec[] = $fr;
        $new_offset = strlen(implode("", $this->datasec));
        $cdrec = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
        $cdrec .= pack("V", 0) . pack("V", 0) . pack("V", 0) . pack("v", strlen($name));
        $cdrec .= pack("v", 0) . pack("v", 0) . pack("v", 0) . pack("v", 0);
        $ext = "\xff\xff\xff\xff";
        $cdrec .= pack("V", 16) . pack("V", $this->old_offset) . $name;
        $this->ctrl_dir[] = $cdrec;
        $this->old_offset = $new_offset;
        $this->dirs[] = $name;
    }
    
    
    public function CompileZipFile($filename, $tozipfilename, $ftype = 'dir')
    {
        if (@function_exists('gzcompress'))
        {
            if ($ftype == 'dir')
            {
                $filelist = $this->ListDirFiles($filename);
            }
            elseif ($ftype == 'file')
            {
                $filelist[] = $filename;
            }
            else
            {
                $filelist = $filename;
            }
            $i = 0;
            if (count($filelist) > 0)
            {
                foreach ($filelist as $filename)
                {
                    if (is_file($filename))
                    {
                        $i++;
                        $fd = fopen($filename, "r");
                        if (filesize($filename) > 0)
                        {
                            $content = fread($fd, filesize($filename));
                        }
                        else
                        {
                            $content = ' ';
                        }
                        fclose($fd);
                        
                        $this->add_File($content, $filename);
                    }
                }
                
                $out = $this->get_file();
                $fp = fopen($tozipfilename, "w");
                fwrite($fp, $out, strlen($out));
                fclose($fp);
            }
            return $i;
        }
        else
        {
            return 0;
        }
    }
    
    //读取某文件夹的所有文件-原
    public function ListDirFiles($dirname)
    {
        $files = array();
        
        if (is_dir($dirname))
        {
            $fh = opendir($dirname);
            while (($file = readdir($fh)) !== false)
            {
                if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0)
                {
                    continue;
                }
                $filepath = $dirname . '/' . $file;
                if (is_dir($filepath))
                {
                    $files = array_merge($files, $this->ListDirFiles($filepath));
                }
                else
                {
                    array_push($files, $filepath);
                }
            }
            closedir($fh);
        }
        else
        {
            $files = false;
            //$files  += $dirname;
        }
        
        return $files;
    }

    public function add_File($data, $name, $compact = 1)
    {
        $name = str_replace('\\', '/', $name);
        $dtime = dechex($this->DosTime());

        $hexdtime = '\x' . $dtime[6] . $dtime[7] . '\x' . $dtime[4] . $dtime[5] . '\x' . $dtime[2] . $dtime[3] . '\x' . $dtime[0] . $dtime[1];
        eval('$hexdtime = "' . $hexdtime . '";');
        if ($compact) $fr = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" . $hexdtime;
        else
        {
            $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00" . $hexdtime;
        }
        $unc_len = strlen($data);
        $crc = crc32($data);
        if ($compact)
        {
            $zdata = gzcompress($data);
            $c_len = strlen($zdata);
            $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
        }
        else
        {
            $zdata = $data;
        }
        $c_len = strlen($zdata);
        $fr .= pack('V', $crc) . pack('V', $c_len) . pack('V', $unc_len);
        $fr .= pack('v', strlen($name)) . pack('v', 0) . $name . $zdata;
        $fr .= pack('V', $crc) . pack('V', $c_len) . pack('V', $unc_len);
        $this->datasec[] = $fr;
        $new_offset = strlen(implode('', $this->datasec));
        if ($compact)
        {
            $cdrec = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00";
        }
        else
        {
            $cdrec = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00";
        }
        $cdrec .= $hexdtime . pack('V', $crc) . pack('V', $c_len) . pack('V', $unc_len);
        $cdrec .= pack('v', strlen($name)) . pack('v', 0) . pack('v', 0);
        $cdrec .= pack('v', 0) . pack('v', 0) . pack('V', 32);
        $cdrec .= pack('V', $this->old_offset);
        $this->old_offset = $new_offset;
        $cdrec .= $name;
        $this->ctrl_dir[] = $cdrec;
        return true;
    }

    public function DosTime()
    {
        $timearray = getdate();
        if ($timearray['year'] < 1980)
        {
            $timearray['year'] = 1980;
            $timearray['mon'] = 1;
            $timearray['mday'] = 1;
            $timearray['hours'] = 0;
            $timearray['minutes'] = 0;
            $timearray['seconds'] = 0;
        }
        return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
    }

    //解压整个压缩包
    //直接用 Extract 会有路径问题，本函数先从列表中获得文件信息并创建好所有目录然后才运行 Extract
    public function ExtractAll($zn, $to)
    {
        if (substr($to, -1) != "/")
        {
            $to .= "/";
        }
        $files = $this->get_List($zn);
        $cn = count($files);
        if (is_array($files))
        {
            for ($i = 0; $i < $cn; $i++)
            {
                if ($files[$i]['folder'] == 1)
                {
                    @mkdir($to . $files[$i]['filename'], $GLOBALS['cfg_dir_purview']);
                    @chmod($to . $files[$i]['filename'], $GLOBALS['cfg_dir_purview']);
                }
            }
        }
        return $this->Extract($zn, $to);
    }

    public function Extract($zn, $to, $index = array(-1))
    {
        $ok = 0;
        $zip = @fopen($zn, 'rb');
        if (!$zip)
        {
            return (-1);
        }
        $cdir = $this->ReadCentralDir($zip, $zn);
        $pos_entry = $cdir['offset'];
        if (!is_array($index))
        {
            $index = array($index);
        }
        for ($i = 0; isset($index[$i]); $i++)
        {
            if (intval($index[$i]) != $index[$i] || $index[$i] > $cdir['entries'])
            {
                return (-1);
            }
        }
        for ($i = 0; $i < $cdir['entries']; $i++)
        {
            @fseek($zip, $pos_entry);
            $header = $this->ReadCentralFileHeaders($zip);
            $header['index'] = $i;
            $pos_entry = ftell($zip);
            @rewind($zip);
            fseek($zip, $header['offset']);
            if (in_array("-1", $index) || in_array($i, $index))
            {
                $stat[$header['filename']] = $this->ExtractFile($header, $to, $zip);
            }

        }
        fclose($zip);
        return $stat;
    }

    public function ReadFileHeader($zip)
    {
        $binary_data = fread($zip, 30);
        $data = unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data);
        $header['filename'] = fread($zip, $data['filename_len']);
        if ($data['extra_len'] != 0)
        {
            $header['extra'] = fread($zip, $data['extra_len']);
        }
        else
        {
            $header['extra'] = '';
        }
        $header['compression'] = $data['compression'];
        $header['size'] = $data['size'];
        $header['compressed_size'] = $data['compressed_size'];
        $header['crc'] = $data['crc'];
        $header['flag'] = $data['flag'];
        $header['mdate'] = $data['mdate'];
        $header['mtime'] = $data['mtime'];
        if ($header['mdate'] && $header['mtime'])
        {
            $hour = ($header['mtime'] & 0xF800) >> 11;
            $minute = ($header['mtime'] & 0x07E0) >> 5;
            $seconde = ($header['mtime'] & 0x001F) * 2;
            $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
            $month = ($header['mdate'] & 0x01E0) >> 5;
            $day = $header['mdate'] & 0x001F;
            $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
        }
        else
        {
            $header['mtime'] = time();
        }
        $header['stored_filename'] = $header['filename'];
        $header['status'] = "ok";
        return $header;
    }

    public function ReadCentralFileHeaders($zip)
    {
        $binary_data = fread($zip, 46);
        $header = unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data);
        if ($header['filename_len'] != 0)
        {
            $header['filename'] = fread($zip, $header['filename_len']);
        }
        else
        {
            $header['filename'] = '';
        }
        if ($header['extra_len'] != 0)
        {
            $header['extra'] = fread($zip, $header['extra_len']);
        }
        else
        {
            $header['extra'] = '';
        }
        if ($header['comment_len'] != 0)
        {
            $header['comment'] = fread($zip, $header['comment_len']);
        }
        else
        {
            $header['comment'] = '';
        }
        if ($header['mdate'] && $header['mtime'])
        {
            $hour = ($header['mtime'] & 0xF800) >> 11;
            $minute = ($header['mtime'] & 0x07E0) >> 5;
            $seconde = ($header['mtime'] & 0x001F) * 2;
            $year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
            $month = ($header['mdate'] & 0x01E0) >> 5;
            $day = $header['mdate'] & 0x001F;
            $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
        }
        else
        {
            $header['mtime'] = time();
        }
        $header['stored_filename'] = $header['filename'];
        $header['status'] = 'ok';
        if (substr($header['filename'], -1) == '/')
        {
            $header['external'] = 0x41FF0010;
        }
        return $header;
    }

    public function ReadCentralDir($zip, $zip_name)
    {
        $size = filesize($zip_name);
        if ($size < 277)
        {
            $maximum_size = $size;
        }
        else
        {
            $maximum_size = 277;
        }
        @fseek($zip, $size - $maximum_size);
        $pos = ftell($zip);
        $bytes = 0x00000000;

        while ($pos < $size)
        {
            $byte = @fread($zip, 1);
            $bytes = ($bytes << 8) | ord($byte);
            if ($bytes == 0x504b0506)
            {
                $pos++;
                break;
            }
            $pos++;
        }
        $data = @unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', fread($zip, 18));
        if ($data['comment_size'] != 0)
        {
            $centd['comment'] = fread($zip, $data['comment_size']);
        }
        else
        {
            $centd['comment'] = '';
            $centd['entries'] = $data['entries'];
        }
        $centd['disk_entries'] = $data['disk_entries'];
        $centd['offset'] = $data['offset'];
        $centd['disk_start'] = $data['disk_start'];
        $centd['size'] = $data['size'];
        $centd['disk'] = $data['disk'];
        return $centd;
    }

    public function ExtractFile($header, $to, $zip)
    {
        $header = $this->readfileheader($zip);
        $header['external'] = (!isset($header['external']) ? 0 : $header['external']);
        if (substr($to, -1) != "/")
        {
            $to .= "/";
        }
        if (!@is_dir($to))
        {
            @mkdir($to, $GLOBALS['cfg_dir_purview']);
        }
        if (!($header['external'] == 0x41FF0010) && !($header['external'] == 16))
        {
            if ($header['compression'] == 0)
            {
                $fp = @fopen($to . $header['filename'], 'wb');
                if (!$fp)
                {
                    return (-1);
                }
                $size = $header['compressed_size'];
                while ($size != 0)
                {
                    $read_size = ($size < 2048 ? $size : 2048);
                    $buffer = fread($zip, $read_size);
                    $binary_data = pack('a' . $read_size, $buffer);
                    @fwrite($fp, $binary_data, $read_size);
                    $size -= $read_size;
                }
                fclose($fp);
                touch($to . $header['filename'], $header['mtime']);
            }
            else
            {
                $fp = @fopen($to . $header['filename'] . '.gz', 'wb');
                if (!$fp)
                {
                    return (-1);
                }
                $binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($header['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
                fwrite($fp, $binary_data, 10);
                $size = $header['compressed_size'];
                while ($size != 0)
                {
                    $read_size = ($size < 1024 ? $size : 1024);
                    $buffer = fread($zip, $read_size);
                    $binary_data = pack('a' . $read_size, $buffer);
                    @fwrite($fp, $binary_data, $read_size);
                    $size -= $read_size;
                }

                $binary_data = pack('VV', $header['crc'], $header['size']);
                fwrite($fp, $binary_data, 8);
                fclose($fp);
                $gzp = @gzopen($to . $header['filename'] . '.gz', 'rb') or die("Cette archive est compress");
                if (!$gzp)
                {
                    return (-2);
                }
                $fp = @fopen($to . $header['filename'], 'wb');
                if (!$fp)
                {
                    return (-1);
                }
                $size = $header['size'];
                while ($size != 0)
                {
                    $read_size = ($size < 2048 ? $size : 2048);
                    $buffer = gzread($gzp, $read_size);
                    $binary_data = pack('a' . $read_size, $buffer);
                    @fwrite($fp, $binary_data, $read_size);
                    $size -= $read_size;
                }
                fclose($fp);
                gzclose($gzp);
                touch($to . $header['filename'], $header['mtime']);
                @unlink($to . $header['filename'] . '.gz');
            }
        }
        return true;
    }
}
?>