| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 | <?phpnamespace App\Service;use App\Exports\TableHeadExport;use App\Import\Import;use App\Import\ImportAll;use App\Model\BasicType;use App\Model\Customer;use App\Model\CustomerInfo;use App\Model\Depart;use App\Model\Employee;use App\Model\Product;use App\Model\ProductCategory;use App\Model\ProductPriceDetail;use App\Model\SalesOrder;use App\Model\SalesOrderInfo;use App\Model\SalesOrderProductInfo;use Illuminate\Support\Facades\DB;use Illuminate\Support\Facades\Log;use Illuminate\Support\Facades\Storage;use Maatwebsite\Excel\Facades\Excel;use PhpOffice\PhpSpreadsheet\IOFactory;use PhpOffice\PhpSpreadsheet\Shared\Date;class ImportService extends Service{    const tmp_dir = 'upload_occ';    const string = '/api/getFile/';    const file_one = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';    const file_two = 'application/zip';    const file_three = 'application/octet-stream';    const file_array = [        self::file_one,        self::file_two,        self::file_three,    ];    //文件类型    const FILE_TYPE = [        'txt',        'jpg',        'png',        'gif',        'jpeg',        'zip',        'rar',        'xlsx',        'xls'    ];    //导入入口    public function import($data){//        //不超时//        ini_set('max_execution_time', 0);//        //内存设置//        ini_set('memory_limit', -1);//        $reader = IOFactory::createReader('Xlsx');//        $reader->setReadDataOnly(true); // 只读取有数据的单元格//        $spreadsheet = $reader->load($data['file']);//        dd($spreadsheet);//        // 创建一个Reader对象//        $reader = IOFactory::createReader('Xlsx'); // 根据你的文件格式选择合适的reader////// 加载Excel文件//        $spreadsheet = $reader->load($data['file']);////// 获取第一个工作表//        $worksheet = $spreadsheet->getActiveSheet();////// 获取总行数//        $totalRows = $worksheet->getHighestRow();dd($totalRows);        if(empty($data['file'])) return [false,'导入文件不能为空'];        try {           $this->uploadFile($data['file']);        }catch (\Throwable $exception) {            return [false, $exception->getMessage() . ' (Code: ' . $exception->getCode() . ', Line: ' . $exception->getLine() . ')'];        }        return [true, ''];    }    public function uploadFile($file){        if(empty($file)) return [false, '请上传文件'];        // 获取文件相关信息        $ext = $file->getClientOriginalExtension();     // 扩展名        $realPath = $file->getRealPath();   //临时文件的绝对路径        $ext = strtolower($ext);        if (! in_array($ext, self::FILE_TYPE)){            $str = '文件格式为:';            foreach (self::FILE_TYPE as $value){                $str.= $value . ' ' ;            }            return [false, $str];        }        $date = date("Y-m-d");        //文件名        $file_name = date("Ymd").time().rand(1000,9999);        $filename =  $file_name.'.' . $ext;        $dir = self::tmp_dir . '/' . $date . '/' . $filename;        Storage::disk('public')->put($dir, file_get_contents($realPath));        return [true, self::string . $filename];    }    public function getFileData($data){        if(empty($data['url'])) return [false, '文件路径不能为空'];        try {            // 发送 HTTP 请求获取文件内容            $response = file_get_contents($data['url']);        } catch (\Throwable $exception) {            if (str_contains($exception->getMessage(), 'failed to open stream')) return [false, "URL链接已失效"];            return [false, $exception->getMessage()];        }        if ($response === false) return [false, '文件获取失败'];        // 创建一个临时文件资源        $tempFile = tempnam(sys_get_temp_dir(), 'download_');        file_put_contents($tempFile, $response);        // 判断文件类型        $fileInfo = finfo_open(FILEINFO_MIME_TYPE);        $mimeType = finfo_file($fileInfo, $tempFile);        finfo_close($fileInfo);        if(! in_array($mimeType, self::file_array)) return [false, '文件类型目前暂时支持zip|xlsx'];        // 根据文件类型处理        if ($mimeType === self::file_one) {            // 处理单个XLSX文件            list($status,$result) = $this->processXlsxFile($tempFile);            if (! $status) return [false, $result];            return [true, ['content' => [$result], 'type' => 'xlsx']];        } elseif ($mimeType === self::file_two) {            // 创建 ZipArchive 对象            $zip = new \ZipArchive();            if ($zip->open($tempFile) !== true) {                // 删除临时文件                unlink($tempFile);                return [false, '无法打开ZIP文件'];            }            // 初始化一个数组来存储所有XLSX文件的数据            $allFilesData = [];            // 遍历ZIP文件中的每一个文件            for ($i = 0; $i < $zip->numFiles; $i++) {                $filename = $zip->getNameIndex($i);                if (pathinfo($filename, PATHINFO_EXTENSION) === 'xlsx') {// 检查是否为XLSX文件                    // 提取文件到临时位置//                    $tempXlsxFile = tempnam(sys_get_temp_dir(), 'xlsx_');                    $tempDir = sys_get_temp_dir() . '/extracted_' . uniqid();                    mkdir($tempDir, 0777, true);                    // 提取文件到临时位置                    if ($zip->extractTo($tempDir, [$filename]) === false) {                        $this->deleteDirectory($tempDir);//                        Log::channel('apiLog')->info('断点1', ["message" => $filename]);                        continue; // 跳过提取失败的文件                    }                    // 递归查找提取的XLSX文件                    $extractedFile = $this->findXlsxFile($tempDir, basename($filename));                    // 获取提取出的文件的实际路径//                    $extractedFile = sys_get_temp_dir() . '/' . basename($filename);                    // 检查临时文件是否存在                    if (! file_exists($extractedFile)){                        $this->deleteDirectory($tempDir);//                        Log::channel('apiLog')->info('断点2', ["message" => $extractedFile]);                        continue;                    }                    // 重命名提取出的文件为临时文件                    $tempXlsxFile = tempnam(sys_get_temp_dir(), 'xlsx_');                    if (! rename($extractedFile, $tempXlsxFile)) {                        $this->deleteDirectory($tempDir);//                        Log::channel('apiLog')->info('断点5', ["message" => "重命名文件失败: " . $extractedFile]);                        continue;                    }//                    // 重命名提取出的文件为临时文件//                    if (! rename($extractedFile, $tempXlsxFile)) {//                        Log::channel('apiLog')->info('断点3', ["message" => $tempXlsxFile]);//                        continue;//                    }                    list($status,$xlsxData) = $this->processXlsxFile($tempXlsxFile);                    if (! $status) {                        $this->deleteDirectory($tempDir);                        return [false, $xlsxData];                    }                    // 将当前XLSX文件的数据添加到所有文件的数据数组中                    $xlsxData['filename'] = $filename;                    $allFilesData[] = $xlsxData;                    $this->deleteDirectory($tempDir);                }            }            // 关闭 ZIP 文件            $zip->close();            // 删除临时 ZIP 文件            unlink($tempFile);            return [true, ["content" => $allFilesData, 'type' => 'zip']];        } elseif ($mimeType === self::file_three){            // 处理单个XLSX文件            list($status,$result) = $this->processXlsxFile($tempFile);            if (! $status) return [false, $result];            return [true, ['content' => [$result], 'type' => 'xlsx']];        }else {            // 删除临时文件            unlink($tempFile);            return [false, '不支持的文件类型'];        }    }    // 递归删除目录及其所有内容    function deleteDirectory($dir) {        if (! is_dir($dir)) {            return;        }        $files = array_diff(scandir($dir), array('.', '..'));        foreach ($files as $file) {            $path = $dir . DIRECTORY_SEPARATOR . $file;            if (is_dir($path)) {                $this->deleteDirectory($path);            } else {                unlink($path);            }        }        rmdir($dir);    }    // 递归查找XLSX文件    function findXlsxFile($dir, $filename) {        $iterator = new \RecursiveDirectoryIterator($dir);        $files = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);        foreach ($files as $file) {            if ($file->isFile() && $file->getFilename() === $filename) {                return $file->getPathname();            }        }        return null;    }    // 定义一个函数来处理XLSX文件    function processXlsxFile($filename) {        try {            if (is_file($filename)) {                chmod($filename, 0777);            }            // 使用 PhpSpreadsheet 读取文件            $reader = IOFactory::createReader('Xlsx');            $spreadsheet = $reader->load($filename);            // 初始化一个数组来存储所有工作表的数据            $allSheetData = [];            // 遍历所有工作表            foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {                $sheetData = [];                foreach ($worksheet->getRowIterator() as $row) {                    $cellIterator = $row->getCellIterator();                    $cellIterator->setIterateOnlyExistingCells(false); // 循环所有单元格,即使它未设置                    $rowData = [];                    foreach ($cellIterator as $cell) {                        // 判断单元格是否为日期                        if (Date::isDateTime($cell)) {                            // 将日期转换为 Y-m-d 格式                            $formattedDate = Date::excelToDateTimeObject($cell->getValue())->format('Y-m-d');                            $rowData[] = $formattedDate;                        } else {                            // 获取单元格的格式化值                            $rowData[] = $cell->getFormattedValue();                        }//                        $cellData = $cell->getFormattedValue();//                        if(! empty($cellData)) $cellData = $this->convertToYMD($cellData);//                        $rowData[] = $cellData;                    }                    $sheetData[] = $rowData;                }                // 将当前工作表的数据添加到总数据数组中                $allSheetData[$worksheet->getTitle()] = $sheetData;            }            // 删除临时文件            unlink($filename);            return [true, $allSheetData];        } catch (\Throwable $e) {            // 删除临时文件            unlink($filename);            return [false, "处理文件 {$filename} 时发生错误: " . $e->getMessage()];        }    }    public function convertToYMD($date)    {        // 定义一些常见的日期格式        $formats = [            'Y-m-d', // 2023-10-17            'Y/m/d', // 2023/10/17            'd-m-Y', // 17-10-2023            'd/m/Y', // 17/10/2023            'm-d-Y', // 10-17-2023            'm/d/Y', // 10/17/2023//            'Ymd',   // 20231017//            'dmy',   // 17102023//            'dmY',   // 17102023//            'dMY',   // 17102023//            'Ymd',   // 20231017//            'Ydm',   // 20231017//            'YDM',   // 20231017//            'YDm',   // 20231017        ];        // 尝试使用每个格式解析日期        foreach ($formats as $format) {            $dateTime = \DateTime::createFromFormat($format, $date);            if ($dateTime && $dateTime->format($format) === $date) {                // 成功解析日期,返回转换后的 Y-m-d 格式                return $dateTime->format('Y-m-d');            }        }        // 如果所有格式都未能解析日期,则返回原字符串        return $date;    }    public function getFileData1($data){        if(empty($data['url'])) return [false, '文件路径不能为空'];        try{            // 发送 HTTP 请求获取文件内容            $response = file_get_contents($data['url']);        }catch (\Throwable $exception){            return [false, $exception->getMessage()];        }        if ($response === false) return [false, '文件获取失败'];        // 创建一个临时文件资源        $tempFile = tempnam(sys_get_temp_dir(), 'xlsx_');        file_put_contents($tempFile, $response);        // 使用 phpspreadsheet 读取文件        try {            // 创建一个 Xlsx 读取器            $reader = IOFactory::createReader('Xlsx');            // 加载临时文件            $spreadsheet = $reader->load($tempFile);            // 初始化一个数组来存储所有工作表的数据            $allSheetData = [];            // 遍历所有工作表            foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {                $sheetData = [];                foreach ($worksheet->getRowIterator() as $row) {                    $cellIterator = $row->getCellIterator();                    $cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set                    $rowData = [];                    foreach ($cellIterator as $cell) {                        $rowData[] = $cell->getValue();                    }                    $sheetData[] = $rowData;                }                // 将当前工作表的数据添加到总数据数组中                $allSheetData[$worksheet->getTitle()] = $sheetData;            }            // 删除临时文件            unlink($tempFile);        } catch (\Exception $e) {            // 删除临时文件            unlink($tempFile);            return [false, $e->getMessage()];        }        return [true , $allSheetData];    }}
 |