闲者博客 - 压缩 2022-03-05T02:12:00+08:00 Typecho https://bk1314.com/feed/atom/tag/%E5%8E%8B%E7%BC%A9/ <![CDATA[php边压缩边下载]]> https://bk1314.com/58.html 2022-03-05T02:12:00+08:00 2022-03-05T02:12:00+08:00 飞鱼 http://www.typecho.org php实现边压缩边下载,原理大概就是,每压缩一个文件就输出给浏览器。实现压缩与下载同步进行。

1.关键代码如下

<?php
//根据需求配置内存和执行时间
set_time_limit(360000);
ini_set('memory_limit','20000M');
ob_clean();//洗干净开始干活
header("Content-Disposition: attachment; filename=".date('Y-m-d_hisa').".zip");//设置下载压缩包名称
require ('zip.class.php');//引用类这个类是phpmyadmin/libraries/zip.lib.php  这个的文件 引用记得删除头部的判断
//创建生成器
$zip = new ZipFile();
//开启流式压缩
$zip->setDoWrite();
$data1;
define('BASE_PATH',str_replace('\\','/',realpath(dirname(__FILE__).'/'))."/");//去当前执行文件绝对路径
//define('WWWROOT',$_SERVER['DOCUMENT_ROOT']."/");//网站根目录,如果需要用这个直接屏蔽上面一行代码用这个变量 把下面BASE_PATH替换成WWWROOT即可
$lj=BASE_PATH."bbb";//设置需要打包的目录,方便下面替换避免压缩包把整个路径的文件夹创建
$filearr1 = list_file($lj);//所有待压缩的文件数组,一般只存路径即可
$filearr=toOneArray($filearr1);//多维数组改为一维数组
foreach ($filearr as $key => $value) {
    try{
        //此处可以添加用户连接判断,若是用户取消了下载或断开了链接就终止操作
        $url = $value;
        $file= file_get_contents($url);//获取文件内容,用file_get_content即可,这个是我自己封装的
        $value=str_replace($lj."/", "", $value);//替换路径避免压缩包多余路径文件夹
        $zip->addFile($file,iconv("utf-8","gbk",$value));//调用类的addFile开始压缩
        ob_flush();//输出本次压缩的文件
    }catch(Exception $e){
       log($e);
    }
}
//输出zip文件尾部
$zip->file();
flush();//结束上传,缺少可能会引起压缩文件打不开
function list_file($date){
        //1、首先先读取文件夹
        $temp=scandir($date);
        //遍历文件夹
        foreach($temp as $v){
            $a=$date.'/'.$v;
             if($v=='.' || $v=='..'){//判断是否为系统隐藏的文件.和..  如果是则跳过否则就继续往下走,防止无限循环再这里。
                   continue;
               }
           if(is_dir($a)){//如果是文件夹则执行
           $data1[] = list_file($a);//因为是文件夹所以再次调用自己这个函数,把这个文件夹下的文件遍历出来
           }else{
              $data1[]=["imgpath"=>$a];  //加入到数组里准备返回(特别上面那个他是调用自身那么他也会返回多维数组出来)
           }
        }
       return $data1;
    }
function toOneArray($array)
{
    static $res_arr = [];
    foreach ($array as $v) {
        if (is_array($v)) {
            toOneArray($v);
        } else {
            $res_arr[] = $v;
        }
    }
    return $res_arr;
}
?>

2.引入压缩文件类zip.class.php,是phpMyadmin的压缩方法

<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
 * Zip file creation
 *
 * @package PhpMyAdmin
 */

/**
 * Zip file creation class.
 * Makes zip files.
 *
 * @access  public
 * @package PhpMyAdmin
 * @see     Official ZIP file format: http://www.pkware.com/support/zip-app-note
 */
class ZipFile
{
    /**
     * Whether to echo zip as it's built or return as string from -> file
     *
     * @var  boolean  $doWrite
     */
    var $doWrite      = false;

    /**
     * Array to store compressed data
     *
     * @var  array    $datasec
     */
    var $datasec      = array();

    /**
     * Central directory
     *
     * @var  array    $ctrl_dir
     */
    var $ctrl_dir     = array();

    /**
     * End of central directory record
     *
     * @var  string   $eof_ctrl_dir
     */
    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";

    /**
     * Last offset position
     *
     * @var  integer  $old_offset
     */
    var $old_offset   = 0;


    /**
     * Sets member variable this -> doWrite to true
     * - Should be called immediately after class instantiantion
     * - If set to true, then ZIP archive are echo'ed to STDOUT as each
     *   file is added via this -> addfile(), and central directories are
     *   echoed to STDOUT on final call to this -> file().  Also,
     *   this -> file() returns an empty string so it is safe to issue a
     *   "echo $zipfile;" command
     *
     * @access public
     *
     * @return void
     */
    function setDoWrite()
    {
        $this -> doWrite = true;
    } // end of the 'setDoWrite()' method

