先生成Excel模板,然后导入Excel数据到mysql,每条数据对应图片上传到阿里云
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: Administrator 5 * Date: 2018/9/27 6 * Time: 13:57 7 */ 8 9 namespace site\admin\model; 10 11 use PhpOffice\PhpSpreadsheet\Spreadsheet; 12 use PhpOffice\PhpSpreadsheet\Writer\Xlsx; 13 use system\library\AliYunOSS; 14 use system\library\Unzip; 15 16 class ProductBatchModel extends \site\admin\component\Model 17 { 18 19 public function add($data){ 20 21 if (!$this->_validate($data, 'add')) { 22 return false; 23 } 24 25 $languageModel = new LanguageModel(); 26 $categoryModel = new CategoryModel(); 27 $productModel = new ProductModel(); 28 $urlAliasModel = new UrlAliasModel(); 29 30 if(substr(strrchr($data['excel_file'], '.'), 1)<>'xlsx'){ 31 $this->addError('excel_file', '请上传xlsx格式的Excel文件'); 32 return false; 33 } 34 35 $arr_file = explode('com/', $data['excel_file']); 36 37 $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx'); 38 $reader->setReadDataOnly(TRUE); 39 $spreadsheet = $reader->load(DIR_UPLOAD.$arr_file[1]); //载入excel表格 40 41 $worksheet = $spreadsheet->getActiveSheet(); 42 $highestRow = $worksheet->getHighestRow(); // 总行数 43 $highestColumn = $worksheet->getHighestColumn(); // 总列数 44 $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); // e.g. 5 45 46 $lines = $highestRow - 1; 47 if ($lines <= 0) { 48 $this->addError('Excel', 'Excel表格中没有数据'); 49 return false; 50 } 51 52 $enableRow = array(); 53 $arr_url = array(); 54 55 for ($row = 2; $row <= $highestRow; ++$row) { 56 57 /******************************验证产品型号***********************************/ 58 59 $model_no = $worksheet->getCellByColumnAndRow(1, $row)->getValue(); 60 if(empty($model_no)){ 61 $this->addError('model_no'.$row, '第'.$row.'行产品型号为空'); 62 }else{ 63 $if_exist = $productModel->getProductByModel($model_no); 64 if(empty($if_exist)){ 65 $enableRow[] = $row; //新增该行 66 } 67 } 68 69 70 /******************************验证产品分类***********************************/ 71 72 $category_name = $worksheet->getCellByColumnAndRow(2, $row)->getValue(); 73 if(empty($category_name)){ 74 $this->addError('category_name'.$row, '第'.$row.'行分类名为空'); 75 }else{ 76 $category = $categoryModel->getCategoryIdByName($category_name); 77 if(empty($category)){ 78 $this->addError('category_name'.$row, '第'.$row.'行分类名不存在'); 79 } 80 } 81 82 83 $sort_order = $worksheet->getCellByColumnAndRow(3, $row)->getValue(); 84 if(empty($sort_order) || !is_numeric($sort_order)){ 85 $this->addError('sort_order'.$row, '第'.$row.'行排序错误'); 86 } 87 88 $status = $worksheet->getCellByColumnAndRow(4, $row)->getValue(); 89 if(empty($status) || !is_numeric($status)){ 90 $this->addError('status'.$row, '第'.$row.'行状态错误'); 91 } 92 93 /******************************验证语言***********************************/ 94 95 $language_name = $worksheet->getCellByColumnAndRow(5, $row)->getValue(); 96 if(empty($language_name)){ 97 $this->addError('language_name'.$row, '第'.$row.'行语言为空'); 98 }else{ 99 $languages = $languageModel->getSysLanguageByName($language_name); 100 if(empty($languages)){ 101 $this->addError('languages'.$row, '第'.$row.'行语言不存在'); 102 } 103 } 104 105 106 $name = $worksheet->getCellByColumnAndRow(6, $row)->getValue(); 107 if(empty($name)){ 108 $this->addError('name'.$row, '第'.$row.'行名称为空'); 109 } 110 111 $keywords = $worksheet->getCellByColumnAndRow(7, $row)->getValue(); 112 if(empty($keywords)){ 113 $this->addError('keywords'.$row, '第'.$row.'行关键词为空'); 114 } 115 116 $url = $worksheet->getCellByColumnAndRow(10, $row)->getValue(); 117 if(!empty($url)){ 118 if(in_array($url, $arr_url)){ 119 $this->addError('url'.$row, '第'.$row.'行网址重复出现'); 120 }else{ 121 $arr_url[] = $url; 122 } 123 } 124 125 } 126 127 if($this->hasErrors()){ 128 return false; 129 } 130 131 //组装数组 132 $enableData = array(); 133 foreach ($enableRow as $key => $row) { 134 135 $model_no = $worksheet->getCellByColumnAndRow(1, $row)->getValue(); 136 137 //获取分类ID 138 $category_name = $worksheet->getCellByColumnAndRow(2, $row)->getValue(); 139 $category = $categoryModel->getCategoryIdByName($category_name); 140 $category_id = $category['category_id']; 141 142 $sort_order = $worksheet->getCellByColumnAndRow(3, $row)->getValue(); 143 $status = $worksheet->getCellByColumnAndRow(4, $row)->getValue(); 144 145 //获取语言ID 146 $language_name = $worksheet->getCellByColumnAndRow(5, $row)->getValue(); 147 $languages = $languageModel->getSysLanguageByName($language_name); 148 $language_id = $languages['language_id']; 149 150 $name = $worksheet->getCellByColumnAndRow(6, $row)->getValue(); 151 $keywords = $worksheet->getCellByColumnAndRow(7, $row)->getValue(); 152 $abstract = $worksheet->getCellByColumnAndRow(8, $row)->getValue(); 153 $description = $worksheet->getCellByColumnAndRow(9, $row)->getValue(); 154 $url = $worksheet->getCellByColumnAndRow(10, $row)->getValue(); 155 $meta_title = $worksheet->getCellByColumnAndRow(11, $row)->getValue(); 156 $meta_keyword = $worksheet->getCellByColumnAndRow(12, $row)->getValue(); 157 $meta_description = $worksheet->getCellByColumnAndRow(13, $row)->getValue(); 158 159 if(!isset($enableData[$model_no])){ 160 $enableData[$model_no] = array( 161 'product_type_id'=>'', 162 'model_no'=>$model_no, 163 'sort_order'=>$sort_order, 164 'status'=>$status, 165 'category'=>array($category_id), 166 'trade'=>'', 167 'producttradeinfo'=>array() 168 ); 169 } 170 171 $enableData[$model_no]['desc'][$language_id] = array( 172 'description'=>$description, 173 'name'=>$name, 174 'abstract'=>$abstract, 175 'keywords'=>$keywords, 176 'language_name'=>$language_name, 177 'meta_title'=>$meta_title, 178 'meta_keyword'=>$meta_keyword, 179 'meta_description'=>$meta_description, 180 'url_alias'=>$url 181 ); 182 183 } 184 185 //遍历检测网址 186 foreach ($enableData as $key => $value){ 187 if(isset($value['desc']) && !empty($value['desc'])){ 188 foreach ($value['desc'] as $k => $v){ 189 $cc = $urlAliasModel->validate(['keyword' => $v['url_alias'], 'language_id' => $k, 'query' => ''],'add'); 190 if($cc==false){ 191 return false; 192 } 193 } 194 } 195 } 196 197 //解压缩图片压缩包 198 $dirPath = DIR_UPLOAD.$this->session->data['site_id']; 199 $file = $dirPath.'/'.$data['images_file']; 200 if(!file_exists($file) || (substr(strrchr($file, '.'), 1)<>'zip')){ 201 $this->addError('imageZip', '请上传产品图片压缩包(zip格式)'); 202 return false; 203 } 204 $z = new Unzip; 205 $info = $z->unzip($file, $dirPath.'/', true, false); 206 if($info){ 207 unlink($file); //删除压缩包 208 } 209 210 //获取产品图片 211 foreach ($enableData as $key => $value){ 212 $enableData[$key]['image'] = $this->_getImage($key,$dirPath.'/'.basename($data['images_file'],'.zip')); 213 } 214 215 foreach ($enableData as $key => $value){ 216 try { 217 $productModel->add($value); 218 } catch (Exception $e) { 219 $this->addError('add', $e->getMessage()); 220 return false; 221 } 222 } 223 return true; 224 225 } 226 227 /** 228 * 生成模板 229 * 230 * @access public 231 * @return void 232 */ 233 public function createTemplate() 234 { 235 236 $languageModel = new LanguageModel(); 237 $languages = $languageModel->getEnabledLanguages(); 238 239 $categoryModel = new CategoryModel(); 240 $category = $categoryModel->getRecursionCategory(); 241 $categoryNme = $this->_getCategoryName($category); 242 243 $columnNum = 3000; 244 245 $spreadsheet = new Spreadsheet(); 246 247 /*****************************************设置当前活动页内容***********************************/ 248 249 $sheet = $spreadsheet->getActiveSheet(); 250 $sheet->setCellValue('A1', '型号(必填)'); 251 $sheet->setCellValue('B1', '分类名(必填)'); 252 $sheet->setCellValue('C1', '排序(必填,请输入数字)'); 253 $sheet->setCellValue('D1', '状态(必填,1=上架|0=下架)'); 254 $sheet->setCellValue('E1', '语言(必填)'); 255 $sheet->setCellValue('F1', '名称(必填)'); 256 $sheet->setCellValue('G1', '关键词(必填)'); 257 $sheet->setCellValue('H1', '简要描述'); 258 $sheet->setCellValue('I1', '详细描述'); 259 $sheet->setCellValue('J1', '网址'); 260 $sheet->setCellValue('K1', 'seo标题'); 261 $sheet->setCellValue('L1', 'seo关键词'); 262 $sheet->setCellValue('M1', 'seo描述'); 263 264 //设置相关属性 265 $sheet->setTitle('Product'); 266 $sheet->getDefaultColumnDimension()->setWidth(30); 267 $sheet->getStyle('A1:M1')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID); 268 $sheet->getStyle('A1:M1')->getFill()->getStartColor()->setARGB('FF808080'); 269 $sheet->getStyle('A1:M1')->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE); 270 271 //分类列 272 for($i=2;$i<=$columnNum;$i++){ 273 $objValidation = $sheet->getDataValidation('B'.$i); 274 $objValidation -> setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST) 275 -> setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION) 276 -> setAllowBlank(false) 277 -> setShowInputMessage(true) 278 -> setShowErrorMessage(true) 279 -> setShowDropDown(true) 280 -> setErrorTitle('输入的值有误') 281 -> setError('您输入的值不在下拉框列表内') 282 -> setPrompt('请选择下拉框列表中的值') 283 -> setFormula1('data!$C$3:$C$'.(count($categoryNme)+2)); 284 } 285 286 //状态列 287 for($i=2;$i<=$columnNum;$i++){ 288 $objValidation = $sheet->getDataValidation('D'.$i); 289 $objValidation -> setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST) 290 -> setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION) 291 -> setAllowBlank(false) 292 -> setShowInputMessage(true) 293 -> setShowErrorMessage(true) 294 -> setShowDropDown(true) 295 -> setErrorTitle('输入的值有误') 296 -> setError('您输入的值不在下拉框列表内') 297 -> setPrompt('请选择下拉框列表中的值') 298 -> setFormula1('data!$A$3:$A$4'); 299 } 300 301 //语言列 302 for($i=2;$i<=$columnNum;$i++){ 303 $objValidation = $sheet->getDataValidation('E'.$i); 304 $objValidation -> setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST) 305 -> setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION) 306 -> setAllowBlank(false) 307 -> setShowInputMessage(true) 308 -> setShowErrorMessage(true) 309 -> setShowDropDown(true) 310 -> setErrorTitle('输入的值有误') 311 -> setError('您输入的值不在下拉框列表内') 312 -> setPrompt('请选择下拉框列表中的值') 313 -> setFormula1('data!$B$3:$B$'.(count($languages)+2)); 314 } 315 316 317 318 /*******************************************新增一个活动页,放公共数据*********************************/ 319 320 $spreadsheet->createSheet(); 321 $spreadsheet->setActiveSheetIndex(1); 322 $sheet = $spreadsheet->getActiveSheet(); 323 $sheet->setTitle('data'); 324 $sheet->getDefaultColumnDimension()->setWidth(25); 325 $sheet->mergeCells('A1:C1'); 326 $styleArray = [ 327 'alignment' => [ 328 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 329 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, 330 ], 331 ]; 332 $sheet->getStyle('A1')->applyFromArray($styleArray); 333 $sheet->getRowDimension('1')->setRowHeight(35); 334 335 $sheet->getStyle('A1')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID); 336 $sheet->getStyle('A1')->getFill()->getStartColor()->setARGB('8B0000'); 337 $sheet->getStyle('A1')->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE); 338 $sheet->setCellValue('A1', '公共数据(请不要修改)'); 339 340 $sheet->getStyle('A2:C2')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID); 341 $sheet->getStyle('A2:C2')->getFill()->getStartColor()->setARGB('FF808080'); 342 $sheet->getStyle('A2:C2')->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE); 343 344 $sheet->setCellValue('A2', '状态(1=上架|0=下架)'); 345 $sheet->setCellValue('A3', '0'); 346 $sheet->setCellValue('A4', '1'); 347 348 $sheet->setCellValue('B2', '语言'); 349 foreach ($languages as $key => $value){ 350 $sheet->setCellValue('B'.($key+3), $value['name']); 351 } 352 353 $sheet->setCellValue('C2', '分类名'); 354 foreach ($categoryNme as $key => $value){ 355 $sheet->setCellValue('C'.($key+3), $value); 356 } 357 358 $sheet->setSheetState('hidden'); 359 360 //设置第一页为活动页,保存 361 $spreadsheet->setActiveSheetIndex(0); 362 $writer = new Xlsx($spreadsheet); 363 $file_name = $this->session->data['site_id'].'.xlsx'; 364 $file_path = DIR_UPLOAD.'excel_template/'.$file_name; 365 $writer->save($file_path); 366 367 //释放内存 368 $spreadsheet->disconnectWorksheets(); 369 unset($spreadsheet); 370 371 return $file_name; 372 } 373 374 /** 375 * 验证 376 * @access private 377 * @param array $data 378 * @param string $scenario 验证场景 add 379 * @return bool 380 */ 381 private function _validate($data, $scenario = '') 382 { 383 384 if (!isset($data['excel_file']) || empty($data['excel_file'])) { 385 $this->addError('excel_file', '没有上传产品Excel文件'); 386 } 387 388 if (!isset($data['images_file']) || empty($data['images_file'])) { 389 $this->addError('images_file', '没有上传产品图片文件'); 390 } 391 392 return $this->hasErrors() ? false : true; 393 } 394 395 /** 396 * 获取产品分类名称 397 * @access private 398 * @param array $data 399 * @return array 400 */ 401 private function _getCategoryName($data){ 402 403 if(!empty($data)){ 404 405 foreach ($data as $key => $value){ 406 if(!empty($data['children'])){ 407 $this->_getCategoryName($data['children']); 408 }else{ 409 $retrun[] = $value['name']; 410 } 411 } 412 413 }else{ 414 $retrun = array(); 415 } 416 417 return $retrun; 418 419 } 420 421 /** 422 * 遍历文件夹 423 * @access private 424 * @param string $dir 425 * @return array 426 */ 427 private function _getDirFile($dir) { 428 $files = array(); 429 if(@$handle = opendir($dir)) { //注意这里要加一个@,不然会有warning错误提示:) 430 while(($file = readdir($handle)) !== false) { 431 if($file != ".." && $file != ".") { //排除根目录; 432 if(is_dir($dir."/".$file)) { //如果是子文件夹,就进行递归 433 $files[$file] = $this->_getDirFile($dir."/".$file); 434 } else { //不然就将文件的名字存入数组; 435 $files[] = $file; 436 } 437 438 } 439 } 440 closedir($handle); 441 return $files; 442 } 443 } 444 445 /** 446 * 获取产品图片 447 * @access private 448 * @param string $dir 449 * @return array 450 */ 451 private function _getImage($key,$images_file){ 452 453 $aliYunOSS = new AliYunOSS(); 454 $data = array(); 455 $arr_image = $this->_getDirFile($images_file); 456 457 if(isset($arr_image[$key])){ 458 459 foreach ($arr_image[$key] as $k => $v){ 460 $result = $aliYunOSS->uploadFile($images_file.'/'.$key.'/'.$v, 'upload/images/'.$key.'/'.$v); 461 if($result['success']==1){ 462 $data[] = array( 463 'name'=>$v, 464 'image'=>$result['info']['url'] 465 ); 466 } 467 } 468 469 } 470 471 return $data; 472 } 473 474 }