清风博客 https://www.skyfinder.cc 关注IT世界,记录平凡生活 Sun, 09 May 2021 11:17:53 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.7.1 网站被恶意镜像的简单快速处理方法 https://www.skyfinder.cc/2021/05/02/mirror-site/ https://www.skyfinder.cc/2021/05/02/mirror-site/#respond Sun, 02 May 2021 15:08:28 +0000 https://www.skyfinder.cc/?p=3457 背景

站点网上飘,哪有不挨刀。总是遇到千奇百怪的问题,让人猝不及防。在51日的前一天,发现博客被人镜像了,这是一个非常糟心的问题,我非常肯定的是这次的镜像不怀好意。为什么我会这么说呢?因为镜像站点域名太不像话了,太长了,有没有特殊的含义,所以我认为这种镜像网站是非常有恶意的。如下图:

镜像站点域名

JavaScript简单紧急处理

这种恶意的镜像站点无法绝对的杜绝,只能尽可能的减小影响。此次处理非常简单,直接使用Javascript对当前域名进行判断,与指定域名不符就跳转回指定的域名。

版本一


var local=window.location.host;
if(local.indexOf("skyfinder.cc")==-1){
   location.href = location.href.replace(local,"skyfinder.cc");
}

版本二

为了更好的预防其简单替换域名,将我们对比的域名的各个字符ASCII码保存起来,通过转换重新组合为域名后再与当前host进行对比,不同则需要跳转原站点,反之则不需要任何的操作。


var local=window.location.host;
var myHost=[115,107,121,102,105,110,100,101,114,46,99,99];
var myurl=[];
for(var item in myHost){
   myurl.push(String.fromCharCode(myHost[item]));
}
if(local.indexOf(myurl.join(""))==-1){
   location.href = location.href.replace(local,myurl.join(""));
}

版本三

这个版本是使用以上其他版本对Javascript代码进行混淆的,希望这种方式使他们的操作增加更多的工作量。



var I1=window['\x6c\x6f\x63\x61\x74\x69\x6f\x6e']['\x68\x6f\x73\x74'];var sRPPOUO2=[115,107,121,102,105,110,100,101,114,46,99,99];var dzhW$3=[];for(var tMYXRE4 in sRPPOUO2){dzhW$3['\x70\x75\x73\x68'](window["\x53\x74\x72\x69\x6e\x67"]['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](sRPPOUO2[tMYXRE4]))}if(I1['\x69\x6e\x64\x65\x78\x4f\x66'](dzhW$3['\x6a\x6f\x69\x6e'](""))==-1){window['\x6c\x6f\x63\x61\x74\x69\x6f\x6e']['\x68\x72\x65\x66']['\x72\x65\x70\x6c\x61\x63\x65']();location['\x68\x72\x65\x66']=location['\x68\x72\x65\x66']['\x72\x65\x70\x6c\x61\x63\x65'](I1,dzhW$3['\x6a\x6f\x69\x6e'](""))}

效果展示

封禁IP

第一步 获取镜像站点的IP

新建一个php文件,将以下代码复制到文件中并命名为“ip.php”上传到网站根目录。


<?php
$file = "ip.txt";//保存的文件名
$ip = $_SERVER['REMOTE_ADDR'];
$handle =fopen($file,'a');
fwrite($handle,"IP Address:");
fwrite($handle,"$ip");
fwrite($handle,"\n");
fclose($handele);
?>

第二步 访问获取镜像站点地址

访问镜像站点,在镜像域名地址后面加ip.php,然后就会在自己网站根目录找到ip.txt文件了,打开复制里面的ip地址。

添加恶意镜像站点IP.htaccess

使用Deny from来将指定的IP加入黑名单,如下所示


#AIOWPS_IP_BLACKLIST_START
<IfModule !mod_authz_core.c>
Order allow,deny
Allow from all
Deny from 112.213.97.64
Deny from 37.187.78.50
Deny from 47.90.76.5
Deny from 5.188.0.0/16
Deny from 61.160.232.95
Deny from 61.160.232.94
Deny from 125.77.16.108
</IfModule>
<IfModule mod_authz_core.c>
<RequireAll>
Require all granted
Require not ip 112.213.97.64
Require not ip 37.187.78.50
Require not ip 47.90.76.5
Require not ip 5.188.0.0/16
Require not 61.160.232.95
Require not 61.160.232.94
Require not ip 125.77.16.108
</RequireAll>
</IfModule>
#AIOWPS_IP_BLACKLIST_END

将指定IP加入黑名单后,刷新镜像站点后显示403被禁止访问。使用这种方式需要维护黑名单列表,如果有新的镜像站点就继续要添加记录。

结语

我个人十分难以理解这种行为,个人博客而已,只是记录点生活的一些琐事、工作中的一些问题处理以及学习中的一些疑问。镜像一个没有商业价值的个人博客,真的值得吗?

关于其他解决恶意镜像站点的方法,以后在寻找。目前仅使用Javascript来做最简单快速的方法。

转载请注明:清风博客 » 网站被恶意镜像的简单快速处理方法

]]>
https://www.skyfinder.cc/2021/05/02/mirror-site/feed/ 0
Linux快速回收连接TIME-WAIT的连接 https://www.skyfinder.cc/2021/04/21/linuxtime-wait-recovery/ https://www.skyfinder.cc/2021/04/21/linuxtime-wait-recovery/#respond Wed, 21 Apr 2021 03:49:28 +0000 https://www.skyfinder.cc/?p=3448 发现Centos系统中出现了很多 TIME-WAIT的空闲连接,连接资源感觉即将耗尽,并且这些TIME-WAIT释放缓慢。

配置修改


vi /etc/sysctl.conf

编辑文件,加入以下内容:


# 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1

# 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1

# 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_tw_recycle = 1

# 修改系統默认的TIMEOUT时间
net.ipv4.tcp_fin_timeout = 30 

执行以下指令,让新增的配置生效.


/sbin/sysctl -p

完成修改之后,使用以下命令查看TIME_WAIT连接数


netstat -ant |grep “TIME_WAIT” |wc -l

转载请注明:清风博客 » Linux快速回收连接TIME-WAIT的连接

]]>
https://www.skyfinder.cc/2021/04/21/linuxtime-wait-recovery/feed/ 0
Docker容器在Centos使用脚本查看日志与清理 https://www.skyfinder.cc/2021/04/10/dockercentoslogclear/ https://www.skyfinder.cc/2021/04/10/dockercentoslogclear/#respond Sat, 10 Apr 2021 05:04:36 +0000 https://www.skyfinder.cc/?p=3425 背景

jenkins突然无法自动构建镜像,经过确认并非是无法构建,而是磁盘空间满了。 关于手动清理Docker日志的方法,自己曾经也处理过,但是容器多起来就相当麻烦。

linux上,容器日志一般存放在/var/lib/docker/containers/container_id/下面, 以json.log结尾的文件.

查看


#!/bin/sh
echo "======== docker containers logs file size ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
ls -lh $log
done

清理


#!/bin/sh
echo "======== start clean docker containers logs ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done
echo "======== end clean docker containers logs ========"

限制Docker容器日志大小

全局设置

新建/etc/docker/daemon.json,若是存在编辑即可。添加log-dirverlog-opts参数,示例如下:


# vim /etc/docker/daemon.json
{
  "log-driver":"json-file",
  "log-opts": {"max-size":"500m", "max-file":"3"}
}

max-size设置日志文件的大小的上线,max-file一个容器有多少个日志。

设置的日志大小,只对新建的容器有效.

// 重启docker守护进程
systemctl daemon-reload
systemctl restart docker

单个容器设置

通过配置容器docker-composemax-size选项来实现。


  consul-server-bootstrap:
    container_name: consul-server-bootstrap
    image: consul:latest
    logging: 
      driver: “json-file” 
      options: 
        max-size: “5g”

重新使用docker-compose运行即可完成最后设置。