    /**
     * Converts an Unix timestamp to a four byte DOS date and time format (date
     * in high two bytes, time in low two bytes allowing magnitude comparison).
     *
     * @param integer $unixtime the current Unix timestamp
     *
     * @return integer the current date in a four byte DOS format
     *
     * @access private
     */
    function unix2DosTime($unixtime = 0)
    {
        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);

        if ($timearray['year'] < 1980) {
            $timearray['year']    = 1980;
            $timearray['mon']     = 1;
            $timearray['mday']    = 1;
            $timearray['hours']   = 0;
            $timearray['minutes'] = 0;
            $timearray['seconds'] = 0;
        } // end if

        return (($timearray['year'] - 1980) << 25)
            | ($timearray['mon'] << 21)
            | ($timearray['mday'] << 16)
            | ($timearray['hours'] << 11)
            | ($timearray['minutes'] << 5)
            | ($timearray['seconds'] >> 1);
    } // end of the 'unix2DosTime()' method


    /**
     * Adds "file" to archive
     *
     * @param string  $data file contents
     * @param string  $name name of the file in the archive (may contains the path)
     * @param integer $time the current timestamp
     *
     * @access public
     *
     * @return void
     */
    function addFile($data, $name, $time = 0)
    {
        $name     = str_replace('\\', '/', $name);

        $dtime    = substr("00000000" . dechex($this->unix2DosTime($time)), -8);
        $hexdtime = '\x' . $dtime[6] . $dtime[7]
                  . '\x' . $dtime[4] . $dtime[5]
                  . '\x' . $dtime[2] . $dtime[3]
                  . '\x' . $dtime[0] . $dtime[1];
        eval('$hexdtime = "' . $hexdtime . '";');

        $fr   = "\x50\x4b\x03\x04";
        $fr   .= "\x14\x00";            // ver needed to extract
        $fr   .= "\x00\x00";            // gen purpose bit flag
        $fr   .= "\x08\x00";            // compression method
        $fr   .= $hexdtime;             // last mod time and date

        // "local file header" segment
        $unc_len = strlen($data);
        $crc     = crc32($data);
        $zdata   = gzcompress($data);
        $zdata   = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
        $c_len   = strlen($zdata);
        $fr      .= pack('V', $crc);             // crc32
        $fr      .= pack('V', $c_len);           // compressed filesize
        $fr      .= pack('V', $unc_len);         // uncompressed filesize
        $fr      .= pack('v', strlen($name));    // length of filename
        $fr      .= pack('v', 0);                // extra field length
        $fr      .= $name;

        // "file data" segment
        $fr .= $zdata;

        // echo this entry on the fly, ...
        if ( $this -> doWrite) {
            echo $fr;
        } else {                     // ... OR add this entry to array
            $this -> datasec[] = $fr;
        }

        // now add to central directory record
        $cdrec = "\x50\x4b\x01\x02";
        $cdrec .= "\x00\x00";                // version made by
        $cdrec .= "\x14\x00";                // version needed to extract
        $cdrec .= "\x00\x00";                // gen purpose bit flag
        $cdrec .= "\x08\x00";                // compression method
        $cdrec .= $hexdtime;                 // last mod time & date
        $cdrec .= pack('V', $crc);           // crc32
        $cdrec .= pack('V', $c_len);         // compressed filesize
        $cdrec .= pack('V', $unc_len);       // uncompressed filesize
        $cdrec .= pack('v', strlen($name)); // length of filename
        $cdrec .= pack('v', 0);             // extra field length
        $cdrec .= pack('v', 0);             // file comment length
        $cdrec .= pack('v', 0);             // disk number start
        $cdrec .= pack('v', 0);             // internal file attributes
        $cdrec .= pack('V', 32);            // external file attributes
                                            // - 'archive' bit set

        $cdrec .= pack('V', $this -> old_offset); // relative offset of local header
        $this -> old_offset += strlen($fr);

        $cdrec .= $name;

        // optional extra field, file comment goes here
        // save to central directory
        $this -> ctrl_dir[] = $cdrec;
    } // end of the 'addFile()' method


    /**
     * Echo central dir if ->doWrite==true, else build string to return
     *
     * @return string  if ->doWrite {empty string} else the ZIP file contents
     *
     * @access public
     */
    function file()
    {
        $ctrldir = implode('', $this -> ctrl_dir);
        $header = $ctrldir .
            $this -> eof_ctrl_dir .
            pack('v', sizeof($this -> ctrl_dir)) . //total #of entries "on this disk"
            pack('v', sizeof($this -> ctrl_dir)) . //total #of entries overall
            pack('V', strlen($ctrldir)) .          //size of central dir
            pack('V', $this -> old_offset) .       //offset to start of central dir
            "\x00\x00";                            //.zip file comment length

        if ( $this -> doWrite ) { // Send central directory & end ctrl dir to STDOUT
            echo $header;
            return "";            // Return empty string
        } else {                  // Return entire ZIP archive as string
            $data = implode('', $this -> datasec);
            return $data . $header;
        }
    } // end of the 'file()' method

} // end of the 'ZipFile' class
?>
]]>
<![CDATA[PHP压缩和解压代码段]]> https://bk1314.com/43.html 2022-02-25T18:59:25+08:00 2022-02-25T18:59:25+08:00 飞鱼 http://www.typecho.org [scode type="green"]PHP文件 Zip 压缩[/scode]

