<?php

namespace App\Module\Goods;


use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class DealZip
{
    /**
     * 本次上传文件存放的随机文件夹名字
     * @var
     */
    public $uploadName;
    /**
     * 本次导出,文件生成存放的随机文件夹名称
     * @var
     */
    public $exportName;

    /**
     * 上传文件
     * @param Request $request
     * @param $savePath
     * @return array
     */
    public function uploadFile($request, $savePath)
    {
        $this->uploadName = time() . rand(1, 10000);
        $savePath = $savePath . $this->uploadName;
        if (!$request->hasFile('file')) {
            return ['status' => 0, 'msg' => '缺少文件'];
        }
        $file = $request->file('file');
        if (!$file->isValid()) {
            return ['status' => 0, 'msg' => '上传出错'];
        }
        $extension = $file->getClientOriginalExtension();
        if ($extension != 'zip') {
            return ['status' => 0, 'msg' => '上传格式错误'];
        }
        $saveName = 'upload.' . $extension;
        $target = $file->move($savePath, $saveName);
        if ($target) {
            return ['status' => 1, 'msg' => '上传成功'];
        } else {
            return ['status' => 0, 'msg' => '上传失败'];
        }
    }

    /**
     * 解压(PHP5.6,7.2测试线上通过)
     * @param $zipName (需要解压的文件路径)
     * @param $dir (解压基础目录)
     * @return bool
     */
    function extractZipToFile($zipName, $dir)
    {
        $zip = new \ZipArchive;
        if ($zip->open($this->transcoding($zipName)) === TRUE) {
            if (!is_dir($this->transcoding($dir))) mkdir($this->transcoding($dir), 0775, true);
            $num = $zip->numFiles;
            //先分成文件夹数组和文件数组,防止后面报错
            //根据文件名称长度从小到大排序,因为不同的压缩软件压缩的压缩包结构不同,编码不同,文件排序不同。
            $dirArr = [];
            $fileArr = [];
            for ($i = 0; $i < $num; $i++) {
                $statInfo = $zip->statIndex($i);
//                dump($statInfo);
                $item = [
                    'statInfo' => $statInfo,
                    'key' => $i,
                ];
                if ($statInfo['crc'] == 0) {
                    $dirArr[$statInfo['name']] = $item;
                } else {
                    $fileArr[$statInfo['name']] = $item;
                }
            }
            ksort($dirArr, SORT_STRING);
            ksort($fileArr, SORT_STRING);
            $create = array_merge($dirArr, $fileArr);
//            var_dump($dirArr);
//            var_dump($create);
//            die();
            //解压文件
            foreach ($create as $value) {
                $statInfo = $value['statInfo'];
                $filename = $this->transcoding($statInfo['name']);
                if ($statInfo['crc'] == 0) {
                    if (!is_dir($this->transcoding($dir . '/' . substr($filename, 0, -1)))) mkdir($this->transcoding($dir . '/' . substr($filename, 0, -1)), 0777, true);
                } else {
                    copy('zip://' . $zipName . '#' . $statInfo['name'], $this->transcoding($dir . '/' . $filename));
                }
            }
            $name = $zip->getNameIndex(0);
            $name = $this->transcoding($name);
            $name = substr($name, 0, -1);
            $zip->close();
            @rename($dir . '/' . $name, $dir . '/extract'); //重新命名,方便取数据
            //修改文件夹名字的问题
            if ($handle = @opendir($dir)) {
                while (false !== ($entry = readdir($handle))) {
                    if ($entry == "." || $entry == "..") {
                        continue;
                    }
                    if (is_dir($dir . '/' . $entry)) {
                        @rename($dir . '/' . $entry, $dir . '/extract'); //重新命名,方便取数据
                    }
                }
                closedir($handle);
            }
            //修改文件夹内的名字
            $path = $dir . '/extract';
            if ($handle = @opendir($path)) {
                while (false !== ($entry = readdir($handle))) {
                    if ($entry == "." || $entry == "..") {
                        continue;
                    }
                    if (is_dir($path . '/' . $entry)) {
                        @rename($path . '/' . $entry, $path . '/pic'); //重新命名,方便取数据
                    } else {
                        $extension = explode('.', $entry)[1];
                        @rename($path . '/' . $entry, $path . '/goods.' . $extension); //重新命名,方便取数据
                    }
                }
                closedir($handle);
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 转换字符编码
     * @param $fileName
     * @return false|string
     */
    function transcoding($fileName)
    {
        $encoding = mb_detect_encoding($fileName, ['UTF-8', 'GBK', 'BIG5', 'CP936']);
        if (DIRECTORY_SEPARATOR == '/') {    //linux
//            $filename = iconv($encoding, 'UTF-8', $fileName);
            $filename = mb_convert_encoding($fileName, 'UTF-8', $encoding);
        } else {  //win
//            $filename = iconv($encoding, 'GBK', $fileName);
            $filename = mb_convert_encoding($fileName, 'GBK', $encoding);
        }
        return $filename;
    }

    /**
     * 删除目录及其目录下的所有文件和目录
     * @param $path (要删除的目录路径)
     * @return void
     */
    public function clearDirAndFiles($path)
    {
        if ($handle = @opendir($path)) {
            while (false !== ($entry = readdir($handle))) {
                if ($entry == "." || $entry == "..") {
                    continue;
                }
                if (is_dir($path_child = $path . '/' . $entry)) {
                    $this->clearDirAndFiles($path_child);
                    @rmdir($path_child);
                } else {
                    @unlink($path_child);
                }
            }
            closedir($handle);
        }
        @rmdir($path);
    }

    /**
     * 压缩文件
     *  path下的目录结构:
     *      build(生成的图片和Excel文件)
     *      pic
     *          pic-1.png
     *          ...
     *      goods.xlsx
     *      goods.zip(该函数最后生成的压缩包)
     * @param $path
     */
    public function zipFiles($path)
    {
        $zip = new \ZipArchive();
        @unlink($path . '/goods.zip'); //删除原来的
        if ($zip->open($path . '/goods.zip', \ZIPARCHIVE::CREATE) === true) {
            $zip->addEmptyDir('压缩包');
            $zip->addEmptyDir('压缩包/图片');
            $filename = $path . '/build/goods.xlsx';
            $content = file_get_contents($filename);
            $zip->addFromString('压缩包/商品列表.xlsx', $content);
            //添加图片
            if ($handle = opendir($path . '/build/pic')) {
                // 添加目录中的所有文件
                while (false !== ($entry = readdir($handle))) {
                    if ($entry != "." && $entry != ".." && !is_dir($entry)) {
                        $zip->addFile($path . '/build/pic/' . $entry, '压缩包/图片/' . $entry);
                    }
                }
                closedir($handle);
            }
            $zip->close();
        }
    }

    /**
     * 规格组合
     * @param $arr (包含所有规格的二维数组)
     * @param string $str
     * @return mixed
     */
    public function combine($arr, $str = ';')
    {
        $result = array_reduce($arr, function ($v, $m) use ($str) {
            $temp = [];
            foreach ($v as $vv) {
                foreach ($m as $mm) {
                    if (empty($vv)) {
                        $temp[] = $mm;
                    } else {
                        $temp[] = $vv . $str . $mm;
                    }
                }
            }
            return $temp;
        }, ['']);
        return $result;
    }

    /**
     * 生成Excel表头字符['A','B','C','D'...]
     * @param $number
     * @return array
     */
    public function generateExcelHead($number)
    {
        $num = $number;
        $begin = 'A'; //从A开始
        $jj = 0;
        $nn = 0;
        $aLetter = [];
        // char_list [A...Z];
        for ($sii = 0; $sii < 26; $sii++) {
            $char = chr(65 + $sii);
            $char_list[$sii] = $char;
        }

        for ($i = 0; $i <= $num; $i++) {
            $beginstr = ord($begin); //65
            $cel = chr($beginstr + $i);
            if ($beginstr + $i <= 90) {
                //列数小于26,Z字母的ASCII是90
                $aLetter[] = $cel;
            }

            if ($beginstr + $i > 90) {// 大于Z,
                $startnum = '65'; // A
                $kkk = ((int)$jj / 26); //0
                $cel = chr($startnum + $nn); //A
                $aLetter[] = $char_list[$kkk] . $cel;
                $nn++;
                if ($nn > 25) {
                    $nn = 0;
                }
                $jj++;
            }
        }
        return $aLetter;
    }

    /**
     *  验证文件的正确性
     * @param $path
     * @param $table
     * @return array
     * @throws \PHPExcel_Exception
     * @throws \PHPExcel_Reader_Exception
     */
    public function verifyFile($path,$table)
    {
        //验证商品列表的数据
        $verifyExcel = $this->verifyExcel($path,$table);
        if ($verifyExcel['status'] == 0) {
            return $verifyExcel;
        }
        $data['lists'] = $verifyExcel['data']['lists'];
        //验证图片
        $verifyPic = $this->verifyPic($path, $data['lists'],$table);
        if ($verifyPic['status'] == 0) {
            return $verifyPic;
        }
        $data['picArray'] = $verifyPic['data']['picArray'];
        return ['status' => 1, 'msg' => '验证通过', 'data' => $data];
    }

    /**
     *  验证excel文件
     * @param $path
     * @return array
     * @throws \PHPExcel_Exception
     * @throws \PHPExcel_Reader_Exception
     */
    private function verifyExcel($path,$table)
    {
        $excelName = ''; //文件名
        $ext = 'xlsx'; //扩展名
        if ($handle = @opendir($path)) {
            while (false !== ($entry = readdir($handle))) {
                if ($entry != "." && $entry != "..") {
                    if (substr_count($entry, 'goods') > 0) {
                        $pathInfo = pathinfo($path . '/' . $entry);
                        $excelName = $entry;
                        $ext = strtolower($pathInfo['extension']);
                    }
                }
            }
            closedir($handle);
        }
        if (empty($excelName) || ($ext != 'xlsx' && $ext != 'xls')) {
            return ['status' => 0, 'msg' => '导入失败,Excel文件不存在或者名称不正确'];
        }
        $file_path = $path . '/' . $excelName;
        //读取数据信息,验证是否正确
        $objReader = \PHPExcel_IOFactory::createReader('Excel2007');
        $objPHPExcel = $objReader->load($file_path, 'utf-8');

        $sheet = $objPHPExcel->getSheet(0);
        $highestRow = $sheet->getHighestRow();//取得总行数
        $highestColumn = $sheet->getHighestColumn(); //取得总列数
        $data = [];
        for ($i = 1; $i <= $highestRow; $i++) {
            $rowData = [];
            for ($k = 'A'; $k <= $highestColumn; $k++) {
                $rowData[] = (string)trim($objPHPExcel->getActiveSheet()->getCell("$k$i")->getValue());
            }
            array_push($data, $rowData);
        }
        $headerInfo = $data[0];
        unset($data[0]);
        if ($table == 'woo_retail_goods'){
            $heads = ['商品条码','商品名称','参与优惠','零售价','会员价','规格条码'];
            $return = $this->verifyHeaders($heads,$headerInfo);
        }elseif ($table == 'woo_admin_goods'){ //蜗蜗商品库
            $heads = ['商品条码','商品名称','库存单位','单规格','建议零售价','规格条码','规格'];
            $headerInfo = array_slice($headerInfo,0,7);
            $return =  $this->verifyHeaders($heads,$headerInfo);
        }elseif ($table == 'woo_takeout_goods'){ //外卖商品库
            $heads = ['商品条码', '商品名称', '商品分类', '参与优惠', '打包费', '商品属性','零售价', '会员价', '规格条码', '库存', '设库存'];
            $headerInfo = array_slice($headerInfo,0,7);
            $return =  $this->verifyHeaders($heads,$headerInfo);
        }else{
            $heads = ['商品条码','商品名称','商品分类','库存单位','参与优惠','单规格','建议零售价','规格条码','规格'];
            $headerInfo = array_slice($headerInfo,0,9);
            $return =  $this->verifyHeaders($heads,$headerInfo);
        }
        if ($return['status'] == 1){
            $return['data']= ['lists' => $data];
        }
        return $return;
    }

    /**
     * 验证表头
     * @param $heads
     * @param $headerInfo
     * @return array
     */
    public function verifyHeaders($heads,$headerInfo)
    {
        $return  = ['status'=>0,'msg'=>'模板不符合规范'];
        foreach ($headerInfo as $key=>&$head){
            $head = str_replace(array("\r\n", "\r", "\n","\t"," "), "", $head);
            if ($head != $heads[$key]){
                return $return;
            }
        }
        return ['status'=>1,'msg'=>'验证通过'];
    }


    /**
     * 过滤掉一列全部为空的数组
     * @param $data
     * @return mixed
     */
    public function delEmptyColumn($data)
    {
        $max = 0;
        foreach ($data as $key => $value) {
            $max = max($max, count($value));
        }
        $deleteIndex = [];
        for ($j = 0; $j < $max; $j++) {
            $result = array_filter(array_column($data, $j));
            if (empty($result)) {
                array_push($deleteIndex, $j);
            }
        }
        array_walk($data, function (&$value) use ($deleteIndex) {
            $value = array_slice($value, 0, $deleteIndex[0]);
        });
        return $data;
    }

    /**
     * 验证图片(规则是:只要数据库中没有商品条形码或者导入的商品Excel表中没有对应的商品码,就验证失败)
     * @param $path
     * @param $lists
     * @param $table
     * @return array
     */
    public function verifyPic($path, $lists,$table)
    {
        $picPath = $path . '/pic';
        $barCodeArr = []; //图片中的商家条形码数组
        $picArray = []; //图片数组,用于导入商家的图片
        //判断图片文件夹是否为空
        if ($handle = @opendir($picPath)) {
            while (false !== ($entry = readdir($handle))) {
                if ($entry != "." && $entry != "..") {
                    $pathInfo = pathinfo($picPath . '/' . $entry);
                    $barCode = explode('-', $pathInfo['filename'])[0];
                    if (!in_array($barCode, $barCodeArr)) {
                        $barCodeArr[] = $barCode;
                    }
                    $picArray[$barCode][] = $pathInfo['basename'];
                }
            }
            closedir($handle);
        }
        //验证
        $code = array_filter(array_column($lists, 0)); //导入的Excel表中的商家条形码
        //根据图片的code码查询出来的商品code数组
        $goodsCodeArr = DB::table($table)->whereIn('code', $barCodeArr)->pluck('code')->toArray();
        $isVerify = true;
        foreach ($barCodeArr as $v) {
            if (!in_array($v, $code) && !in_array($v, $goodsCodeArr)) {
                $isVerify = false;
                break;
            }
        }
        //返回
        if ($isVerify) {
            return ['status' => 1, 'msg' => '图片验证成功', 'data' => ['picArray' => $picArray]];
        } else {
            return ['status' => 0, 'msg' => '模板不符合规范'];
        }
    }

    /**
     * 生成文件(包括Excel和图片)
     * @param $data (用于生成Excel的数据)
     * @return array
     * @throws \PHPExcel_Exception
     */
    public function buildFiles($data)
    {
        $list = $data['returnLists'];
        if (!is_dir($data['path'] . '/pic')) {
            mkdir($data['path'] . '/pic', 0775, true);
        }
        /******复制图片******/
        if (!empty($data['picLists'])) {
            foreach ($data['picLists'] as $goodCode=>$goodPics){
                foreach ($goodPics as $pic) {
                    if (file_exists($data['picPath'].$pic)){
                        $picContent = file_get_contents($data['picPath'].$pic);
                        file_put_contents($data['path'] . '/pic/'.$goodCode.'-'.$pic,$picContent);
                    }
                }
            }
        }
        /******生成Excel文件******/
        $headers = $this->generateExcelHead($data['max']-1);
        $file = $data['path'] . 'goods.xlsx';
        $PHPExcel = new \PHPExcel();
        $PHPExcel->getDefaultStyle()->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
        $PHPExcel->getDefaultStyle()->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
        $PHPSheet = $PHPExcel->getActiveSheet();
        //设置单元格边框
        $styleThinBlackBorderOutline = array(
            'borders' => array (
                'allborders' => array (                               //allborders  表示全部线框
                    'style' => \PHPExcel_Style_Border::BORDER_THIN,   //设置border样式
                    'color' => array ('argb' => '000000'),          //设置border颜色
                ),
            ),
        );
        /***设置表格值***/
        foreach ($headers as $k => $header) {
            $PHPSheet->getColumnDimension($header)->setWidth(16);
            $PHPSheet->setCellValue($header . '1', $data['heads'][$k])->getStyle($header . '1')->applyFromArray($styleThinBlackBorderOutline);
            foreach ($list as $key => $row) {
                $PHPSheet->setCellValueExplicit($header . ($key + 2), $row[$k],\PHPExcel_Cell_DataType::TYPE_STRING)->getStyle($header . ($key + 2))->applyFromArray($styleThinBlackBorderOutline)->getNumberFormat()->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
            }
        }
        /***设置行高***/
        $PHPSheet->getRowDimension(1)->setRowHeight(26); //设置表头行高
        for ($i = 0; $i < count($list); $i++) { //设置数据体行高
            $PHPSheet->getRowDimension($i + 2)->setRowHeight(26);
        }
        $PHPSheet->getDefaultRowDimension()->setRowHeight(26); //设置默认行高
        /******保存Excel文件******/
        $PHPWriter = \PHPExcel_IOFactory::createWriter($PHPExcel, "Excel2007");//告诉浏览器数据excel2007文件
        $PHPWriter->save($file);

        if (is_file($file)) {
            return ['status' => 1, 'msg' => '创建文件成功'];
        } else {
            return ['status' => 0, 'msg' => '创建文件失败'];
        }
    }


}

results matching ""

    No results matching ""