作者 zhl

Merge remote-tracking branch 'origin/master' into zhl

  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :CropImage.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/5/8 9:19
  8 + */
  9 +
  10 +namespace App\Console\Commands\CropImage;
  11 +
  12 +use App\Enums\Common\Code;
  13 +use App\Models\Domain\DomainInfo;
  14 +use App\Models\File\Image;
  15 +use App\Models\WebSetting\AggregationSetting;
  16 +use App\Models\WebSetting\WebSettingImage;
  17 +use App\Services\CosService;
  18 +use App\Services\ProjectServer;
  19 +use Illuminate\Console\Command;
  20 +use Illuminate\Support\Facades\DB;
  21 +
  22 +class CropImage extends Command
  23 +{
  24 + /**
  25 + * The name and signature of the console command.
  26 + *
  27 + * @var string
  28 + */
  29 + protected $signature = 'crop_image {project_id}';
  30 +
  31 + /**
  32 + * The console command description.
  33 + *
  34 + * @var string
  35 + */
  36 + protected $description = '裁剪图片';
  37 +
  38 + public function handle(){
  39 + echo '测试裁剪->cs-crop:'.PHP_EOL;
  40 + $project_id = $this->argument('project_id');
  41 + ProjectServer::useProject($project_id);
  42 + $data = $this->_keywordAction($project_id);
  43 + $this->_aiAction($project_id,$data[0] ?? []);
  44 + DB::disconnect('custom_mysql');
  45 + }
  46 +
  47 + /**
  48 + * @remark :执行的方法
  49 + * @name :_action
  50 + * @author :lyh
  51 + * @method :post
  52 + * @time :2025/5/8 9:21
  53 + */
  54 + public function _keywordAction($project_id){
  55 + $resData = [];
  56 + //聚合页裁剪
  57 + $data = $this->getKeywordImage($project_id);
  58 + $cosService = new CosService();
  59 + if(!empty($data)){
  60 + foreach ($data as $val){
  61 + //处理图片为相对路径
  62 + $image = str_replace_url($val);
  63 + $height = $cosService->getImageHeight($image);
  64 + if(empty($height)){
  65 + echo '未获取到图片高度。'.PHP_EOL;
  66 + continue;
  67 + }
  68 + echo '返回的图片高度:'.$height.PHP_EOL;
  69 + if($height > 220){
  70 + $result = $cosService->cropCosImage($image);
  71 + if(empty($result)){
  72 + continue;
  73 + }
  74 + $resData[] = $result['path'];
  75 + $this->saveMysql($project_id,$result['size'],$result['type'],$result['path'],$result['mime']);
  76 + }else{
  77 + $resData[] = $image;
  78 + }
  79 + }
  80 + }
  81 + $this->saveAggregationSetting($project_id,$resData);
  82 + return $resData;
  83 + }
  84 +
  85 + /**
  86 + * @remark :ai执行方法
  87 + * @name :_aiAction
  88 + * @author :lyh
  89 + * @method :post
  90 + * @time :2025/5/8 16:12
  91 + */
  92 + public function _aiAction($project_id,$keywordImage){
  93 + $cosService = new CosService();
  94 + //ai_blog裁剪
  95 + $ai_image = $this->getAiBlogImage($project_id,$keywordImage ?? '');
  96 + if(empty($ai_image)){
  97 + echo '当前图片不需要裁剪。'.PHP_EOL;
  98 + return true;
  99 + }
  100 + $height = $cosService->getImageHeight($ai_image);
  101 + if(empty($height)){
  102 + echo '未获取到AI_BLOG图片高度。'.PHP_EOL;
  103 + return true;
  104 + }
  105 + echo '返回的图片高度:'.$height.PHP_EOL;
  106 + if($height > 220){
  107 + $result = $cosService->cropCosImage($ai_image);
  108 + if(empty($result)){
  109 + return true;
  110 + }
  111 + $this->saveMysql($project_id,$result['size'],$result['type'],$result['path'],$result['mime']);
  112 + $webSettingImageModel = new WebSettingImage();
  113 + $webSettingImageModel->edit(['image'=>$result['path']],['project_id' => $project_id, 'type' => 4]);
  114 + }
  115 + return true;
  116 + }
  117 +
  118 + /**
  119 + * @remark :保存数据
  120 + * @name :saveAggregationSetting
  121 + * @author :lyh
  122 + * @method :post
  123 + * @time :2025/5/8 16:24
  124 + */
  125 + public function saveAggregationSetting($project_id,$data){
  126 + if(empty($data)){
  127 + return true;
  128 + }
  129 + //存全路径
  130 + foreach ($data as $key => $val){
  131 + $val = getImageUrl($val);
  132 + $data[$key] = $val;
  133 + }
  134 + $aggregationSettingModel = new AggregationSetting();
  135 + $info = $aggregationSettingModel->read(['project_id'=>$project_id]);
  136 + if($info === false){
  137 + $aggregationSettingModel->addReturnId(['project_id'=>$project_id,'top_banner'=>json_encode($data,true)]);
  138 + }else{
  139 + $aggregationSettingModel->edit(['top_banner'=>json_encode($data,true)],['id'=>$info['id']]);
  140 + }
  141 + return true;
  142 + }
  143 +
  144 + /**
  145 + * @remark :获取aiBlog图片
  146 + * @name :getAiBlogImage
  147 + * @author :lyh
  148 + * @method :post
  149 + * @time :2025/5/8 10:42
  150 + */
  151 + public function getAiBlogImage($project_id,$keywordImage){
  152 + // AI博客banner type:1:产品,2:博客,3:新闻,4:AIBlog
  153 + $webSettingImageModel = new WebSettingImage();
  154 + $aiBlogInfo = $webSettingImageModel->read(['project_id' => $project_id, 'type' => 4],['image']);
  155 + if($aiBlogInfo === false && !empty($keywordImage)){
  156 + $webSettingImageModel->addReturnId(['project_id'=>$project_id,'image'=>$keywordImage,'type'=>4]);
  157 + return '';
  158 + }
  159 + if(empty($aiBlogInfo['image']) && !empty($keywordImage)){
  160 + $webSettingImageModel->edit(['image'=>$keywordImage],['id'=>$aiBlogInfo['id']]);
  161 + return '';
  162 + }
  163 + $ai_image = str_replace_url($aiBlogInfo['image']);
  164 + return $ai_image;
  165 + }
  166 +
  167 + /**
  168 + * @remark :获取聚合页图片
  169 + * @name :getImage
  170 + * @author :lyh
  171 + * @method :post
  172 + * @time :2025/5/8 9:21
  173 + */
  174 + public function getKeywordImage($project_id){
  175 + $data = [];
  176 + // 聚合页banner
  177 + $aggregationSettingModel = new AggregationSetting();
  178 + $aggregationSettingInfo = $aggregationSettingModel->read(['project_id' => $project_id],['id','top_banner']);
  179 + if($aggregationSettingInfo !== false && !empty($aggregationSettingInfo['top_banner'])){
  180 + foreach ($aggregationSettingInfo['top_banner'] as $val){
  181 + if($val != 'jpg' && $val != 'png' && $val != 'webp'){
  182 + $data[] = $val;
  183 + }
  184 + }
  185 + }
  186 + if(empty($data)){
  187 + //重页面上获取首页banner
  188 + $data = $this->getDomImage($project_id);
  189 + }
  190 + return $data;
  191 + }
  192 +
  193 + /**
  194 + * @remark :页面上获取图片
  195 + * @name :getDomImage
  196 + * @author :lyh
  197 + * @method :post
  198 + * @time :2025/5/8 10:32
  199 + */
  200 + public function getDomImage($project_id){
  201 + $data = [];
  202 + echo '获取首页banner:' . $project_id . PHP_EOL;
  203 + $domainModel = new DomainInfo();
  204 + $domainInfo = $domainModel->read(['project_id' => $project_id, 'status' => 1]);
  205 + if ($domainInfo !== false) {
  206 + $dom = @file_get_html('https://' . $domainInfo['domain'] . '/');
  207 + if (empty($dom)) {
  208 + $this->output('获取HTML失败: ' . $project_id);
  209 + }else{
  210 + $banner_dom = $dom->find('main .section-banner-wrap-block img', 0);
  211 + $data[] = $banner_dom ? $banner_dom->src : '';
  212 + $dom->clear();
  213 + unset($dom);
  214 + }
  215 + }else{
  216 + $this->output('域名不存在: ' . $project_id);
  217 + }
  218 + return $data;
  219 + }
  220 +
  221 + /**
  222 + * @remark :写入数据库
  223 + * @name :saveMysql
  224 + * @author :lyh
  225 + * @method :post
  226 + * @time :2025/5/8 14:59
  227 + */
  228 + public function saveMysql($project_id,$size,$image_type,$path,$mime = ''){
  229 + $hash = md5($path);
  230 + $imageModel = new Image();
  231 + $info = $imageModel->read(['hash'=>$hash,'project_id'=>$project_id]);
  232 + $data = [
  233 + 'path' => $path,
  234 + 'size' => $size,
  235 + 'hash' => $hash,
  236 + 'type' => $image_type,
  237 + 'refer'=> 0,
  238 + 'mime' => $mime,
  239 + 'project_id'=>$project_id,
  240 + 'name'=>basename($path),
  241 + 'en_name'=>basename($path)
  242 + ];
  243 + if($info === false){
  244 + $imageModel->addReturnId($data);
  245 + }else{
  246 + $imageModel->edit($data,['id'=>$info['id']]);
  247 + }
  248 + return true;
  249 + }
  250 +
  251 + /**
  252 + * @remark :记录日志
  253 + * @name :output
  254 + * @author :lyh
  255 + * @method :post
  256 + * @time :2025/5/8 9:57
  257 + */
  258 + public function output($message, $log_file = 'logs/crop_image.log')
  259 + {
  260 + $message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
  261 + echo $message;
  262 + file_put_contents(storage_path($log_file), $message, FILE_APPEND);
  263 + return true;
  264 + }
  265 +}