转载请注明:清风博客 » Docker容器在Centos使用脚本查看日志与清理

]]>
https://www.skyfinder.cc/2021/04/10/dockercentoslogclear/feed/ 0
删除Docker中为none的Image/镜像 https://www.skyfinder.cc/2021/04/08/dockernoneimagermove/ https://www.skyfinder.cc/2021/04/08/dockernoneimagermove/#respond Thu, 08 Apr 2021 15:26:45 +0000 https://www.skyfinder.cc/?p=3422 docker build 或是 pull 命令就会产生临时镜像。


//删除无效的临时镜像
docker rmi $(docker images -f "dangling=true" -q)

其他方法

停止容器


docker stop $(docker ps -a | grep "Exited" | awk '{print $1 }')

删除容器


docker rm $(docker ps -a | grep "Exited" | awk '{print $1 }')

删除镜像


docker rmi $(docker images | grep "none" | awk '{print $3}')

转载请注明:清风博客 » 删除Docker中为none的Image/镜像

]]>
https://www.skyfinder.cc/2021/04/08/dockernoneimagermove/feed/ 0
WordPress博客Gravatar头像无法显示问题 https://www.skyfinder.cc/2021/04/04/wordpress-gravatar/ https://www.skyfinder.cc/2021/04/04/wordpress-gravatar/#respond Sat, 03 Apr 2021 18:10:34 +0000 https://www.skyfinder.cc/?p=3412

Gravatar

Gravatar,全称Globally Recognized Avatar。翻译成中文为全球通用头像

Gravatar的概念首先是在国外的独立WordPress博客中兴起的,当你到任何一个支持Gravatar的网站留言时,这个网站都会根据你所提供的Email地址为你显示出匹配的头像。当然,这个头像,是需要你事先到Gravatar的网站注册并上传的,否则,在这个网站上,就只会显示成一个默认的头像。

注册使用

使用该服务时需要去官网中注册一个账号,并上传头像。

注意头像上传后会审核,然后管理员会按图片包含的内容划分一个等级(G 普通级、PG 辅导级、R 和 X 为限制级)。通过之后这个头像就可以使用了。在任何支持Gravatar的地方,在评论填写email地址时,请填写你申请注册头像用的这个email地址。你的头像就会出现在留言中。

网站调用

本博客使用的是WordPress,突然发现Gravatar头像已经无法显示了,成了裂图。经过证实链接被阻断了,所以无法显示。打开当前主题中functions.php文件进行编辑,新增以下代码并保存更新。


//v2ex国内gravatar头像缓存
function get_ssl_avatar($avatar){ 
	$avatar = preg_replace('/.*\/avatar\/(.*)\?s=([\d]+)&.*/','<img src="https://cdn.v2ex.com/gravatar/$1?s=$2" class="avatar avatar-$2" height="50px" width="50px">',$avatar);
	return $avatar; 
} 
add_filter('get_avatar', 'get_ssl_avatar');

如果您的WordPress网站中没用使用Gravatar头像功能,则没用任何影响.

Gravatar镜像源

本来博客中gravatar不可以使用,改为v2ex镜像一段时间后又重新不可以使用,只能继续找其他镜像来替代,以下是通过互联网收集一些支持gravatar的一些镜像.

官方的www  https://www.gravatar.com/avatar/

官方的en  https://en.gravatar.com/avatar/

官方的cn  https://cn.gravatar.com/avatar/

官方的secure  https://secure.gravatar.com/avatar/

V2EX  https://cdn.v2ex.com/gravatar/

Loli  https://gravatar.loli.net/avatar/

极客族  https://sdn.geekzu.org/avatar/

zeruns’s Blog https://gravatar.zeruns.tech/avatar/

转载请注明:清风博客 » WordPress博客Gravatar头像无法显示问题

]]>
https://www.skyfinder.cc/2021/04/04/wordpress-gravatar/feed/ 0
移除.net解决方案中TFS的绑定控制 https://www.skyfinder.cc/2021/03/26/removenetcodetfs/ https://www.skyfinder.cc/2021/03/26/removenetcodetfs/#respond Fri, 26 Mar 2021 11:23:56 +0000 https://www.skyfinder.cc/?p=3396 TFS与解决方案绑定信息清理

tfs与解决方案之间有相关信息需要清理,以下是相关的清理步骤。

删除关联文件以及文件夹

删除项目目录下所有的*.vssscc*.vspscc为后缀的文件,删除隐藏文件夹$tf

修改项目的解决方案文件

在目录中找到以*.sln为后缀名的解决方案文件,打开文件进行编辑。删除TeamFoundationVersionControl所在的整块内容并保存。

GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 2
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http:///tfs/defaultcollection
SccLocalPath0 = .
SccProjectUniqueName1 = .csproj
//Scc……
EndGlobalSection

修改项目文件

在项目目录中,找到以*.csproj为后缀的项目文件,打开进行编辑。

删除<SccProjectName><SccLocalPath><SccAuxPath><SccProvider>这四个节点。

代码实现

为了方便以后使用,所以这里使用.net 5 写一个小工具来清理这些TFS绑定信息。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DisassociateSourceCodeManagementTFS
{
    public partial class DisassociateTFS : Form
    {
        
        public DisassociateTFS()
        {
            InitializeComponent();
        }
        private void btnDisassociateTFS_Click(object sender, EventArgs e)
        {
            string path = txtSourceFolder.Text;
            if (string.IsNullOrWhiteSpace(path))
            {
                MessageBox.Show("请选择需要解除TFS绑定的源码目录","提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
                return;
            }
            if (!Directory.Exists(path))
            {
                return;
            }
            btnDisassociateTFS.Enabled = false;
            var vssscc = Directory.EnumerateFiles(path, "*.vssscc", SearchOption.AllDirectories);
            var vspscc = Directory.EnumerateFiles(path, "*.vspscc", SearchOption.AllDirectories);
            DeleteFolderOrFiles(vssscc);
            DeleteFolderOrFiles(vspscc);
            var sln = Directory.EnumerateFiles(path, "*.sln", SearchOption.AllDirectories);
            RewriteFileContent(sln,(item)=> { 
               return Regex.Replace(item, @"GlobalSection\(TeamFoundationVersionControl\)[\s\S]+?EndGlobalSection", "");
            });
            var csproj = Directory.EnumerateFiles(path, "*.csproj", SearchOption.AllDirectories);
            RewriteFileContent(csproj, (item) => {
                item = Regex.Replace(item, @"<SccProjectName>.+?</SccProjectName>", "");
                item = Regex.Replace(item, @"<SccLocalPath>.+?</SccLocalPath>", "");
                item = Regex.Replace(item, @"<SccAuxPath>.+?</SccAuxPath>", "");
                item = Regex.Replace(item, @"<SccProvider>.+?</SccProvider>", "");
                return item;
            });
            var tf = Directory.EnumerateDirectories(path, "$tf", SearchOption.AllDirectories);
            DeleteFolderOrFiles(tf);
            btnDisassociateTFS.Enabled = true;
            MessageBox.Show("解除TFS绑定的源码目录成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void DeleteFolderOrFiles(IEnumerable<string> files)
        {
            if (files == null)
            {
                return;
            }
            foreach (var item in files)
            {
                if (File.Exists(item))
                {
                    File.Delete(item);
                    continue;
                }
                if (Directory.Exists(item))
                {
                    Directory.Delete(item, true);
                }
            }
        }
        private void RewriteFileContent(IEnumerable<string> files,Func<string,string> contentOperation)
        {
            foreach (var item in files)
            {
                if (!File.Exists(item))
                {
                    continue;
                }
                Encoding textEncoding = GetFileEncodeType(item);
                StreamReader reader = new StreamReader(item, textEncoding);
                string fileContent = reader.ReadToEnd();
                reader?.Close();
                reader?.Dispose();
                if (contentOperation != null)
                {
                    fileContent = contentOperation(fileContent);
                }
                StreamWriter writer = new StreamWriter(item, false, textEncoding);
                writer.Write(fileContent);
                writer.Flush();
                writer?.Close();
                writer?.Dispose();
            }
        }
        /// <summary>
        /// 获取指定文件的编码
        /// 以防止在不知道文件编码格式的情况下处理文件而造成的乱码问题
        /// </summary>
        /// <param name="filename">文件路径</param>
        /// <returns></returns>
        private System.Text.Encoding GetFileEncodeType(string filename)
        {
            if (!File.Exists(filename))
            {
                return System.Text.Encoding.Default;
            }
            System.Text.Encoding ReturnReturn = null;
            System.IO.FileStream fs = null;
            System.IO.BinaryReader br = null;
            try
            {
                fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                br = new System.IO.BinaryReader(fs);
                byte[] buffer = br.ReadBytes(2);
                if (buffer.Length > 0 && buffer[0] >= 0xEF)
                {
                    if (buffer[0] == 0xEF && buffer[1] == 0xBB)
                    {
                        ReturnReturn = System.Text.Encoding.UTF8;
                    }
                    else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
                    {
                        ReturnReturn = System.Text.Encoding.BigEndianUnicode;
                    }
                    else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
                    {
                        ReturnReturn = System.Text.Encoding.Unicode;
                    }
                    else
                    {
                        ReturnReturn = System.Text.Encoding.Default;
                    }
                }
                else if (buffer.Length > 0 && buffer[0] == 0xe4 && buffer[1] == 0xbd) //无BOM的UTF-8 
                {
                    ReturnReturn = System.Text.Encoding.UTF8;
                }
                else
                {
                    ReturnReturn = System.Text.Encoding.Default;
                }
            }
            catch
            {
                ReturnReturn = System.Text.Encoding.Default;
            }
            finally
            {
                br?.Close();
                fs?.Close();
                fs?.Dispose();
            }
            return ReturnReturn;
        }
        private void btnOpenFloder_Click(object sender, EventArgs e)
        {
            if (fbdFolderSelect.ShowDialog() == DialogResult.OK)
            {
                txtSourceFolder.Text = fbdFolderSelect.SelectedPath;
            }
        }
        private void txtSourceFolder_DragDrop(object sender, DragEventArgs e)
        {
            string path = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            if (File.Exists(path))
            {
                FileInfo fileInfo = new FileInfo(path);
                path=fileInfo.DirectoryName;
            }
            txtSourceFolder.Text = path;
        }
        private void txtSourceFolder_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.All;//重要代码:表明是所有类型的数据,比如文件路径
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }

        }
    }
}

示例下载

解除解决方案与TFS绑定
以上示例请使用Microsoft Visual Studio 2019 打开

转载请注明:清风博客 » 移除.net解决方案中TFS的绑定控制

]]>
https://www.skyfinder.cc/2021/03/26/removenetcodetfs/feed/ 0
博客园整改 https://www.skyfinder.cc/2021/03/21/cnblogs-rectify/ https://www.skyfinder.cc/2021/03/21/cnblogs-rectify/#respond Sun, 21 Mar 2021 04:46:26 +0000 https://www.skyfinder.cc/?p=3391 博客园是国内最出名的IT从业者的技术交流社区。

