refactor: 同步程序
This commit is contained in:
@@ -45,7 +45,10 @@ class DataMigration extends Command
|
||||
// $this->migrateProductAttr();
|
||||
|
||||
// 迁移产品
|
||||
$this->migrateProduct();
|
||||
// $this->migrateProduct();
|
||||
|
||||
// 迁移产品关联产品数据
|
||||
$this->migrateProductRelated();
|
||||
|
||||
// 迁移文章
|
||||
// $this->migrateArticle([
|
||||
@@ -245,15 +248,27 @@ class DataMigration extends Command
|
||||
|
||||
$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('id', '=', 128)
|
||||
->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 {
|
||||
// 处理封面图片
|
||||
@@ -262,8 +277,10 @@ class DataMigration extends Command
|
||||
if ($image_ret['code'] == 0) {
|
||||
$image = $image_ret['data']['path'];
|
||||
} else {
|
||||
if ($image_ret['code'] != 400) {
|
||||
$image = $image_ret['msg'];
|
||||
}
|
||||
}
|
||||
|
||||
// 处理视频
|
||||
$video = '';
|
||||
@@ -271,8 +288,10 @@ class DataMigration extends Command
|
||||
if ($video_ret['code'] == 0) {
|
||||
$video = $video_ret['data']['path'];
|
||||
} else {
|
||||
if ($video_ret['code'] != 400) {
|
||||
$video = $video_ret['msg'];
|
||||
}
|
||||
}
|
||||
|
||||
// 处理详情中图片
|
||||
$content = preg_replace_callback('/<img[^>]*src=[\'"]([^\'"]*?)[\'"][^>]*>/is', function($matches) use ($uploadMgr) {
|
||||
@@ -287,11 +306,11 @@ class DataMigration extends Command
|
||||
return '<img src="解析替换图片失败,请手动处理" alt="" />';
|
||||
}
|
||||
return '<img src="' . $file_path . '" alt="" />';
|
||||
}, $v['ld_md_content']);
|
||||
}, $v['ld_md_content']??'');
|
||||
|
||||
$item = [
|
||||
'language_id' => $v['country_code'] == 'ZH' ? 1 : 2,
|
||||
'category_id' => '',
|
||||
'category_id' => $v['cid'],
|
||||
'spu' => $v['brand_id'],
|
||||
'name' => $v['name'],
|
||||
'short_name' => $v['shortname'],
|
||||
@@ -302,21 +321,22 @@ class DataMigration extends Command
|
||||
'is_sale' => $v['is_onsale'],
|
||||
'is_new' => $v['isnew'],
|
||||
'is_hot' => $v['ishot'],
|
||||
'is_show' => $v['is_show'],
|
||||
'sort' => $v['sort'],
|
||||
'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' => date('Y-m-d H:i:s', $v['updatetime']),
|
||||
'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) {
|
||||
@@ -327,6 +347,7 @@ class DataMigration extends Command
|
||||
];
|
||||
}
|
||||
Db::name('product_params')->insertAll($prarms);
|
||||
}
|
||||
|
||||
// 保存sku数据
|
||||
$skus = [];
|
||||
@@ -350,6 +371,7 @@ class DataMigration extends Command
|
||||
if (!isset($images[$pkey])) {
|
||||
$images[$pkey] = [];
|
||||
$images[$pkey]['sku'] = $im['sku'];
|
||||
$images[$pkey]['attrs'] = [];
|
||||
}
|
||||
|
||||
// 处理图册
|
||||
@@ -365,6 +387,10 @@ class DataMigration extends Command
|
||||
$photo_album[$pkey] = [];
|
||||
}
|
||||
$photo_album[$pkey][] = $photos_ret['data']['path'];
|
||||
} else {
|
||||
if ($photos_ret['code'] != 400) {
|
||||
$photo_album[$pkey][] = json_encode($photos_ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,19 +398,21 @@ class DataMigration extends Command
|
||||
// 处理属性
|
||||
$attrs = json_decode($im['image_color'], true);
|
||||
if (!empty($attrs)) {
|
||||
foreach ($attrs as $k => $at) {
|
||||
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'] = [
|
||||
$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 == '[]') {
|
||||
@@ -402,20 +430,21 @@ class DataMigration extends Command
|
||||
'attr_value' => $attr_value,
|
||||
];
|
||||
if (
|
||||
empty($images[$pkey]['attrs']) ||
|
||||
(!empty($images[$pkey]['attrs']) && empty(array_intersect($images[$pkey]['attrs'], $attr_arr)))
|
||||
empty($images[$pkey]['attrs']) || !array_some($images[$pkey]['attrs'], function($k, $v) use($attr_arr) {
|
||||
return $v == $attr_arr;
|
||||
})
|
||||
) {
|
||||
|
||||
$images[$pkey]['attrs'][] = $attr_arr;
|
||||
file_put_contents(runtime_path() . 'attrs.txt', json_encode($attr_arr));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($photo_album)) {
|
||||
foreach ($images as $key => $image) {
|
||||
if (isset($photo_album[$key])) {
|
||||
$images[$key]['photo_album'] = $photo_album[$key];
|
||||
}
|
||||
file_put_contents(runtime_path() . 'images.txt', json_encode($images, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
file_put_contents(runtime_path() . 'photo_album.txt', json_encode($photo_album, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
|
||||
$two_images = $old_db->name('product_two_img')
|
||||
->where('product_id', '=', $v['id'])
|
||||
@@ -428,56 +457,74 @@ class DataMigration extends Command
|
||||
if (!empty($ti['image_color'])) {
|
||||
$tpkey = md5($ti['image_color']);
|
||||
}
|
||||
if (!empty($ti['image_url'])) {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
$skus[] = ['main_image' => $ti['image_url'], 'image_color' => $ti['image_color'], 'pkey' => $tpkey];
|
||||
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) {
|
||||
if (isset($images[$sku['pkey']])) {
|
||||
$skus[$idx]['product_id'] = $id;
|
||||
$skus[$idx]['sku'] = $images[$sku['pkey']]['sku'];
|
||||
$skus[$idx]['photo_album'] = $images[$sku['pkey']]['photo_album'];
|
||||
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($images[$idx])) {
|
||||
$temp = $images[$idx];
|
||||
if (empty($temp_images)) {
|
||||
$temp_images = array_values($images);
|
||||
}
|
||||
if (!empty($temp_images[$idx])) {
|
||||
$temp = $temp_images[$idx];
|
||||
}
|
||||
if (!empty($temp)) {
|
||||
$skus[$idx]['product_id'] = $id;
|
||||
$skus[$idx]['sku'] = $temp['sku'];
|
||||
$skus[$idx]['photo_album'] = $temp['photo_album'];
|
||||
$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']);
|
||||
unset($skus[$idx]['image_color']);
|
||||
}
|
||||
} else {
|
||||
foreach ($images as $image) {
|
||||
$skus[] = [
|
||||
'product_id' => $id,
|
||||
'sku' => $image['sku'],
|
||||
'sku' => $image['sku']??null,
|
||||
'main_image' => '',
|
||||
'photo_album' => $image['photo_album'],
|
||||
'photo_album' => $image['photo_album']??null,
|
||||
'skus' => $image['attrs']
|
||||
];
|
||||
}
|
||||
}
|
||||
file_put_contents(runtime_path() . 'skus.txt', json_encode($skus, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
// throw new \Exception("exit;");
|
||||
|
||||
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' => json_encode($sku['photo_album']),
|
||||
'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) {
|
||||
@@ -491,13 +538,21 @@ class DataMigration extends Command
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
$this->println(sprintf('迁移产品ID:%s => %s', $v['id'], $id));
|
||||
$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())
|
||||
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',
|
||||
@@ -505,6 +560,38 @@ class DataMigration extends Command
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
// 迁移文章
|
||||
@@ -758,11 +845,13 @@ class UploadMannager
|
||||
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');
|
||||
}
|
||||
|
||||
// 下载图片
|
||||
@@ -805,21 +894,14 @@ class UploadMannager
|
||||
|
||||
$file_path = self::DOWNLOAD_TEMP_PATH . $file_name;
|
||||
if (file_exists($file_path)) {
|
||||
if (!is_valid_image($file_path)) {
|
||||
return '';
|
||||
}
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
// 使用file_get_contents下载
|
||||
// $opts = [
|
||||
// 'http' => [
|
||||
// 'method' => 'GET',
|
||||
// 'header' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
|
||||
// ]
|
||||
// ];
|
||||
// $context = stream_context_create($opts);
|
||||
// $file = file_get_contents($url, false, $context);
|
||||
|
||||
// 使用curl下载
|
||||
$file = $this->file_get_withcurl($url);
|
||||
$file = file_get_withcurl($url);
|
||||
$dir = dirname($file_path);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
@@ -828,34 +910,17 @@ class UploadMannager
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
// 使用curl下载图片
|
||||
private 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, 30); // 传输超时 30 秒
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // 模拟浏览器 UA
|
||||
|
||||
$data = curl_exec($ch);
|
||||
if ($data === false) {
|
||||
error_log(sprintf('cURL Error: %s; URL: %s', curl_error($ch), $url));
|
||||
return false;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// 上传图片
|
||||
public function upload($file_path, $field_name, $module = 'unknown') {
|
||||
if (empty($file_path)) {
|
||||
return ['code' => 0, 'msg' => 'file_path为空', 'data' => ['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':
|
||||
@@ -939,3 +1004,48 @@ class UploadMannager
|
||||
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;
|
||||
}
|
||||
|
||||
2
public/migrate_temp_images/.gitignore
vendored
Normal file
2
public/migrate_temp_images/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user