@@ -82,8 +82,8 @@ class AiBlogController extends BaseController @@ -82,8 +82,8 @@ class AiBlogController extends BaseController
82 * @method :post 82 * @method :post
83 * @time :2023/7/5 14:33 83 * @time :2023/7/5 14:33
84 */ 84 */
85 - public function save(AiBlogRequest $aiBlogRequest,AiBlogLogic $aiBlogLogic){  
86 - $aiBlogRequest->validated(); 85 + public function save(AiBlogLogic $aiBlogLogic){
  86 +// $aiBlogRequest->validated();
87 $aiBlogLogic->blogSave(); 87 $aiBlogLogic->blogSave();
88 $this->response('success'); 88 $this->response('success');
89 } 89 }
@@ -312,4 +312,70 @@ class CosService @@ -312,4 +312,70 @@ class CosService
312 'HelveticaNeue.dfont' 312 'HelveticaNeue.dfont'
313 ]; 313 ];
314 } 314 }
  315 +
  316 + /**
  317 + * @remark :获取cos图片高度
  318 + * @name :getImageHeight
  319 + * @author :lyh
  320 + * @method :post
  321 + * @time :2025/5/8 10:58
  322 + * @param :pathUrl->存储桶相对路径
  323 + */
  324 + public function getImageHeight($pathUrl){
  325 + $cos = config('filesystems.disks.cos');
  326 + $url = 'https://' . $cos['bucket'] . '.cos.' . $cos['region'] . '.myqcloud.com/' . ltrim($pathUrl, '/') . '?image/info';
  327 + $imageInfo = @getimagesize($url);
  328 + if ($imageInfo) {
  329 +// $width = $imageInfo[0];
  330 + $height = $imageInfo[1];
  331 + return $height;
  332 + }
  333 + return '';
  334 + }
  335 +
  336 + /**
  337 + * @remark :裁剪图片
  338 + * @name :cropCosImage
  339 + * @author :lyh
  340 + * @method :post
  341 + * @time :2025/5/8 11:06
  342 + */
  343 + public function cropCosImage($cosUrl,$height = 220)
  344 + {
  345 + $cos = config('filesystems.disks.cos');
  346 + $cosClient = new Client([
  347 + 'region' => $cos['region'],
  348 + 'credentials' => [
  349 + 'secretId' => $cos['credentials']['secretId'],
  350 + 'secretKey' => $cos['credentials']['secretKey'],
  351 + ],
  352 + ]);
  353 + $pathInfo = pathinfo($cosUrl);
  354 + $newKey = $pathInfo['dirname'] . '/crop_' . $pathInfo['filename'] .'.'. $pathInfo['extension'];
  355 + $operations = [
  356 + 'is_pic_info' => 0,
  357 + 'rules' => [
  358 + [
  359 + // 注意 fileid 要 base64 编码,并与 Key 相同才能覆盖
  360 + 'fileid' => $newKey,
  361 + 'rule' => 'imageMogr2/crop/x'.$height.'/gravity/center'
  362 + ]
  363 + ]
  364 + ];
  365 + // 执行裁剪并覆盖
  366 + $res = $cosClient->ImageProcess([
  367 + 'Bucket' => $cos['bucket'],
  368 + 'Key' => $cosUrl, // 要处理的对象路径
  369 + 'PicOperations' => json_encode($operations),
  370 + ]);
  371 + if($res){
  372 + return [
  373 + 'path' => '/'.$res['ProcessResults']['Object'][0]['Key'] ?? '',
  374 + 'size' => (int)$res['ProcessResults']['Object'][0]['Size'] ?? 0,
  375 + 'mime' => 'image/'.($res['ProcessResults']['Object'][0]['Format'] ?? 'jpg'),
  376 + 'type' => $res['ProcessResults']['Object'][0]['Format'] ?? 'jpg',
  377 + ];
  378 + }
  379 + return [];
  380 + }
315 } 381 }