博客园是一个面向开发者的知识分享社区。自创建以来,博客园一直致力并专注于为开发者打造一个纯净的技术交流社区,推动并帮助开发者通过互联网分享知识,从而让更多开发者从中受益。博客园的使命是帮助开发者用代码改变世界。

不知为何,浏览博客园任何帖子都会跳转到整改公告,具体整改原因不详!也不晓得哪里违规了!不管怎么样,希望尽快完成整改,合规合法运营!

为了遵守相关法律法规,合法合规运营,网站进行全面整改,整改工作于2021年3月18日12:00开始,预计于3月25日11:59结束,整改期间全站无法发布任何内容,之前发布的内容重新审核后才能访问,由此给您带来很大的麻烦,请您谅解。

转载请注明:清风博客 » 博客园整改

]]>
https://www.skyfinder.cc/2021/03/21/cnblogs-rectify/feed/ 0
关于HOST文件中出现不明网址记录 https://www.skyfinder.cc/2021/03/15/microdone-cn/ https://www.skyfinder.cc/2021/03/15/microdone-cn/#respond Mon, 15 Mar 2021 04:33:11 +0000 https://www.skyfinder.cc/?p=3376 因局域网源代码管理服务器地址做了变更,所以就重新更改下HOST文件中的IP地址。意外发现HOST文件中多了一条记录,而我对这条记录竟然没有一点印象。好奇怪!!!!哪来的呢?172.17.187.161 windows10.microdone.cn,其中IP172.17.187.161又是本地局域网。然后就通过浏览器尝试访问域名windows10.microdone.cn,结果根本无法连接,最后尝试了顶级域microdone.cn,这下就出现了内容。如下图所示:

我仔细回忆一下,自己最近几天究竟做了什么,好像也没有做什么呀!于是,我就在控制面板中打开程序和功能查看一下。最近几个月的程序安装记录,由安装时间来看,也没有太多内容。如下图所示:

我结合之前打开域名microdone.cn来看,这条HOST记录必然和中国邮政储蓄银行网上银行安全控件有关。看到了此记录,也逐渐想起自己的确安装过这个控件。既然现在用不到这个网上银行,就索性把它给卸载吧。最后,把HOST文件的那条记录也删除。我很疑惑为什么会有这种行为,一些开发人员总是搞些千奇百怪的事情,也不晓得意图是什么。

转载请注明:清风博客 » 关于HOST文件中出现不明网址记录

]]>
https://www.skyfinder.cc/2021/03/15/microdone-cn/feed/ 0
深圳龙华清湖春季车展 https://www.skyfinder.cc/2021/03/13/shenzhenlonghuaicocarshow/ https://www.skyfinder.cc/2021/03/13/shenzhenlonghuaicocarshow/#respond Sat, 13 Mar 2021 15:37:58 +0000 https://www.skyfinder.cc/?p=3366 突然,有一种念想,想买一辆代步车。所以,关注了一些车展的相关消息。春季车展还是不少的,其3月4日至7日宝安体育馆,13日至14日深圳市龙华星河iCO广场都有相关车展的活动。这前后两次的车展活动规模都相对较小,品牌以及车型都不是很多。今天让人意想不到的的是,这小小的车展活动竟然会请车模。没有错,有车模,不过仅仅只有两个车模。车展活动的车我都已经看一遍了,各个品牌车的价格都不算贵,但是我还是没有订购。我觉得还是要多了解下,要不然总感觉太草率了!车没拍,车模拍了几张。

转载请注明:清风博客 » 深圳龙华清湖春季车展

]]>
https://www.skyfinder.cc/2021/03/13/shenzhenlonghuaicocarshow/feed/ 0
可以在线浏览PDF的一个WEB标准插件PDF.js https://www.skyfinder.cc/2021/03/01/pdfwebpdf-js/ https://www.skyfinder.cc/2021/03/01/pdfwebpdf-js/#respond Mon, 01 Mar 2021 07:08:00 +0000 https://www.skyfinder.cc/?p=3359 背景

因有一个需求,需要在线浏览PDF文件。所以,需要找一个满足需求的解决方案。经过一些列资料搜寻,最终确定使用PDF.js插件。目前来说此插件完美满足需求。

PDF.js

一个通用的、基于web标准的、用于解析和呈现pdf的平台。

PDF.js项目在线预览效果

转载请注明:清风博客 » 可以在线浏览PDF的一个WEB标准插件PDF.js

]]>
https://www.skyfinder.cc/2021/03/01/pdfwebpdf-js/feed/ 0
急性上呼吸道感染 https://www.skyfinder.cc/2021/01/14/influenza/ https://www.skyfinder.cc/2021/01/14/influenza/#respond Thu, 14 Jan 2021 04:42:51 +0000 https://www.skyfinder.cc/?p=3341

最近天气突然骤降,一不小心就生病了,鼻塞、流鼻涕实在难受,随即而来的就是鼻炎复发以及中耳炎。每一次都是这个流程,每一次感冒没有千把块就摆不平,总有一天死在这个上面,也说不准。哎!

急性上呼吸道感染

