println)($msg); } protected function configure() { // 指令配置 $this->setName('migrate') ->setDescription('执行数据迁移'); } protected function execute(Input $input, Output $output) { ini_set('pcre.backtrack_limit', 10000000); ini_set('default_socket_timeout', 1); // 指令输出 $this->println = function ($msg) use ($output) { $output->writeln($msg); }; try { // 迁移tock产品分类 // $this->productTcoCategory(); // 迁移产品分类 // $this->productCategory(); // 迁移产品属性 // $this->migrateProductAttr(); // 迁移产品 // $this->migrateProduct(); // 迁移产品关联产品数据 // $this->migrateProductRelated(); // 迁移产品购买链接 $this->migrateProductPurchaseLinks(); // 迁移文章 // $this->migrateArticle([ // 68 => 10, // 69 => 11, // 70 => 12, // 71 => 13, // 72 => 14, // 73 => 15, // 74 => 16, // 75 => 17, // 78 => 19, // 79 => 20, // 80 => 21, // 81 => 22, // 82 => 23, // 83 => 24, // 84 => 25, // 85 => 26 // ]); // 迁移faq // $this->migrateFaq(); // 迁移附件下载 // $this->migrateAttachment([ // 1 => 1, // 2 => 2, // 3 => 3, // 4 => 4, // 5 => 5, // 43 => 6, // 22 => 8, // 24 => 11, // 25 => 12, // 26 => 13, // 44 => 9, // 45 => 10 // ]); // 迁移视频分类 // $this->migrateVideoCategory(); // 迁移视频 // $this->migrateVideo([ // 0 => 0, // 1 => 1, // 2 => 2, // 3 => 3, // 4 => 4, // 5 => 5, // 6 => 6, // 7 => 7, // 8 => 8, // 11 => 0, // 36 => 9, // 37 => 10, // 38 => 11, // 39 => 12, // 40 => 13, // 41 => 14, // 42 => 15, // 43 => 16, // 60 => 17, // 62 => 18, // 63 => 19 // ]); // $this->test(); $output->writeln('success'); } catch(\Throwable $th) { $output->writeln($th->getMessage() .':' . $th->getLine()); } } // 迁移tco产品分类 private function productTcoCategory() { $category = Db::connect('old') ->name('product_tco_category') ->select(); foreach ($category as $val) { $item = [ 'id' => $val['id'], 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'name' => $val['name'], 'tco_id' => $val['tco_id'], 'tco_pid' => $val['tco_pid'], 'tco_path' => $val['tco_path'], 'erp_id' => $val['erp_id'], 'erp_pid' => $val['erp_pid'], 'erp_path' => $val['erp_path'], 'erp_code' => $val['erp_code'], 'disabled' => $val['disabled'], 'sync_time' => $val['sync_time'], ]; Db::name('product_tco_category')->insert($item); } } // 迁移产品分类 private function productCategory() { $tco_category = Db::connect('old') ->name('product_tco_category') ->select(); $tco_category_map = []; foreach ($tco_category as $val) { $key = sprintf("%s_%s", $val['category_id'], $val['country_code']); if (isset($tco_category_map[$key])) { $tco_category_map[$key] = []; } $tco_category_map[$key][] = $val['id']; } $category = Db::connect('old') ->name('product_category') ->select() ->toArray(); // 处理数据 $this->handlerProductCategory(array_to_tree($category, 0, 'pid', 1), $tco_category_map); } private function handlerProductCategory($category, $map) { foreach ($category as $val) { $key = sprintf("%s_%s", $val['id'], $val['country_code']); $item = [ 'id' => $val['id'], 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'unique_id' => uniqid('PRO_CATE_'), 'pid' => $val['pid'], 'name' => $val['name'], 'icon' => $val['icon'], 'desc' => $val['description'], 'related_tco_category' => isset($map[$key]) ? implode(',', $map[$key]) : '', 'sort' => $val['sort'] == 9999 ? 0 : $val['sort'], 'level' => $val['level'], 'is_show' => $val['isshow'], ]; Db::name('product_category')->insert($item); if (isset($val['children'])) { $this->handlerProductCategory($val['children'], $map); } } } // 迁移产品属性 private function migrateProductAttr() { $products = Db::connect('old') ->name('product') ->where('country_code', 'in', ['ZH', 'US']) ->where('product_attr', '<>', '') ->order(['id' => 'asc']) ->cursor(); $exists = []; foreach ($products as $v) { $attrs = []; $product_attr = json_decode($v['product_attr'], true); foreach ($product_attr as $attr) { if (!in_array($attr, ['颜色', 'Color']) && !in_array($attr, $exists)) { $attrs[] = [ 'language_id' => $v['country_code'] == 'ZH' ? 1 : 2, 'attr_type' => 2, 'attr_name' => $attr, 'is_system' => 0 ]; $exists[] = $attr; } } if (empty($attrs)) { continue; } Db::name('product_attr')->insertAll($attrs); } } // 迁移产品 private function migrateProduct() { $attrs_map = []; $attrs_dict = Db::name('product_attr') ->withoutField(['created_at', 'updated_at', 'deleted_at']) ->select(); foreach ($attrs_dict as $attr) { $code = $attr['language_id'] == 1 ? 'ZH' : 'US'; if (!isset($attrs_map[$code])) { $attrs_map[$code] = []; } $attrs_map[$code][$attr['attr_name']] = $attr['id']; } $old_db = Db::connect('old'); $success_map = []; $success_arr = include_once(runtime_path() . 'product_success.php'); foreach ($success_arr as $so) { $success_map['p_' . $so['cod_product_id']] = $so; } $products = $old_db->name('product') ->where('country_code', 'in', ['ZH', 'US']) ->where('id', '>', 0) ->order(['id' => 'asc']) ->cursor(); $total = 0; $uploadMgr = new UploadMannager(); foreach ($products as $v) { $start = microtime(true); if (isset($success_map['p_' . $v['id']])) { continue; } Db::startTrans(); try { // 处理封面图片 $image = ''; $image_ret = $uploadMgr->upload($uploadMgr->download($v['list_bk_img']), 'image', 'product'); if ($image_ret['code'] == 0) { $image = $image_ret['data']['path']; } else { if ($image_ret['code'] != 400) { $image = $image_ret['msg']; } } // 处理视频 $video = ''; $video_ret = $uploadMgr->upload($uploadMgr->download($v['videopath']), 'video', 'video'); if ($video_ret['code'] == 0) { $video = $video_ret['data']['path']; } else { if ($video_ret['code'] != 400) { $video = $video_ret['msg']; } } // 处理详情中图片 $content = preg_replace_callback('/]*src=[\'"]([^\'"]*?)[\'"][^>]*>/is', function($matches) use ($uploadMgr) { $file_path = ''; try { $ret = $uploadMgr->upload($uploadMgr->download($matches[1]), 'image'); if ($ret['code'] == 0) { $file_path = $ret['data']['path']; } } catch (\Throwable $th) { $this->println($th->getMessage() . ':' . $th->getLine()); return ''; } return ''; }, $v['ld_md_content']??''); $item = [ 'language_id' => $v['country_code'] == 'ZH' ? 1 : 2, 'category_id' => $v['cid'], 'spu' => $v['brand_id'], 'name' => $v['name'], 'short_name' => $v['shortname'], 'cover_image' => $image, 'desc' => $v['description'], 'video_img' => '', 'video_url' => $video, 'is_sale' => $v['is_onsale'], 'is_new' => $v['isnew'], 'is_hot' => $v['ishot'], 'is_show' => $v['is_show'] == 0 ? 1 : 0, 'sort' => $v['sort'] == 9999 ? 0 : $v['sort'], 'detail' => $content, 'status' => $v['stat'] == -1 ? -1 : 1, 'seo_title' => $v['seo_title'], 'seo_keywords' => $v['seo_keyword'], 'seo_desc' => $v['seo_description'], 'created_at' => date('Y-m-d H:i:s', $v['createtime']), 'updated_at' => $v['updatetime'] == 0 ? date('Y-m-d H:i:s', $v['createtime']) : date('Y-m-d H:i:s', $v['updatetime']), 'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null, ]; // 保存产品数据 $id = Db::name('product')->insertGetId($item); // 保存产品参数数据 if (!empty($v['product_view'])) { $prarms = []; $views = unserialize($v['product_view']); foreach ($views as $p) { $prarms[] = [ 'product_id' => $id, 'name' => $p['desc_title'], 'value' => $p['desc_desc'] ]; } Db::name('product_params')->insertAll($prarms); } // 保存sku数据 $skus = []; $sku_images = $old_db->name('product_image') ->where('product_id', '=', $v['id']) ->where('country_code', '=', $v['country_code']) ->where('stat', '=', 0) ->order(['id' => 'asc']) ->select(); $images = []; $photo_album = []; foreach ($sku_images as $im) { $pkey = $im['sku']; if (empty($pkey)) { if (!empty($im['image_color'])) { $pkey = md5($im['image_color']); } else { $pkey = 0; } } if (!isset($images[$pkey])) { $images[$pkey] = []; $images[$pkey]['sku'] = $im['sku']; $images[$pkey]['attrs'] = []; } // 处理图册 if (!empty($im['image_url'])) { $photos = json_decode($im['image_url'], true); if (empty($photos)) { $photos[] = $im['image_url']; } foreach ($photos as $photo) { $photos_ret = $uploadMgr->upload($uploadMgr->download($photo), 'image', 'product'); if ($photos_ret['code'] == 0) { if (!isset($photo_album[$pkey])) { $photo_album[$pkey] = []; } $photo_album[$pkey][] = $photos_ret['data']['path']; } else { if ($photos_ret['code'] != 400) { $photo_album[$pkey][] = json_encode($photos_ret); } } } } // 处理属性 $attrs = json_decode($im['image_color'], true); if (!empty($attrs)) { foreach ($attrs as $attr) { foreach ($attr as $k => $at) { if ($k != 'sort') { $attr_value = $at; if (in_array($k, ['颜色', 'Color'])) { if ($k == 'Color') $k = '颜色'; $attr_value = '/static/common/images/colors/' . $at . '.png'; } $images[$pkey]['attrs'][] = [ 'attr_id' => $attrs_map[$v['country_code']][$k], 'attr_value' => $attr_value, ]; } } } } else { $attr_value = $im['image_color']; if (empty($attr_value) || $attr_value == '[]') { $images[$pkey]['attrs'] = []; continue; } if (\think\helper\Str::endsWith($attr_value, ['.png', '.jpg', 'jpeg', '.gif'])) { $photos_ret = $uploadMgr->upload($uploadMgr->download($attr_value), 'image', 'product'); if ($photos_ret['code'] == 0) { $attr_value = $photos_ret['data']['path']; } } $attr_arr = [ 'attr_id' => $attrs_map[$v['country_code']]['颜色'], 'attr_value' => $attr_value, ]; if ( empty($images[$pkey]['attrs']) || !array_some($images[$pkey]['attrs'], function($k, $v) use($attr_arr) { return $v == $attr_arr; }) ) { $images[$pkey]['attrs'][] = $attr_arr; } } } if (!empty($photo_album)) { foreach ($images as $key => $image) { if (isset($photo_album[$key])) { $images[$key]['photo_album'] = $photo_album[$key]; } } } $two_images = $old_db->name('product_two_img') ->where('product_id', '=', $v['id']) ->where('country_code', '=', $v['country_code']) ->where('stat', '=', 0) ->order(['id' => 'asc']) ->select(); foreach ($two_images as $ti) { $tpkey = 0; if (!empty($ti['image_color'])) { $tpkey = md5($ti['image_color']); } if (!empty($ti['image_url']) && $ti['image_url'] != '[]') { $main_image_ret = $uploadMgr->upload($uploadMgr->download($ti['image_url']), 'image', 'product'); if ($main_image_ret['code'] == 0) { $ti['image_url'] = $main_image_ret['data']['path']; } } if (\think\helper\Str::endsWith($ti['image_color'], ['.png', '.jpg', 'jpeg', '.gif'])) { $arrt_ret = $uploadMgr->upload($uploadMgr->download($ti['image_color']), 'image', 'product'); if ($arrt_ret['code'] == 0) { $ti['image_color'] = $arrt_ret['data']['path']; } } $skus[] = [ 'main_image' => $ti['image_url'], 'attrs' => [[ 'attr_id' => $attrs_map[$v['country_code']]['颜色'], 'attr_value' => $ti['image_color'], ]], 'pkey' => $tpkey ]; } if (!empty($skus)) { $temp = []; $temp_images = []; foreach ($skus as $idx => $sku) { $skus[$idx]['product_id'] = $id; if (isset($images[$sku['pkey']])) { $skus[$idx]['sku'] = $images[$sku['pkey']]['sku']??null; $skus[$idx]['photo_album'] = $images[$sku['pkey']]['photo_album']??null; if (!empty($images[$sku['pkey']]['attrs'])) { $skus[$idx]['attrs'] = $images[$sku['pkey']]['attrs']; } } else { if (empty($temp_images)) { $temp_images = array_values($images); } if (!empty($temp_images[$idx])) { $temp = $temp_images[$idx]; } if (!empty($temp)) { $skus[$idx]['sku'] = $temp['sku']??null; $skus[$idx]['photo_album'] = $temp['photo_album']??null; if (!empty($temp['attrs'])) { $skus[$idx]['attrs'] = $temp['attrs']; } } } unset($skus[$idx]['pkey']); } } else { foreach ($images as $image) { $skus[] = [ 'product_id' => $id, 'sku' => $image['sku']??null, 'main_image' => '', 'photo_album' => $image['photo_album']??null, 'skus' => $image['attrs'] ]; } } foreach ($skus as $sku) { $sku_id = Db::name('product_sku')->insertGetId([ 'product_id' => $sku['product_id'], 'sku' => $sku['sku']??'', 'main_image' => $sku['main_image']??'', 'photo_album' => !empty($sku['photo_album']) ? json_encode($sku['photo_album']) : null, ]); if (!empty($sku['attrs'])) { foreach ($sku['attrs'] as $attr) { if (!empty($sku_id)) { Db::name('product_sku_attr')->insert([ 'sku_id' => $sku_id, 'attr_id' => $attr['attr_id'], 'attr_value' => $attr['attr_value'] ]); } } } } Db::commit(); $total += 1; file_put_contents( runtime_path() . 'product_success.txt', sprintf('["ow_product_id" => %d, "cod_product_id" => %d]'.PHP_EOL, $id, $v['id']), FILE_APPEND ); $this->println(sprintf('迁移产品ID:%s => %s 【耗时:%s】', $v['id'], 0, round(microtime(true) - $start, 2) . 's')); } catch (\Throwable $th) { Db::rollback(); file_put_contents( runtime_path() . 'product_throwable.txt', sprintf('【%s】 产品【%s】,迁移失败,错误【%s:%d】' . PHP_EOL, date('Y-h-d H:i:s'), $v['id'], $th->getMessage(), $th->getLine()), FILE_APPEND ); file_put_contents( runtime_path() . 'product_throwable_details.txt', (string)$th ); } } $this->println(sprintf('迁移产品完成,共迁移 %s 条数据', $total)); } // 迁移产品关联产品数据 private function migrateProductRelated() { $sources = include_once(runtime_path() . 'product_success.php'); $maps = []; foreach ($sources as $so) { $maps[$so['cod_product_id']] = $so; } $old_db = Db::connect('old'); $related = $old_db->name('product_related') ->where('country_code', 'in', ['ZH', 'US']) ->where('stat', '=', 0) ->cursor(); $data = []; foreach ($related as $rl) { if (empty($maps[$rl['product_id']]) || empty($maps[$rl['related_product_id']])) { continue; } $data[] = [ 'product_id' => $maps[$rl['product_id']]['ow_product_id'], 'related_product_id' => $maps[$rl['related_product_id']]['ow_product_id'], 'desc' => empty($rl['related_desc']) ? null : $rl['related_desc'], 'sort' => $rl['related_sort'] == 9999 ? 0 : $rl['related_sort'] ]; } Db::name('product_related')->insertAll($data); } // 迁移产品购买链接 private function migrateProductPurchaseLinks() { $platform_maps = [ 1 => 2, 2 => 1, 3 => 3, 4 => 4 ]; $sources = include_once(runtime_path() . 'product_success.php'); $maps = []; foreach ($sources as $so) { $maps[$so['cod_product_id']] = $so; } $old_db = Db::connect('old'); $links = $old_db->name('product_purchase_links') ->where('country_code', 'in', ['ZH', 'US']) ->where('link', '<>', '') ->cursor(); foreach ($links as $link) { if (empty($maps[$link['product_id']])) { continue; } $item = [ 'language_id' => $link['country_code'] == 'ZH' ? 1 : 2, 'product_id' => $maps[$link['product_id']]['ow_product_id'], 'platform_id' => $platform_maps[$link['platform_id']], 'link' => $link['link'] ]; Db::name('product_purchase_link')->insert($item); } } // 迁移文章 private function migrateArticle($category_map = []) { $this->println('开始迁移文章......'); if (empty($category_map)) { throw new \Exception('请确认分类ID'); } $article = Db::connect('old') ->name('article') ->where('cid', 'in', array_keys($category_map)) ->order(['id' => 'asc']) ->cursor(); $uploadMgr = new UploadMannager(); foreach ($article as $v) { // 处理封面图片 $image = ''; $ret = $uploadMgr->upload($uploadMgr->download($v['picture']), 'image', 'article'); if ($ret['code'] == 0) { $image = $ret['data']['path']; } else { $image = $ret['msg']; } // 处理详情中图片 $content = preg_replace_callback('/]*src=[\'"]([^\'"]*?)[\'"][^>]*>/is', function ($matches) use ($uploadMgr) { $file_path = ''; try { $ret = $uploadMgr->upload($uploadMgr->download($matches[1]), 'image'); if ($ret['code'] == 0) { $file_path = $ret['data']['path']; } } catch (\Throwable $th) { $this->println($th->getMessage() . ':' . $th->getLine()); return ''; } return ''; }, $v['content']); $item = [ 'language_id' => $v['country_code'] == 'ZH' ? 1 : 2, 'category_id' => $category_map[$v['cid']], 'title' => $v['name'], 'author' => $v['writer'], 'source' => $v['source'], 'image' => $image, 'desc' => $v['description'], 'recommend' => $v['recommend'], 'sort' => $v['sort'] == 9999 ? 0 : $v['sort'], 'link' => $v['jump_link'], 'content' => $content, 'view_count' => $v['viewcount'], 'praise_count' => $v['zancount'], 'seo_title' => $v['seo_title'], 'seo_keywords' => $v['seo_keyword'], 'seo_desc' => $v['seo_description'], 'release_time' => date('Y-m-d H:i:s', $v['createtime']), 'deleted_at' => $v['stat'] == -1 ? date('Y-m-d H:i:s') : null ]; $id = Db::name('article')->insertGetId($item); $this->println(sprintf('迁移文章ID:%s => %s', $v['id'], $id)); } } // 迁移FAQ private function migrateFaq() { $faq = Db::connect('old') ->name('fq') ->where('id', '>', 0) ->where('stat', '>=', 0) ->select(); $uploadMgr = new UploadMannager(); foreach ($faq as $key => $val) { $image = ''; $ret = $uploadMgr->upload($uploadMgr->download($val['picture']), 'image', 'faq'); if ($ret['code'] == 0) { $image = $ret['data']['path']; } else { $image = $ret['msg']; } $content = explode("\n", $val['content']); $content = '

' . implode("

", $content) . '

'; $item = [ 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'image' => $image, 'question' => $val['name'], 'answer' => $content, 'recommend' => $val['is_home'], 'sort' => $val['sort'] == 9999 ? 0 : $val['sort'] ]; Db::name('faq')->insert($item); } } // 迁移附件 private function migrateAttachment($category_map = []) { $attachment = Db::connect('old') ->name('download') ->where('id', '>', 0) ->where('country_code', 'in', ['ZH', 'US']) ->order(['id' => 'asc']) ->cursor(); $uploadMgr = new UploadMannager(); foreach ($attachment as $key => $val) { $image = ''; $image_ret = $uploadMgr->upload($uploadMgr->download($val['picture']), 'image'); if ($image_ret['code'] == 0) { $image = $image_ret['data']['path']; } else { $image = $image_ret['msg']; } $paths = explode(',', $val['downloadpath']); $btns = explode(',', $val['downloadpath64']); $attach = []; foreach ($paths as $k => $path) { $file_path = ''; if (\think\helper\Str::contains($path, "oos.oricogroup.com")) { $file_path = $path; } else { $attach_ret = $uploadMgr->upload($uploadMgr->download($path), 'attachment'); if ($attach_ret['code'] == 0) { $file_path = $attach_ret['data']['path']; } else { $file_path = $attach_ret['msg']; } } $file_ext = ''; $last_sper_idx = strrpos($path, '.'); if ($last_sper_idx !== false) { $file_ext = substr($path, $last_sper_idx + 1); if (substr($path, $last_sper_idx - 3, $last_sper_idx) == 'tar') { $file_ext = 'tar.' . $file_ext; } } $attach[] = [ 'file_path' => $file_path, 'file_ext' => $file_ext, 'btn_name' => $btns[$k], ]; } $item = [ 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'category_id' => $category_map[$val['cid']], 'name' => $val['name'], 'desc' => $val['description'], 'image' => $image, 'applicable_to' => $val['app_model'], 'support_platform' => $val['support_os'], 'attach' => json_encode($attach), 'sort' => $val['sort'] == 9999 ? 0 : $val['sort'], 'recommend' => $val['recommend'], 'seo_title' => $val['seo_title'], 'seo_keywords' => $val['seo_keyword'], 'seo_desc' => $val['seo_description'], 'deleted_at' => $val['stat'] == -1 ? date('Y-m-d H:i:s') : null ]; Db::name('attachment')->insert($item); $this->println('迁移附件ID:' . $val['id']); } } // 迁移视频 private function migrateVideoCategory() { $categorys = Db::connect('old') ->name('video_category') ->where('id', '>', 0) ->where('country_code', 'in', ['ZH', 'US']) ->order(['id' => 'asc']) ->cursor(); foreach ($categorys as $val) { $item = [ 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'name' => $val['name'], 'sort' => $val['sort'] == 9999 ? 0 : $val['sort'], 'is_show' => $val['isshow'] ]; Db::name('video_category')->insert($item); $this->println('迁移视频分类ID:' . $val['id']); } } // 迁移视频 private function migrateVideo($category_map = []) { $videos = Db::connect('old') ->name('video') ->where('id', '>', 844) ->where('country_code', 'in', ['ZH', 'US']) ->order(['id' => 'asc']) ->cursor(); $uploadMgr = new UploadMannager(); foreach ($videos as $val) { $image = ''; $image_ret = $uploadMgr->upload($uploadMgr->download($val['picture']), 'image', 'video'); if ($image_ret['code'] == 0) { $image = $image_ret['data']['path']; } else { $image = $image_ret['msg']; } $video = ''; if (!empty($val['videourl'])) { $video = $val['videourl']; } else { $video_ret = $uploadMgr->upload($uploadMgr->download($val['videopath']), 'video', 'video'); if ($video_ret['code'] == 0) { $video = $video_ret['data']['path']; } else { $video = $video_ret['msg']; } } $item = [ 'language_id' => $val['country_code'] == 'ZH' ? 1 : 2, 'category_id' => $category_map[$val['cid']], 'name' => $val['name'], 'desc' => $val['description'], 'image' => $image, 'video' => $video, 'sort' => $val['sort'] == 9999 ? 0 : $val['sort'], 'recommend' => $val['recommend'], 'seo_title' => $val['seo_title'], 'seo_keywords' => $val['seo_keyword'], 'seo_desc' => $val['seo_description'], 'deleted_at' => $val['stat'] == -1 ? date('Y-m-d H:i:s') : null ]; Db::name('video')->insert($item); $this->println('迁移视频ID:' . $val['id']); } } } class UploadMannager { const UPLOAD_BASE_API = 'http://dev.ow.f2b211.com'; const DOWNLOAD_BASE_API = 'http://www.orico.com.cn'; const DOWNLOAD_TEMP_PATH = '/var/www/html/orico-official-website/public/migrate_temp_images'; private $username = 'admin'; private $password = 'Aa-1221'; private $token = ''; private $retrys = []; private $maps = []; public function __construct() { // 登录获取token $this->token = $this->getAuthorization(); $this->maps = include_once(runtime_path() . 'fiber_product_image_mapping.php'); } // 下载图片 public function download($file_name) { if (empty($file_name)) { return ''; } $url = $file_name; if (\think\helper\Str::startsWith($file_name, 'http')) { $need = 'orico.com.cn'; if (!\think\helper\Str::contains($file_name, $need)) { if (\think\helper\Str::contains($file_name, 'https')) { // 避免https过期情况 $url = 'http://' . \think\helper\Str::substr($file_name, mb_strlen('https://')); } } else { $url = self::DOWNLOAD_BASE_API . \think\helper\Str::substr($file_name, mb_strpos($file_name, $need) + mb_strlen($need)); } $file_name = '/' . \think\helper\Str::substr($url, mb_strpos($url, '://') + 3); } elseif (\think\helper\Str::startsWith($file_name, 'data:image/')) { $idx = strpos($file_name, ';'); $file_type = substr($file_name, 0, $idx); $base64_image = preg_replace('#^data:image/\w+;base64,#i', '', $file_name); $file_data = base64_decode($base64_image, true); $file_path = self::DOWNLOAD_TEMP_PATH . '/uploads/' . date('Ymd') . '/' . uniqid() . '.' . substr($file_type, 11); $dir = dirname($file_path); if (!is_dir($dir)) { mkdir($dir, 0777, true); } if (!file_put_contents($file_path, $file_data, FILE_USE_INCLUDE_PATH)) { throw new \Exception('转换base64图片失败'); } return $file_path; } else { $url = self::DOWNLOAD_BASE_API . str_replace(" ", "%20", $file_name); } $file_path = self::DOWNLOAD_TEMP_PATH . $file_name; if (file_exists($file_path)) { if (!is_valid_image($file_path)) { return ''; } return $file_path; } // 使用curl下载 $file = file_get_withcurl($url); $dir = dirname($file_path); if (!is_dir($dir)) { mkdir($dir, 0777, true); } file_put_contents($file_path, $file, FILE_USE_INCLUDE_PATH); return $file_path; } // 上传图片 public function upload($file_path, $field_name, $module = 'unknown') { if (empty($file_path)) { return ['code' => 400, 'msg' => 'file_path为空', 'data' => ['path' => '']]; } if (\think\helper\Str::startsWith($file_path, 'http')) { return ['code' => 0, 'msg' => 'file_path为http', 'data' => ['path' => $file_path]]; } if (isset($this->maps[$file_path])) { return ['code' => 0, 'msg' => '成功', 'data' => ['path' => $this->maps[$file_path]]]; } switch($field_name){ case 'image': $url_path = "/admapi/v1/images/$module/upload"; break; case 'attachment': $url_path = '/admapi/v1/attachment/upload'; break; case 'video': $url_path = "/admapi/v1/video/$module/upload"; break; default: $url_path = "/admapi/v1/images/$module/upload"; break; } $ch = curl_init(self::UPLOAD_BASE_API . $url_path); $post_data = [ $field_name => new \CURLFile($file_path) ]; curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $this->token ]); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // 登录失效 if ($http_code == 401) { $this->token = $this->getAuthorization(); if (!isset($this->retrys[$file_path])) { $this->retrys[$file_path] = 0; } if ($this->retrys[$file_path] > 0) { throw new \Exception('[' . $file_path . ']上传重试失败'); } $this->retrys[$file_path] += 1; return $this->upload($file_path, $field_name); } if ($http_code != 200 && $http_code != 401) { print($file_path . PHP_EOL); print($field_name . PHP_EOL); print(self::UPLOAD_BASE_API . $url_path . PHP_EOL); print($response . PHP_EOL); print($http_code . PHP_EOL); } $ret = json_decode($response, true); if (empty($ret)) { throw new \Exception($response); } return $ret; } // 登录获取token private function getAuthorization() { $ch = curl_init(self::UPLOAD_BASE_API . '/admapi/v1/user/login'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'username' => $this->username, 'password' => md5($this->password) ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code != 200) { throw new \Exception('获取token失败'); } $result = json_decode($response, true); if ($result['code'] != 0) { throw new \Exception($result['msg']); } return $result['data']['token']; } } // 使用curl下载图片 function file_get_withcurl($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时 10 秒 curl_setopt($ch, CURLOPT_TIMEOUT, 60); // 传输超时 30 秒 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // 模拟浏览器 UA $data = curl_exec($ch); if ($data === false) { file_put_contents(runtime_path() . 'file_get_withcurl.txt', sprintf('cURL Error: %s; URL: %s' . PHP_EOL, curl_error($ch), $url), FILE_APPEND); return false; } curl_close($ch); return $data; } // 检查图片是否有效 function is_valid_image($filepath) { try { $image_size = getimagesize($filepath); if ($image_size === false) { return false; } [$width, $height] = $image_size; return $width > 0 && $height > 0; } catch (\Throwable $e) { return false; } } // 根据自定义函数检查数组 function array_some($array, callable $ca): bool { foreach ($array as $k => $v) { if ($ca($k, $v)) return true; } return false; }