<?php
/* creates a compressed zip file */
function create_zip($files = array(),$destination = '',$overwrite = false) {
 
    //if the zip file already exists and overwrite is false, return false
    if (file_exists($destination) && !$overwrite) {
        return false;
    }
 
    //vars
    $valid_files = array();
    //if files were passed in...
    if (is_array($files)) {
 
        //cycle through each file
        foreach ($files as $file) {
            //make sure the file exists
            if (file_exists($file)) {
                $valid_files[] = $file;
            }
        }
    }
 
    //if we have good files...
    if (count($valid_files)) {
        //create the archive
        $zip = new ZipArchive();
        if ($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
            return false;
        }
        //add the files
        foreach ($valid_files as $file) {
            $zip->addFile($file,$file);
        }
        //debug
        //echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
 
        //close the zip -- done!
        $zip->close();
 
        //check to make sure the file exists
        return file_exists($destination);
    } else {
        return false;
    }
}
 
/***** Example Usage ***/
$files = array('file1.jpg', 'file2.jpg', 'file3.gif');
create_zip($files, 'myzipfile.zip', true);
?>

[scode type="green"]PHP解压缩 Zip文件[/scode]

<?php
/**
 * @param $file - path to zip file
 * @parm $destination - destination directory for unzipped files
 */
function unzip_file($file, $destination) {
    // create object
    $zip = new ZipArchive() ;
    // open archive
    if ($zip->open($file) !== TRUE) {
        die ('Could not open archive');
    }
    // extract contents to destination directory
    $zip->extractTo($destination);
    // close archive
    $zip->close();
    echo 'Archive extracted to directory';
}
?>
]]>
<![CDATA[修改qcow2文件镜像和压缩的教程]]> https://bk1314.com/13.html 2022-02-23T17:09:00+08:00 2022-02-23T17:09:00+08:00 飞鱼 http://www.typecho.org 一、 修改镜像内容步骤

guestfish --rw -a qcow2
#镜像文件绝对路径 (例子:guestfish --rw -a /home/kvm/images/CentOS-7.8.2003-x64.qcow2)
进入后先执行run;
随后执行list-filesystems 查看分区信息;
以魔方centos7.8镜像为例,分区信息为 /dev/sda1: ext4 ,执行mount /dev/sda1 / 进行分区挂载;
接下来可以修改任意文件,例如操作ssh登录提示 vi /etc/motd
执行exit 退出
目前发现一个重点问题:在挂载xfs分区时会出现分区格式不兼容的情况。例如CentOS8官方的云镜像,默认是xfs分区格式,CentOS8与CentOS7的xfs格式不相同,会出现兼容问题 运行不成功或挂载不成功,请注意区分。

1.另外一种挂载到宿主机目录方式

guestmount -a qcow2 -m 分区  /宿主机目录
#镜像文件绝对路径 (例子:guestmount -a /home/kvm/images/CentOS-7.8.2003-x64.qcow2 -m /dev/sda1  /mnt)
#卸载命令
guestunmount /mnt

二、 清除磁盘空洞

virt-sparsify -x 原qcow2镜像文件路径 --convert qcow2 新qcow2镜像文件路径
(例子:virt-sparsify -x /home/kvm/images/CentOS-7.8.2003-x64.qcow2 --convert qcow2 /home/kvm/images/tmp.qcow2)

如果出错提示tmp不足可以参考下面这个文章

[post cid="134" /]

操作完成后,可先进行重装验证是否可以正常引导启动,最后修改新qcow2镜像文件名称

三、对qcow2镜像文件进行打包压缩

qemu-img convert -c -O qcow2 需要压缩的镜像文件路径 压缩后的镜像文件路径
(例子:qemu-img convert -c -O qcow2 /home/kvm/images/tmp.qcow2 /home/kvm/images/CentOS-7.8.2003-x64.qcow2)
]]>