急性上呼吸道感染,俗称“感冒”主要是指鼻咽和咽部的急性感染。本病是常见的疾病,常诊断为“急性鼻咽炎”、“急性咽炎”、“急性扁桃体炎”等。该病一年四季均可发生,以冬、春季节及气候骤变时多见。

  • 患病期间好好休息、充足睡眠、忌劳累、忌锻炼身体,以保持体力,有利于康复。
  • 多喝水,吃清淡、富含维生素、易消化的食物,如:米汤,豆浆、粥、面条、鸡蛋羹等半流质食物及新鲜蔬菜、水果,忌食油腻、煎炸的食物。
  • 房间经常通风换气,保持适宜的温度,在家里尽量做到床边隔离,避免再传染给他人。
  • 预防胜于治疗:避免受凉、淋雨、过度疲劳;避免与感冒患者接触,避免脏手接触口、眼、鼻。年老体弱易感者更应注意防护,上呼吸道感染流行时应戴口罩,避免在人多的公共场合出入。平时加强体质锻炼、增强抗病能力。必要时注射疫苗。

在医生的指导下用药,切记乱用药,由于上呼吸道感染大多数由病毒引起,一般不必应用抗生素,更不必输液。

转载请注明:清风博客 » 急性上呼吸道感染

]]>
https://www.skyfinder.cc/2021/01/14/influenza/feed/ 0
Visual Studio(VS) Code提示php.executablePath配置问题 https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/ https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/#respond Thu, 07 Jan 2021 03:22:29 +0000 https://www.skyfinder.cc/?p=3334 Visual Studio Code 安装php插件后提示:

PHP executable not found. Install PHP 7 and add it to your PATH or set the php.executablePath setting

打开VS Code设置查找到php.validate.executablePath进行修改,其值是php安装目录。


{
    "editor.suggestSelection": "first",
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "java.semanticHighlighting.enabled": true,
    "php.validate.executablePath": "F:\\phpstudy_pro\\Extensions\\php\\php7.3.4nts"
}

转载请注明:清风博客 » Visual Studio(VS) Code提示php.executablePath配置问题

]]>
https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/feed/ 0
ASP.NET Core Web Api实现大文件切/分片上传 https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/ https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/#respond Thu, 31 Dec 2020 08:15:58 +0000 https://www.skyfinder.cc/?p=3313 一年前的一个项目,有人反馈上传超时,超时原因是文件大小超出限制。由于原来维护项目的人员离开,现在上传超时的问题就有我来处理。解决方案也比较简单,就是切片上传。前端不想自己写了,就利用了上传组件,这个上传组件是百度WebUploaderWebUploader这个组件被使用的也比较广泛,为了省事就用它啦!

上传中

合并后

代码实现

前端代码

前端上传以及分片使用的百度上传组件WebUploader


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Home Page - WebUpload</title>

    
        <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
    
    
    <link rel="stylesheet" href="/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" href="/">WebUpload</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/Home/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        


        <main role="main" class="pb-3">
            <link rel="stylesheet" type="text/css" href="/webuploader/webuploader.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script src="/webuploader/webuploader.js"></script>
    <div class="text-center">
        <h1 class="display-4">Welcome</h1>
        <div id="uploader" class="wu-example">
            <div class="container-fluid">
                <div class="col-md-10">
                    <div class="row">文件上传示例:</div>
                    <div class="row">
                        <div id="uploader" class="wu-example">
                            <!--用来存放文件信息-->
                            <div id="fileList" class="uploader-list"></div>
                            <div class="btns">
                                <div id="picker" class="btn btn-primary">选择文件</div>

                            </div>

                        </div>
                    </div>

                    <div class="row">

                    </div>
                    <div class="row">  <button id="ctlBtn" class="btn btn-default">开始上传</button></div>
                </div>
                <div>
                </div>
            </div>
        </div>
        <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    </div>
<script>
    jQuery(function () {
        var $ = jQuery,
            $list = $('#fileList'),
            $btn = $('#ctlBtn'),
            state = 'pending',
            uploader, guid = {};
        uploader = WebUploader.create({
            // 不压缩image
            resize: false,

            // swf文件路径
            swf: "~/webuploader/Uploader.swf",

            server: 'http://localhost:8011/api/File/UplaodFile?isConvert=true',

            // 选择文件的按钮。可选。
            // 内部根据当前运行是创建,可能是input元素,也可能是flash.
            pick: '#picker',
            chunked: true

        });
        
        // 当有文件添加进来的时候
        uploader.on('fileQueued', function (file) {
            guid[file.id] = +(new Date());
            $list.append('<div id="' + file.id + '" class="item">' +
                '<h4 class="info">' + file.name + '</h4>' +
                '<p class="state">等待上传...</p>' +
                '</div>');
            uploader
                .md5File(file)
                .progress(function (percentage) {
                    // console.log("Percentage:", percentage);
                    $("#ctlBtn").hide();
                })
                // MD5计算完毕,可以点击上传了
                .then(function (fileMd5) {
                    file.fileMd5 = fileMd5;
                    $("#ctlBtn").show()
                    console.log(fileMd5);
                });

        });
        uploader.on('uploadBeforeSend', function (file, data, headers) {
            $.extend(data, { "fileId": guid[data.id], "fileMd5": file.file.fileMd5 });
            $.extend(headers, {
                "Authorization":"Bearer "
            });
            if (data.chunks) {
                data["chunkStart"] = file.start;
                data["chunkEnd"] = file.end;
            }
        });
        // 文件上传过程中创建进度条实时显示。
        uploader.on('uploadProgress', function (file, percentage) {

            var $li = $('#' + file.id),
                $percent = $li.find('.progress .progress-bar');
            // 避免重复创建
            if (!$percent.length) {
                $percent = $('<div class="progress progress-striped active">' +
                    '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                    '</div>' +
                    '</div>').appendTo($li).find('.progress-bar');
            }
            $li.find('p.state').text('上传中');
            $percent.css('width', percentage * 100 + '%');

        });

        uploader.on('uploadSuccess', function (file) {
            $('#' + file.id).find('p.state').text('已上传');
        });

        uploader.on('uploadError', function (file) {
            $('#' + file.id).find('p.state').text('上传出错');
        });

        uploader.on('uploadComplete', function (file) {
            $('#' + file.id).find('.progress').fadeOut();
        });
        uploader.on('all', function (type) {
            if (type === 'startUpload') {
                state = 'uploading';
            } else if (type === 'stopUpload') {
                state = 'paused';
            } else if (type === 'uploadFinished') {
                state = 'done';
            }
            if (state === 'uploading') {
                $btn.text('暂停上传');
            } else {
                $btn.text('开始上传');
            }

        });

        $btn.on('click', function () {
            if (state === 'uploading') {
                uploader.stop();
            } else {
                uploader.upload();
            }
        });
    });
</script>

        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - WebUpload - <a href="/Home/Privacy">Privacy</a>
        </div>
    </footer>

    
        <script src="/lib/jquery/dist/jquery.js"></script>
        <script src="/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    
    
    <script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>

    
</body>
</html>

后台实现

后台使用的是ASP .NET Core Web API,实现方式也很简单。文件的校验,分块的校验等这里就省略了。
    
    [Route("api/[controller]")]
    public class FileController : Controller
    {
        public static readonly object locker = new object();
        [HttpPost]
        [Route("UplaodFile")]
        public IActionResult UplaodFile([FromForm] IFormCollection form)
        {
            try
            {
                string fileId = form["fileId"];
                if (string.IsNullOrWhiteSpace(fileId)||form.Files==null||form.Files.Count==0)
                {
                    return BadRequest();
                }
                string tempFileFolder = Path.Combine(AppContext.BaseDirectory, $"FileUploader/{fileId}");
                CreateFolder(tempFileFolder);
                if (form.ContainsKey("chunks"))
                {
                    string chunksString = form["chunks"];
                    int chunks = int.Parse(chunksString);
                    string chunkString = form["chunk"];
                    int chunk = int.Parse(chunkString);
                    string sizeString = form["size"];
                    long size = long.Parse(sizeString);
                    string chunkStartString = form["chunkStart"];
                    string chunkEndString = form["chunkEnd"];
                    string chunkMd5 = form["chunkMd5"];
                    string fileMd5 = form["fileMd5"];
                    string lastModifiedDate = form["lastModifiedDate"];
                    var file = form.Files.FirstOrDefault();
                    string name = file.FileName;
                    string ext = Path.GetExtension(name);
                    Stream stream = file.OpenReadStream();
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    string factFilePath = Path.Combine(tempFileFolder, $"{name}");
                    string chunkFilePath = $"{factFilePath}.chunk{chunk}";
                    string chunkFileTempPath = $"{chunkFilePath}.temp";
                    System.IO.File.Delete(chunkFileTempPath);
                    FileStream fs = new FileStream(chunkFileTempPath, FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write(bytes);
                    bw.Flush();
                    bw.Close();
                    bw.Dispose();
                    fs.Close();
                    fs.Dispose();
                    stream.Close();
                    stream.Dispose();
                    System.IO.File.Move(chunkFileTempPath, chunkFilePath);
                    bool isMerge = true;
                    for (int i = 0; i < chunks; i++)
                    {
                        if (!System.IO.File.Exists($"{factFilePath}.chunk{i}"))
                        {
                            isMerge = false;
                            break;
                        }
                    }

                    if (isMerge)
                    {
                        lock (locker)
                        {
                            if (isMerge)
                            {
                                if (System.IO.File.Exists(factFilePath))
                                {
                                    return Ok();
                                }
                                var fileStream = new FileStream(factFilePath, FileMode.Create);
                                for (int i = 0; i < chunks; i++)
                                {
                                    string chunkFile = $"{factFilePath}.chunk{i}";
                                    var chunkBytes = System.IO.File.ReadAllBytes(chunkFile);
                                    fileStream.Write(chunkBytes, 0, chunkBytes.Length);
                                    fileStream.Flush();
                                    System.IO.File.Delete(chunkFile);//删除分块
                                }
                                fileStream.Close();
                                fileStream.Dispose();
                            }
                        }

                    }
                }
                else
                {
                    var file = form.Files.FirstOrDefault();
                    Stream stream = file.OpenReadStream();
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    FileStream fileStream = new FileStream(Path.Combine(tempFileFolder, $"{file.FileName}"), FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fileStream);
                    bw.Write(bytes);
                    bw.Flush();
                    bw.Close();
                    bw.Dispose();
                    fileStream.Close();
                    fileStream.Dispose();
                    stream.Close();
                    stream.Dispose();
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }

            return Ok();
        }
        private void CreateFolder(string folderPath)
        {
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
        }
        [HttpGet]
        [Route("Index")]
        public IActionResult Index()
        {
            return Ok();
        }
    }

示例下载

.NET CORE大文件分/切片上传示例

转载请注明:清风博客 » ASP.NET Core Web Api实现大文件切/分片上传

]]>
https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/feed/ 0
.NET操作达梦数据库编译错误处理 https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/ https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/#respond Mon, 07 Dec 2020 02:03:58 +0000 https://www.skyfinder.cc/?p=3279 由于客户突然要进行国产化的一个要求,数据库使用更换了国产达梦数据库,将数据由Oracle数据库迁移到达梦数据库。所以,之前基于Oracle处理的一些功能就需要进行一些调整。

使用NuGet 引入达梦数据提供器DmProvider 

引用相关的组件后,就按照套路对已经存在的方法进行相关调整,结果出现了一些编译出错且无论如何调整都无法消除。如下:

错误 CS1705 标识为“Dm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”的程序集“Dm”所使用的“System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”版本高于所引用的标识为“System.Runtime, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”的程序集“System.Runtime”

通过各种搜索引擎查找一通,最后也没有见到任何处理问题的方法。总觉得国产的某些东西,距大面积商用还有很远的距离。实在没有办法了,就到达梦官方把达梦数据库Windows开发版本下载下来,并加入达梦数据库官方QQ支持群,咨询关于.net framework 4.0的数据库驱动哪里有提供。

根据QQ群的信息回复,在安装目录找到了相关的组件并引用进行尝试,最终错误消失。

至于为什么Nuget上的会出现异常,也没有深入研究。感觉这没有意义!!

转载请注明:清风博客 » .NET操作达梦数据库编译错误处理

]]>
https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/feed/ 0
Linux无法访问外网问题 https://www.skyfinder.cc/2020/11/16/linux-net-work/ https://www.skyfinder.cc/2020/11/16/linux-net-work/#respond Mon, 16 Nov 2020 13:30:23 +0000 https://www.skyfinder.cc/?p=3239 一台Linux局域网服务器,突然发现不能访问外网,也许本来就不行,因为没有用到外网,所以只是没有注意到吧!经过测试外网无法访问,内网畅行无阻。如下:

[root@offline-200 services]# wget baidu.com
–2020-11-03 17:56:58– http://baidu.com/
正在解析主机 baidu.com (baidu.com)… 失败:未知的名称或服务。
wget: 无法解析主机地址 “baidu.com”

[root@offline-200 services]# ping 192.168.2.3
PING 192.168.2.3 (192.168.2.3) 56(84) bytes of data.
64 bytes from 192.168.2.3: icmp_seq=1 ttl=128 time=0.305 ms
64 bytes from 192.168.2.3: icmp_seq=2 ttl=128 time=0.245 ms
64 bytes from 192.168.2.3: icmp_seq=3 ttl=128 time=0.211 ms
64 bytes from 192.168.2.3: icmp_seq=4 ttl=128 time=0.255 ms
64 bytes from 192.168.2.3: icmp_seq=5 ttl=128 time=0.353 ms
— 192.168.2.3 ping statistics —
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.211/0.273/0.353/0.053 ms
[root@offline-200 services]# ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=255 time=1.39 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=255 time=1.47 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=255 time=1.43 ms
— 192.168.2.1 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.393/1.433/1.470/0.031 ms

首先,检查DNS服务器是否设置且是否设置正确。


cat  resolv.conf

如下所示,DNS只是一个局域网的服务器。具体之前为什么这么设置,现在也搞不清楚。

[root@offline-200 services]# cat /etc/resolv.conf
Generated by NetworkManager
search host.com
nameserver 192.168.2.200

不管之前是什么原因,现在使用vi进行编辑新加两个DNS服务器。

cat /etc/resolv.conf

#阿里DNS服务器

nameserver 223.5.5.5

nameserver 223.6.6.6

[root@offline-200 services]# vi /etc/resolv.conf
[root@offline-200 services]# cat /etc/resolv.conf
Generated by NetworkManager
search host.com
nameserver 192.168.2.200
nameserver 223.5.5.5
nameserver 223.6.6.6

新加DNS服务器之后保存,测试访问外网通过。

curl  www.baidu.com

转载请注明:清风博客 » Linux无法访问外网问题

]]>
https://www.skyfinder.cc/2020/11/16/linux-net-work/feed/ 0
.NET混淆加壳代码保护工具.NET Reactor最新版 https://www.skyfinder.cc/2020/11/10/netreactor/ https://www.skyfinder.cc/2020/11/10/netreactor/#respond Tue, 10 Nov 2020 14:52:29 +0000 https://www.skyfinder.cc/?p=3255

.NET Reactor是一款功能强大的代码保护以及许可授权管理系统软件,主要用于开发人员保护其.NET软件程序,.NET Reactor支持所有支持.NET编译的程序开发语言。.

.net Reactor功能介绍

.net Reactor设置说明

下载

.NET.Reactor 6.3 提取码:k5wr
压缩文件设置了解压密码:www.skyfinder.cc

转载请注明:清风博客 » .NET混淆加壳代码保护工具.NET Reactor最新版

]]>
https://www.skyfinder.cc/2020/11/10/netreactor/feed/ 0
.NET 使用MySql 8.0报caching_sha2_password错误的问题处理 https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/ https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/#respond Mon, 05 Oct 2020 13:41:04 +0000 https://www.skyfinder.cc/?p=3224 背景

接手别人项目进行维护,使用Mysql 8.0 数据库正确还原,但是项目却无法启动,经过调试发现以下问题。

MySqlException Authentication method ‘caching_sha2_password’ not supported by any of the available plugins。

通常的报这个错误是因为它的身份验证方式是 mysql_native_password ,不是caching_sha2_password导致。

Mysql 官方相关资料:https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html

解决方法

首先找到MySql 8.0 的安装目录,看一下是否存在my.ini配置文件,默认安装路径如下:

C:\Program Files\MySQL\MySQL Server 8.0

现在并没有发现my.ini配置文件,经过了解Mysql 8.0 安装后会将配置相关内容保存在以下目录中:

C:\ProgramData\MySQL\MySQL Server 8.0

打开my.ini配置文件并找到caching_sha2_password所在的行。

default_authentication_plugin=caching_sha2_password替换为default_authentication_plugin=mysql_native_password

操作完成后保存,然后重启mysql 8.0服务即可。

转载请注明:清风博客 » .NET 使用MySql 8.0报caching_sha2_password错误的问题处理

]]>
https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/feed/ 0
NET CORE将对象属性按照指定顺序输出 https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/ https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/#respond Tue, 08 Sep 2020 08:42:31 +0000 https://www.skyfinder.cc/?p=3194 背景

因业务需求,需要与第三方进行融合登录。第三方融合登录接口有关于验签的要求,将解密的数据按照规定的顺序进行MD5进行签名验证并与提供的MD5签名作为对比。其加密的明文是Json字符串,解密后还原后要按照URl参数的形式进行排列进行MD5签名。

规定

加密参数(注:加密参数名称均为小写字母,没有使用驼峰法命名)

名称类型默认值简介
sourceidString必传来源标识
targetidString必传目标标识
usercodeString必传用户唯一标识
usernameString用户姓名
idcardString身份证号码
phoneString手机号码
ounameString部门名称
timeString必传当前时间戳,精确到毫秒

签名数据采用以上面表格顺序以及以下格式进行字段拼接

sourceid=skyfinder&targetid=sky&usercode=100001&username=清风&idcard=110101199003074194&phone=16620927111&ouname=博客&time=1599539358

实现

创建一个自定义特性SortOrderAttribute,用来标识实体属性顺序与名称。


public class SortOrderAttribute: Attribute
 {
        public string Name { get; set; }

        public int Index { get; set; }

        public SortOrderAttribute(string name,int index)
        {
            Name = name;
            Index = index;
        }
    }

根据表格内容创建实体模型指定其排列顺序并通过方法GetUrIParameterString实现顺序输出内容。


public class PoliceStudiesUser
{
        /// <summary>
        /// 来源标识
        /// </summary>
        [SortOrder("来源标识",1)]
        public string sourceid { get; set; }
        /// <summary>
        /// 目标标识
        /// </summary>
        [SortOrder("来源标识", 2)]
        public string targetid { get; set; }
        /// <summary>
        /// 用户唯一标识
        /// </summary>
        [SortOrder("来源标识", 3)]
        public string usercode { get; set; }
        /// <summary>
        /// 用户姓名
        /// </summary>
        [SortOrder("来源标识", 4)]
        public string username { get; set; }
        /// <summary>
        /// 身份证号码
        /// </summary>
        [SortOrder("来源标识", 5)]
        public string idcard { get; set; }
        /// <summary>
        /// 手机号码
        /// </summary>
        [SortOrder("来源标识", 6)]
        public string phone { get; set; }
        /// <summary>
        /// 部门名称
        /// </summary>
        [SortOrder("来源标识", 7)]
        public string ouname { get; set; }

        /// <summary>
        /// 当前时间戳,精确到毫秒
        /// </summary>
        [SortOrder("来源标识", 8)]
        public string time { get; set; }

        public string GetUrIParameterString()
        {
            List<string> urlParameter = new List<string>();
            //foreach (PropertyInfo item in this.GetType().GetProperties().OrderBy(p => (p.GetCustomAttributes(true)[0] as SortOrderAttribute).Index).ToArray())
            Type type = this.GetType();
            var properties = type.GetProperties().OrderBy(p => (p.GetCustomAttributes(true)[0] as SortOrderAttribute).Index).ToArray();
            foreach (var item in properties)
            {
                string value = item.GetValue(this, null) == null ? "" : item.GetValue(this, null).ToString().Trim();
                if (string.IsNullOrWhiteSpace(value))
                {
                    continue;
                }
                urlParameter.Add($"{item.Name}={value}");
            }
            return string.Join("&",urlParameter);
        }
    }

调用测试

       

 static void Main(string[] args)
 {
            PoliceStudiesUser studiesUser = new PoliceStudiesUser() {
                sourceid="skyfinder",
                targetid="sky",
                idcard= "110101199003074194",
                usercode="100001",
                username="清风",
                ouname="博客",
                phone= "16620927111",
                time= "1599539358"
            };
            Console.WriteLine(studiesUser.GetUrIParameterString());
            Console.Read();
 }

示例下载

NET CORE指定顺序输出对象属性内容

转载请注明:清风博客 » NET CORE将对象属性按照指定顺序输出

]]>
https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/feed/ 0
推送Docker镜像被拒绝问题处理 https://www.skyfinder.cc/2020/09/04/docker-push-denied/ https://www.skyfinder.cc/2020/09/04/docker-push-denied/#respond Thu, 03 Sep 2020 16:00:00 +0000 https://www.skyfinder.cc/?p=3178 构建了自己常用的基础镜像,就打算推送到Docker Hub上。首先使用docker login 进行登录,然后就使用docker push 执行镜像推送,最后返回错误信息如下:

denied: requested access to the resource is denied

如下图:

在网上找了下相关信息,大部分都是说认证、登录等信息,按照相关信息试一试也没有什么用。最后发现是镜像名称不符合Docker规范,从而导致了镜像推送被拒绝。

推送的镜像命名规范如下:

登录名/镜像名称:标签

例如:

skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

如果现有的镜像名称不符合规范,可以使用tag打一个标签,如下:

docker tag skyfinder/microsoft/dotnet-2.1-aspnetcore-runtime-libgdiplus:1.0 skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

当镜像名称符合规范后,就可以使用docker push 来完成推送,如下:

docker push skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

至此也不会再有关于文章开头所描述的错误。

转载请注明:清风博客 » 推送Docker镜像被拒绝问题处理

]]>
https://www.skyfinder.cc/2020/09/04/docker-push-denied/feed/ 0
.NET CORE实现MD5加密 https://www.skyfinder.cc/2020/09/03/net-core-md5/ https://www.skyfinder.cc/2020/09/03/net-core-md5/#respond Wed, 02 Sep 2020 16:00:00 +0000 https://www.skyfinder.cc/?p=3154 背景

因某些需求,需要与合作单位进行相应的数据交互,而交互均使用了加密方式处理并用MD5作为签名,以便校验传输内容是否遭到篡改。

MD5

md5是一种信息摘要算法,它可以从一个字符串或一个文件中按照一定的规则生成一个特殊的字符串,并且一个文件所对应的MD5摘要是固定的,当文件内容变化后,其MD5值也会不一样,因此,在应用中经常使用MD5值来验证一段数据有没有被篡改。

.NET CORE 实现MD5

以下简单实现,支持返回大小写、32位以及16位MD5字符串。


    public static class EncryptionMd5
    {
         /// <summary>
        /// md5加密
        /// </summary>
        /// <param name="content">要加密的内容</param>
        /// <param name="isUpper">是否大写,默认小写</param>
        /// <param name="is16">是否是16位,默认32位</param>
        /// <returns></returns>
        public static string Md5(string content,bool isUpper=false,bool is16=false)
        {
            using (var md5 = MD5.Create())
            {
                var result = md5.ComputeHash(Encoding.UTF8.GetBytes(content));
                string md5Str = BitConverter.ToString(result);
                md5Str = md5Str.Replace("-", "");
                md5Str= isUpper ? md5Str : md5Str.ToLower();
                return is16 ? md5Str.Substring(8,16) : md5Str;
            }
        }
    }
以上是使用.NET CORE自身提供的MD5加密进行实现,如果想了解原理以及具体实现方式,请使用万能搜索引擎查找。

使用方式


using System;
using System.Text;
using System.Security.Cryptography;
namespace CryptographyApplication
{
   class SecurityCryptography
   {
      static void Main(string[] args)
      {
         Console.WriteLine(EncryptionMd5.Md5("Hello World!"));
         Console.ReadKey();
      }
   }
}

转载请注明:清风博客 » .NET CORE实现MD5加密

]]>
https://www.skyfinder.cc/2020/09/03/net-core-md5/feed/ 0
.Net Core实现AES加解密 https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/ https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/#respond Wed, 02 Sep 2020 04:30:29 +0000 https://www.skyfinder.cc/?p=3148 背景

因业务需求,需要与其他平台实现融合登录,根据提供融合登录方的文档内容,对AES加密解密相关内容使用.NET CORE来进行一次实现。以下记录实现AES加解密后的内容,便以后备用。

AES

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。严格地说,AESRijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128 比特,密钥长度则可以是128192256比特;而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。包括AES-ECBAES-CBCAES-CTRAES-OFBAES-CFB

.NET CORE 的AES加解密实现


    public enum CiphertextType
    {
        /// <summary>
        /// Base64
        /// </summary>
        Base64 = 1,
        /// <summary>
        /// 16进制字符串
        /// </summary>
        Hex = 2
    }
    public static class EncryptionAes
    {
        #region AES加密

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <param name="ciphertextType">密文类型</param>
        /// <returns></returns>
        public static (bool isSuccess, string text) AESEncrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC, CiphertextType ciphertextType = CiphertextType.Base64)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = Encoding.UTF8.GetBytes(source);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                {
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                }
                else
                {
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);
                }
                if (ivBytes.Length > useIvBytes.Length)
                {
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                }
                else
                {
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);
                }

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 256;//秘钥的大小,以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量,如果没有设置默认的16个0

                ICryptoTransform cryptoTransform = aes.CreateEncryptor();
                byte[] resultBytes = cryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);
                return (true, CipherByteArrayToString(resultBytes, ciphertextType));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        #endregion



        #region AES解密

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <param name="ciphertextType">密文类型</param>
        /// <returns></returns>
        public static (bool isSuccess, string text) AESDecrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC, CiphertextType ciphertextType = CiphertextType.Base64)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = CiphertextStringToByteArray(source, ciphertextType);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                {
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                }
                else
                {
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);
                }

                if (ivBytes.Length > useIvBytes.Length)
                {
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                }
                else
                {
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);
                }

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 256;//秘钥的大小,以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量,如果没有设置默认的16个0

                ICryptoTransform decryptoTransform = aes.CreateDecryptor();
                byte[] resultBytes = decryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);
                return (true, Encoding.UTF8.GetString(resultBytes));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        /// <summary>
        /// 通过密文返回加密byte数组
        /// </summary>
        /// <param name="ciphertext"></param>
        /// <param name="ciphertextType"></param>
        /// <returns></returns>
        public static byte[] CiphertextStringToByteArray(string ciphertext, CiphertextType ciphertextType)
        {
            byte[] cipherByte;
            switch (ciphertextType)
            {
                case CiphertextType.Base64:
                    cipherByte = Convert.FromBase64String(ciphertext);
                    break;
                case CiphertextType.Hex:
                    cipherByte = HexStringToByteArray(ciphertext);
                    break;
                default:
                    cipherByte = Convert.FromBase64String(ciphertext);
                    break;
            }
            return cipherByte;
        }

        /// <summary>
        /// 通过加密的Byte数组返回加密后的密文
        /// </summary>
        /// <param name="cipherByte"></param>
        /// <param name="ciphertextType"></param>
        /// <returns></returns>
        public static string CipherByteArrayToString(byte[] cipherByte, CiphertextType ciphertextType)
        {
            string ciphertext = "";
            switch (ciphertextType)
            {
                case CiphertextType.Base64:
                    ciphertext = Convert.ToBase64String(cipherByte);
                    break;
                case CiphertextType.Hex:
                    ciphertext = ByteArrayToHexString(cipherByte);
                    break;
                default:
                    ciphertext = Convert.ToBase64String(cipherByte);
                    break;
            }
            return ciphertext;
        }

        /// <summary>
        /// Hex字符串转Byte
        /// </summary>
        /// <param name="hexContent"></param>
        /// <returns></returns>
        public static byte[] HexStringToByteArray(string hexContent)
        {
            hexContent = hexContent.Replace(" ", "");
            byte[] buffer = new byte[hexContent.Length / 2];
            for (int i = 0; i < hexContent.Length; i += 2)
            {
                buffer[i / 2] = (byte)Convert.ToByte(hexContent.Substring(i, 2), 16);
            }
            return buffer;
        }
        /// <summary>
        /// Byte转Hex字符串
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            }
            return sb.ToString().ToUpper();
        }
        #endregion
    }

调用AES加解密


    class Program
    {
        static void Main(string[] args)
        {
            var ddd = "111111111" .AESEncrypt("3EDsw9[A4W5FdS{]3W","0102030504030201", PaddingMode.PKCS7);
            Console.WriteLine($"加密:{ddd.text}");
            Console.WriteLine($"解密:{(ddd.text.AESDecrypt("3EDsw9[A4W5FdS{]3W", "0102030504030201", PaddingMode.PKCS7)).text}");
            Console.Read();
        }
    }

示例下载

.Net Core实现AES加解密示例

转载请注明:清风博客 » .Net Core实现AES加解密

]]>
https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/feed/ 0
Java实现AES加解密 https://www.skyfinder.cc/2020/09/01/java-aes-encryption/ https://www.skyfinder.cc/2020/09/01/java-aes-encryption/#respond Tue, 01 Sep 2020 06:46:16 +0000 https://www.skyfinder.cc/?p=3140 因业务需求,需要进行融合登录,根据提供融合登录方的文档内容,对AES加密解密相关内容使用.NET CORE来进行一次实现。使用.NET CORE完成后,根据文档提到的密文进行解密,很遗憾解密无法完成。最终根据提供的Java文件进行相关确认,发现文档中所表述内容与Java示例文件中出现诸多不一致的地方。最后经过咨询并确认了以Java示例文件中的内容为准,所以此处记录一下这个AES加密解密的方法。


import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加密工具类
 * 
 */
public class AESCommonUtils
{

    /** 16位向量 双方约定一致 */
    private static final String IV = "0102030504030201";

    /** 密钥 双方约定一致 */
    private static final String KEY = "3EDsw9[A4W5FdS{]3W";

    /** 加密模式及填充方式 */
    private static final String MODE_PADDING = "AES/CBC/NoPadding";

    /** 加密模式 */
    private static final String MODE = "AES";

    /** 编码格式 UTF-8 */
    private static final String CHARSET_UTF8 = "UTF-8";

    /**
     * AES加密过程
     * 
     * @param strKey
     * @return
     * @throws Exception
     */
    public static String encrypt(String strKey, String info) throws Exception {
        SecretKeySpec skeySpec = getKey(strKey);
        Cipher cipher = Cipher.getInstance(MODE_PADDING);
        int blockSize = cipher.getBlockSize();

        byte[] dataBytes = info.getBytes(CHARSET_UTF8);
        int plaintextLength = dataBytes.length;
        if (plaintextLength % blockSize != 0) {
            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        }

        byte[] plaintext = new byte[plaintextLength];
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(plaintext);

        // return new BASE64Encoder().encode(encrypted);
        return byte2hex(encrypted);
    }

    /***
     * AES解密
     * 
     * @param strKey
     * @param strIn
     * @return
     * @throws Exception
     */
    public static String decrypt(String strKey, String info) throws Exception {
        try {
            byte[] byteResult = decrypt2Byte(strKey, info);
            String result = new String(byteResult, CHARSET_UTF8);
            return result;
        }
        catch (Exception e) {
            return info;
        }

    }

    /***
     * AES解密详细过程
     * 
     * @param strKey
     * @param content
     * @return
     * @throws Exception
     */
    private static byte[] decrypt2Byte(String strKey, String content) throws Exception {
        SecretKeySpec skeySpec = getKey(strKey);

        Cipher cipher = Cipher.getInstance(MODE_PADDING);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        // byte[] encrypted = Base64.decode(content)
        byte[] encrypted = hex2byte(content);
        byte[] original = flushZeroElements(cipher.doFinal(encrypted));

        return original;

    }

    /**
     * 清除AES加密前补位的内容
     * 
     * @param source
     * @return
     */
    private static byte[] flushZeroElements(byte[] source) {
        int i = 0;
        for (byte b : source) {
            if (b == 0) {
                break;
            }
            i++;
        }
        byte[] result = Arrays.copyOf(source, i);
        return result;
    }

    /***
     * 针对长度不满16的密钥进行补0操作
     * 
     * @param strKey
     * @return
     * @throws Exception
     */
    private static SecretKeySpec getKey(String strKey) throws Exception {
        byte[] arrBTmp = strKey.getBytes();
        byte[] arrB = new byte[16]; // 创建一个空的16位字节数组(默认值为0)

        for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
            arrB[i] = arrBTmp[i];
        }

        SecretKeySpec skeySpec = new SecretKeySpec(arrB, MODE);

        return skeySpec;
    }

    /***
     * 把16进制转成byte类型数组
     * 
     * @param strhex
     * @return
     */
    public static byte[] hex2byte(String strhex) {
        if (strhex == null) {
            return null;
        }
        int l = strhex.length();
        if (l % 2 == 1) {
            return null;
        }
        byte[] b = new byte[l / 2];
        for (int i = 0; i != l / 2; i++) {
            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2), 16);
        }
        return b;
    }

    /**
     * 把byte数组转成16进制
     * 
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            }
            else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();
    }

    public static void main(String[] args) {
        String userInfo = "11111";
        try {
                        userInfo = AESCommonUtils.encrypt(KEY,userInfo);
                        System.out.println("加密后:***" + userInfo + "===========");

                        userInfo= AESCommonUtils.decrypt(KEY,userInfo);
                        System.out.println("解密后***" + userInfo + "===========");
           
        }
        catch (Exception e) {
            System.out.println("加解密异常 : " + e.toString());
        }
    }

}

转载请注明:清风博客 » Java实现AES加解密

]]>
https://www.skyfinder.cc/2020/09/01/java-aes-encryption/feed/ 0
CodeSmith 7系列安装 https://www.skyfinder.cc/2020/08/23/codesmith-7-install/ https://www.skyfinder.cc/2020/08/23/codesmith-7-install/#respond Sun, 23 Aug 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=3094

CodeSmith

CodeSmith 是一种语法类似于ASP.NET的基于模板的代码生成器,程序可以自定义模板,作为开发人员工具,它可以减少重复编码的劳动量,提高效率。

CodeSmith 是一种基于模板的代码生成工具,它使用类似于ASP.NET的语法来生成任意类型的代码或文本。与其他许多代码生成工具不同,CodeSmith 不要求您订阅特定的应用程序设计或体系结构。使用 CodeSmith,可以生成包括简单的强类型集合和完整应用程序在内的任何东西。

CodeSmith 7 下载

CodeSmith 提取码:3pv6
压缩文件设置了解压密码:www.skyfinder.cc

CodeSmith 7安装

双击进行安装,点击next(下一步),以后的每一步都点击next进行下一步,直到点击Finish安装完成。

点击Finish后会出现以下界面,暂时不要输入任何内容且不要关闭窗体。如果真的关闭了,也没有什么关系,需要的时候再打开即可。

CodeSmith 7注册

打开KeyGenerator文件夹下的CodesmithKeyGenerator.exe工具,如下图所示:

打开激活工具后,在Prefix里面输入:CS70P-,因为使用的是CodeSmith 7.0.2,所以是CS70P-,如果是8.0则是CS80P-。其他的保持默认,点击Generate按钮。

下图则是点击Generate后计算出的假的注册码。复制假的注册码且注册工具不要关闭

回到CodeSmith Generator 程序界面,如果之前已经关闭就重新启动你的CodeSmith,输入上面复制的假的注册码并点击Register

输入名字和组织,其中Serial Number是我们上一步输入的内容,如果上一步没有输入任何内容,此处就需要粘贴之前注册机复制的假注册码。点击Register

点击按钮Activate by Entering a Code

记下机器码(Machine Code)且窗体不要关闭,如果嫌手动记录麻烦就使用下一步方法临时保存。

点击左侧按钮Copy to Clipboard 按钮并将复制的内容粘贴到文本临时保存。如果上一步已经手动记录且保证无误,此步骤可以省略。

回到注册工具界面并点击Generate Activation按钮

替换Prefix以后内容为CS70P-,修改时间且远大于当前时间。

将之前保存的Machine Code(机器码) ,粘贴到Machine Hash Code 下的文本框内并点击Generate来生成最终的激活码。

点击Generate后,在Activation下的文本框内就生成了最后的激活码

将激活码复制下来,回到CodeSmith的激活码待输入界面,在Activation Code下的文本框内中粘贴刚才复制的激活码,点击Activate来完成激活。

出现以下内容等待完成。

进度完成后就可以进入应用了,看下是否完成激活即可。

转载请注明:清风博客 » CodeSmith 7系列安装

]]>
https://www.skyfinder.cc/2020/08/23/codesmith-7-install/feed/ 0
Adobe Photoshop https://www.skyfinder.cc/2020/08/22/adobe-photoshop/ https://www.skyfinder.cc/2020/08/22/adobe-photoshop/#respond Fri, 21 Aug 2020 22:00:00 +0000 https://www.skyfinder.cc/?p=3087

Adobe Photoshop介绍

Adobe Photoshop,简称“PS”,是由Adobe Systems开发和发行的图像处理软件。

Photoshop主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具,可以有效地进行图片编辑工作。ps有很多功能,在图像、图形、文字、视频、出版等各方面都有涉及。

功能上看可分为图像编辑、图像合成、校色调色及功能色效制作部分等。 图像编辑是图像处理的基础,可以对图像做各种变换如放大、缩小、旋转、倾斜、镜像、透视等;也可进行复制、去除斑点、修补、修饰图像的残损等。

图像合成则是将几幅图像通过图层操作、工具应用合成完整的、传达明确意义的图像,这是美术设计的必经之路;该软件提供的绘图工具让外来图像与创意很好地融合。校色调色可方便快捷地对图像的颜色进行明暗、色偏的调整和校正,也可在不同颜色进行切换以满足图像在不同领域如网页设计、印刷、多媒体等方面应用。

特效制作在该软件中主要由滤镜、通道及工具综合应用完成。包括图像的特效创意和特效字的制作,如油画、浮雕、石膏画、素描等常用的传统美术技巧都可藉由该软件特效完成。

Adobe Photoshop下载

Adobe Photoshop CC 2019

Adobe Photoshop CC 2019 提取码:v8nw

转载请注明:清风博客 » Adobe Photoshop

]]>
https://www.skyfinder.cc/2020/08/22/adobe-photoshop/feed/ 0
adobe photoshop cc 2019打开图片显示空白图层的问题 https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/ https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/#respond Sun, 16 Aug 2020 04:21:20 +0000 https://www.skyfinder.cc/?p=3074 卸载了已经使用很久的Photoshop CS 6,重新安装一个稍微高版本adobe photoshop cc 2019,安装完成后使用photoshop打开图片显示空白图层,可能是与系统硬件不兼容。

  • 首先选择编辑菜单
  • 再选择首选项菜单
  • 然后选择性能菜单
  • 在图形处理器设置区域取消勾选使用图形处理器
  • 点击确定完成设置
  • 重新打开图片即刻正常显示

转载请注明:清风博客 » adobe photoshop cc 2019打开图片显示空白图层的问题

]]>
https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/feed/ 0