王新阳

wangxinyang

未解之谜

百度搜索算法规范详解https://zy.baidu.com/act/guide?isResponsible=1

百度搜索优化知识大全https://zy.baidu.com/act/seo?isResponsible=1

阿里云开发者课堂 https://edu.aliyun.com/

spark-md5.js 计算文件md5值 :https://github.com/satazor/js-spark-md5

一个提供用户脚本的网站
https://greasyfork.org/zh-CN

用户脚本管理器:Tampermonkey中文文档
https://www.cnblogs.com/grubber/p/12560522.html

Js上传插件 Plupload

drupal

嵌入式WEB开发

CSRF 漏洞

fopen漏洞

Python
阿里云大学PYTHON学习路线
https://edu.aliyun.com/roadmap/python

ThinkPHP list_to_tree、tree_to_list、list_search

vue.js

C盘可以删除的临时文件,也可以用系统自带的磁盘清理程序清除
C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Temp
C:\Windows\SoftwareDistribution\Download
https://support.microsoft.com/zh-cn/windows?ui=zh-CN&rs=zh-CN&ad=CN
https://support.microsoft.com/zh-cn/windows/%E9%87%8A%E6%94%BE-windows-10-%E4%B8%AD%E7%9A%84%E9%A9%B1%E5%8A%A8%E5%99%A8%E7%A9%BA%E9%97%B4-85529ccb-c365-490d-b548-831022bc9b32

批量获取某目录及子孙目录下的所有图片image、视频video、目录dir、目录树dir_tree

/**
 * 批量获取某目录及子孙目录下的所有图片image、视频video、目录dir、目录树dir_tree
 * @param array  $filter_array 要过滤的目录名称列表
 */
function get_file_list($type, $path, $filter_array=array()){
	if(!in_array($type, explode(',','image,video,dir,dir_tree')))return return_data(1,'类型错误:'.$type);

	/**
	 * SELF_FIRST 目录从浅到深返回
	 * CHILD_FIRST 先处理子节点,目录从深到浅返回
	 */
	$iterator = new RecursiveIteratorIterator(
		new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
		RecursiveIteratorIterator::SELF_FIRST
	);

	$photos = [];
	$videos = [];
	$dirs = [];
	foreach ($iterator as $SplFileInfo){
		$skip=false;
		foreach($filter_array as $filter){
			if(strpos($SplFileInfo->getRealPath(), $filter)!==false){
				$skip=true;
				break;
			}
		}
		if($skip)continue;
/*
$SplFileInfo 实际是 RecursiveDirectoryIterator 类
参考:https://www.php.net/manual/zh/class.recursivedirectoryiterator.php
常用方法:
getExtension	获取扩展名,如:jpg
getFilename		获取文件名,如:abc.jpg
getPathname		返回创建 SplFileInfo 对象时传入的原始路径字符串(不做任何解析或验证),如:D:\web/pictures\2001\a.jpg
getRealPath		返回文件的规范化的绝对路径,如:D:\web\pictures\2001\a.jpg
getSize
getType
isDir
isFile
isLink	快捷方式,会自动跟随与链接文件
*/
		if($SplFileInfo->isDir()){
			$dirs[$iterator->getDepth()][] = $SplFileInfo->getRealPath();
		}else if($SplFileInfo->isFile()){
			$cur_path = dirname($SplFileInfo->getRealPath());
			$cur_file = $SplFileInfo->getRealPath();
			$cur_size = $SplFileInfo->getSize();
			switch(strtolower($SplFileInfo->getExtension())){
				case 'jpe':
				case 'jpg':
				case 'jpeg':
				case 'png':
					//因生成缩略图时可能出错,所以不展示大图片
					if($cur_size < 20*1024*1024){
						$photos[$cur_path][] = $cur_file;
					}
					break;
				case 'mp4':
					$videos[$cur_path][] = $cur_file;
					break;
			}
/*
			$photos[] = [
				'getRealPath' => $SplFileInfo->getRealPath(),
				'getPathname' => $SplFileInfo->getPathname(),
				'getExtension' => $SplFileInfo->getExtension(),
				'getFilename' => $SplFileInfo->getFilename(),
				'getSize' => $SplFileInfo->getSize(),
				'getType' => $SplFileInfo->getType(),
			];
*/
		}
	}
	ksort($dirs);
	// 构建树形结构
	$dir_tree = [];
	foreach ($dirs as $depth => $paths) {
		foreach ($paths as $path) {
			insertPathIntoTree($dir_tree, $path, $path);
		}
	}
	switch($type){
		case 'image':
			return return_data(0,'',$photos);
		case 'video':
			return return_data(0,'',videos);
		case 'dir':
			return return_data(0,'',dir);
		case 'dir_tree':
			return return_data(0,'',dir_tree);
	}
}
//生成目录树
function insertPathIntoTree(&$tree, $currentPath, $rootPath) {
  // 计算相对路径
  $relativePath = substr($currentPath, strlen($rootPath));
  if (empty($relativePath)) {
    $tree[$currentPath] = [];
    return;
  }

  // 分割路径
  $parts = explode(DIRECTORY_SEPARATOR, trim($relativePath, DIRECTORY_SEPARATOR));

  // 找到父路径
  $parentPath = $rootPath;
  for ($i = 0; $i < count($parts) - 1; $i++) {
    $parentPath .= DIRECTORY_SEPARATOR . $parts[$i];
  }

  // 如果是根目录下的直接子目录
  if ($parentPath === $rootPath) {
    $tree[$currentPath] = [];
    return;
  }

  // 在树中找到父路径对应的节点
  $current = &$tree;
  $pathSoFar = $rootPath;

  for ($i = 0; $i < count($parts) - 1; $i++) {
    $pathSoFar .= DIRECTORY_SEPARATOR . $parts[$i];
    // 查找当前路径在树中的位置
    $found = false;
    foreach ($current as $key => $value) {
      if (strpos($key, $pathSoFar) === 0) {
        $current = &$current[$key];
        $found = true;
        break;
      }
    }
    if (!$found) break;
  }

  // 在父节点中添加当前路径
  $current[$currentPath] = [];
}

php获取图片方向、纠正图片方向

/**
 * 自动纠正图片方向
 * 方向经过旋转的图片,在电脑、手机、浏览器中查看时一般会自动纠正,
 * 但是在生成缩略图、使用某些打印控件打印时,可能会出现方向不正确的情况。
 */
function rotateImage($imagePath) {
    if (!function_exists('exif_read_data')) {
        return false; // EXIF扩展未启用
    }
    
    if (!file_exists($imagePath)) {
        return false; // 文件不存在
    }
    
    $exif = exif_read_data($imagePath);
    
	$orientation=1;
    if ($exif && isset($exif['Orientation'])) {
        $orientation= (int)$exif['Orientation'];
    }

    // 读取图片
    $size = getimagesize($imagePath);
	$width = $size[0];
	$height= $size[1];
	$mime = $size['mime'];
    
    switch ($mime) {
		case 'image/jpeg':
			$image = imagecreatefromjpeg($imagePath);
			break;
		case 'image/png':
			$image = imagecreatefrompng($imagePath);
			break;
		case 'image/gif':
			 $image = imagecreatefromgif($imagePath);
			break;
        default:
   			header('Content-Type: '.$mime);
			echo file_get_contents($imagePath);
            return false;
    }
    
    // 根据方向值进行旋转
    switch ($orientation) {
        case 2:
            // 水平翻转
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 3:
            // 旋转180°
            $image = imagerotate($image, 180, 0);
            break;
        case 4:
            // 垂直翻转
            imageflip($image, IMG_FLIP_VERTICAL);
            break;
        case 5:
            // 顺时针90° + 水平翻转
            $image = imagerotate($image, -90, 0);
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 6:
            // 顺时针90°
            $image = imagerotate($image, -90, 0);
            break;
        case 7:
            // 逆时针90° + 水平翻转
            $image = imagerotate($image, 90, 0);
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 8:
            // 逆时针90°
            $image = imagerotate($image, 90, 0);
            break;
    }
    
    // 输出图片
    switch ($mime) {
        case 'image/jpeg':
            header('Content-Type: image/jpeg');
            imagejpeg($image, null, 90); // 90% 质量
            break;
        case 'image/png':
            header('Content-Type: image/png');
            imagepng($image, null, 9); // 9级压缩
            break;
        case 'image/gif':
            header('Content-Type: image/gif');
            imagegif($image);
            break;
    }

    imagedestroy($image);
}
/*获取图片方向*/
function getImageOrientation($imagePath) {
    if (!function_exists('exif_read_data')) {
        return return_data(1, 'EXIF扩展未启用');
    }
    
    if (!file_exists($imagePath)) {
        return return_data(2, '文件不存在');
    }
    
	$exif = @exif_read_data($imagePath);
	if($exif===null)return return_data(2,'方向无法读取:'.$imagePath);
	
	$orientation=0;
    if ($exif && isset($exif['Orientation'])) {
        $orientation= (int)$exif['Orientation'];
    }

	// 方向值说明:
	// 1 = 正常
	// 2 = 水平翻转
	// 3 = 旋转180°
	// 4 = 垂直翻转
	// 5 = 顺时针90°+水平翻转
	// 6 = 顺时针90°
	// 7 = 逆时针90°+水平翻转
	// 8 = 逆时针90°

	$txt='';
	switch ($orientation) {
		case 1:
			$txt="正常方向 (0°)";
			break;
		case 2:
			$txt="水平翻转";
			break;
		case 3:
			$txt="旋转 180°";
			break;
		case 4:
			$txt="垂直翻转";
			break;
		case 5:
			$txt="顺时针 90° + 水平翻转";
			break;
		case 6:
			$txt="顺时针 90°";
			break;
		case 7:
			$txt="逆时针 90° + 水平翻转";
			break;
		case 8:
			$txt="逆时针 90°";
			break;
		default:
			$txt="未知方向";
			break;
	}
	
	return return_data(0, $orientation.chr(32).$txt, array('orientation'=>$orientation, 'description'=>$txt));
}



function return_data($code=0,$msg='',$data=array()){
	return array('code'=>$code, 'msg'=>$msg, 'data'=>$data);
}

js实现浏览器全屏切换

调用浏览器的 Fullscreen API 来实现点击按钮后让整个页面(或指定元素)进入全屏模式

var btn=document.getElementById('fullscreenBtn');
btn.addEventListener('click', function(){
	if (document.fullscreenElement && document.exitFullscreen) {
		document.exitFullscreen();
		return;
	}

	// 获取整个文档根元素(通常是 )
	const elem = document.documentElement;

	// 尝试进入全屏(兼容不同浏览器前缀)
	if (elem.requestFullscreen) {
		elem.requestFullscreen();
	} else if (elem.mozRequestFullScreen) { /* Firefox */
		elem.mozRequestFullScreen();
	} else if (elem.webkitRequestFullscreen) { /* Chrome, Safari, Edge */
		elem.webkitRequestFullscreen();
	} else if (elem.msRequestFullscreen) { /* IE11 */
		elem.msRequestFullscreen();
	} else {
		alert('您的浏览器不支持全屏功能');
	}
});

PHP try catch示例

try {
    throw new Exception("错误消息", 404);
} catch (Exception $e) {
    echo "消息: " . $e->getMessage() . "\n"; // 错误消息
    echo "代码: " . $e->getCode() . "\n";     // 404
    echo "文件: " . $e->getFile() . "\n";     // 文件路径
    echo "行号: " . $e->getLine() . "\n";     // 行号
    echo "回溯: " . $e->getTraceAsString();  // 调用栈
}

php判断png/gif/webp是否背景透明

function isPngTransparent($filePath) {
	$image = imagecreatefrompng($filePath);
	if (!$image) return false;
	
	// 获取图像尺寸
	$width = imagesx($image);
	$height = imagesy($image);
	
	// 检查alpha通道
	if (imagecolortransparent($image) >= 0) {
		return true;
	}
	
	// 逐像素检查透明度
	for ($x = 0; $x < $width; $x++) {
		for ($y = 0; $y < $height; $y++) {
			$color = imagecolorat($image, $x, $y);
			$alpha = ($color >> 24) & 0xFF;
			if ($alpha > 0) {
				//imagedestroy($image);
				return true;
			}
		}
	}
	
	imagedestroy($image);
	return false;
}
function isGifTransparent($filePath) {
	$image = imagecreatefromgif($filePath);
	if (!$image) return false;
	
	// 获取透明色索引
	$transparentIndex = imagecolortransparent($image);
	
	// 如果有透明色索引
	if ($transparentIndex >= 0) {
		// 获取调色板中的透明色
		$transparentColor = imagecolorsforindex($image, $transparentIndex);
		if ($transparentColor['alpha'] == 127) {
			//imagedestroy($image);
			return true;
		}
	}
	
	imagedestroy($image);
	return false;
}
function isWebpTransparent($filePath) {
	if (!function_exists('imagecreatefromwebp')) {
		throw new Exception('WebP支持未启用');
	}
	
	$image = imagecreatefromwebp($filePath);
	if (!$image) return false;
	
	$width = imagesx($image);
	$height = imagesy($image);
	
	// WebP支持alpha通道,检查方式类似PNG
	for ($x = 0; $x < $width; $x++) {
		for ($y = 0; $y < $height; $y++) {
			$color = imagecolorat($image, $x, $y);
			$alpha = ($color >> 24) & 0xFF;
			if ($alpha > 0) {
				//imagedestroy($image);
				return true;
			}
		}
	}
	
	imagedestroy($image);
	return false;
}

安装SSL证书后中创中间件InforSuite_AS获取不到session、只能获取第一个cookie项的解决办法

麒麟V10系统+中创蹭件InforSuite_AS10+php,网站一直正常使用,自从安装SSL证书后,网站后台就经常登录不了,session获取不到,cookie也只能获取到请求并头cookie中的第一项。

解决办法:中创中间件管理后台禁用 HTTP2

步骤:中间件后台 > 配置 > server-config > 网络配置 > 网络监听程序 > HTTP >  HTTP/2 启用前的对勾去掉 > 保存 > 重启中间件。


附中创中间件忘记管理密码的解决办法:

XXX/as/domains/domain1/config/admin-keyfile 文件是密码存放文件,如果忘记密码,可以手动修改这个文件,重置密码。

可以直接替换整个 admin-keyfile 文件,重置三个默认用户的密码,也可以只替换某一用户的密码串,重置单用户的密码。

1) 创建新的域,使用 sh asadmin create-domain domain2 命令创建 domain2 域,此时 domain2 域下的 admin-keyfile 文件为默认密码文件,用户密码为初始密码。

2) 用 domain2 域下的/as/domains/domain2/config/admin-keyfile 文件,覆盖掉/as/domains/domain1/config/admin-keyfile 文件,重新启动应用服务器,即可使用默认密码登录,登录后请及时修改默认密码。

3) 替换单用户密码可以使用 domain2 下 admin-keyfile 文件中密码串替换domain1 下admin-keyfile中对应用户的密码串。例如,想用重置 inforsAdmin 用户密码,直接打开 domain2/config/下的 admin-keyfile 文件,复制 inforsAdmin 用户行信息,将/domain1/config/admin-keyfile 里面 inforsAdmin 整行替换掉即可,重新启动中间件,使用默认密码登录,登录后请及时修改默认密码。

以下只替换 admin 用户:

admin;{SSHA256}6ttdtB61vruEeIFeYcezgPxZLKHyZtgZRVdrCAEPvvqv3BVwaTTRkQ==,;asadmin;updateTime=2026-1-8 15:03:52

默认用户:admin,默认初始密码:Cvicse@as123

linux中启动mysql

1. 使用systemctl启动MySQL(推荐)
如果系统使用Systemd,并且MySQL已安装为系统服务,可以使用以下命令:

# 启动MySQL
sudo systemctl start mysql

# 或者,有些系统上服务名可能是mysqld
sudo systemctl start mysqld

# 设置开机自启
sudo systemctl enable mysql

# 查看状态
sudo systemctl status mysql

# 停止MySQL
sudo systemctl stop mysql

# 重启MySQL
sudo systemctl restart mysql

2. 使用service命令(SysVinit系统)对于使用SysVinit的系统,可以使用service命令:

# 启动MySQL
sudo service mysql start

# 或者,有些系统上服务名可能是mysqld
sudo service mysqld start

# 查看状态
sudo service mysql status

# 停止MySQL
sudo service mysql stop

# 重启MySQL
sudo service mysql restart

3. 使用mysqld_safe启动
mysqld_safe是一个脚本,用于启动MySQL服务器,并在发生错误时自动重启。通常,它位于MySQL安装目录的bin目录下。

# 进入MySQL安装目录,假设在/usr/local/mysql
cd /usr/local/mysql

# 使用mysqld_safe启动,并指定配置文件(如果需要)
sudo bin/mysqld_safe --defaults-file=/etc/my.cnf &

# 或者,如果已经将MySQL的bin目录添加到PATH,可以直接运行
sudo mysqld_safe &

注意:使用mysqld_safe启动时,可能需要指定--user选项来指定运行MySQL的用户,通常为mysql。

4. 手动启动MySQL服务器
你也可以直接调用mysqld来启动,但这通常不推荐,因为它不会提供自动重启等保护。

# 指定配置文件启动
sudo /usr/sbin/mysqld --defaults-file=/etc/mysql/my.cnf &

# 或者,如果知道MySQL的数据目录和socket文件等位置,可以指定选项
sudo /usr/sbin/mysqld --datadir=/var/lib/mysql --socket=/var/lib/mysql/mysql.sock --user=mysql &

5. 使用MySQL安装包中的启动脚本
如果你使用二进制包或源码编译安装,可能提供了启动脚本。例如,在源码编译安装后,可以使用support-files/mysql.server脚本。

# 假设在MySQL安装目录下
sudo support-files/mysql.server start

6. 检查MySQL是否启动
无论使用哪种方式启动,都可以通过以下方法检查MySQL是否正在运行:

# 检查进程
ps aux | grep mysqld

# 检查端口(默认3306)
netstat -tlnp | grep 3306
ss -tlnp | grep 3306

# 尝试连接
mysql -u root -p -e "SHOW DATABASES;"

1. systemctl 启动(Systemd 系统,推荐)

# 1.1 启动 MySQL
sudo systemctl start mysql
# 或(某些发行版使用 mysqld)
sudo systemctl start mysqld

# 1.2 停止 MySQL
sudo systemctl stop mysql
sudo systemctl stop mysqld

# 1.3 重启 MySQL
sudo systemctl restart mysql
sudo systemctl restart mysqld

# 1.4 查看状态
sudo systemctl status mysql
sudo systemctl status mysqld

# 1.5 设置开机自启
sudo systemctl enable mysql
sudo systemctl enable mysqld

# 1.6 禁用开机自启
sudo systemctl disable mysql
sudo systemctl disable mysqld

# 1.7 重新加载配置文件
sudo systemctl reload mysql
sudo systemctl reload mysqld

# 1.8 查看日志
sudo journalctl -u mysql
sudo journalctl -u mysqld
sudo journalctl -u mysql -f  # 实时监控日志

2. service 启动(SysVinit 系统)

# 2.1 启动 MySQL
sudo service mysql start
sudo service mysqld start

# 2.2 停止 MySQL
sudo service mysql stop
sudo service mysqld stop

# 2.3 重启 MySQL
sudo service mysql restart
sudo service mysqld restart

# 2.4 查看状态
sudo service mysql status
sudo service mysqld status

# 2.5 设置开机自启
sudo chkconfig mysql on       # RHEL/CentOS 6
sudo update-rc.d mysql defaults # Debian/Ubuntu

# 2.6 禁用开机自启
sudo chkconfig mysql off
sudo update-rc.d mysql remove

3. 直接启动 MySQL 守护进程

# 3.1 使用 mysqld_safe(推荐)
sudo mysqld_safe --defaults-file=/etc/my.cnf &

# 3.2 直接启动 mysqld
sudo /usr/sbin/mysqld --defaults-file=/etc/my.cnf --user=mysql &

# 3.3 使用 MySQL 启动脚本
sudo /etc/init.d/mysql start
sudo /etc/init.d/mysqld start

# 3.4 使用 mysql.server(MacOS/部分Linux)
sudo /usr/local/mysql/support-files/mysql.server start

检查系统中安装的 MySQL

# 查看 MySQL 版本
mysql --version
mysql -V

# 查看 MySQL 安装位置
which mysql
whereis mysql

# 查看 MySQL 服务状态
systemctl list-units | grep -i mysql
systemctl list-units | grep -i mariadb

# 查看 MySQL 进程
ps aux | grep mysql
ps aux | grep mysqld

# 查看 MySQL 端口
sudo netstat -tlnp | grep mysql
sudo ss -tlnp | grep mysql
sudo lsof -i :3306

配置文件位置

# 常见配置文件位置
/etc/my.cnf
/etc/mysql/my.cnf
/usr/local/mysql/my.cnf
~/.my.cnf

# MariaDB 配置文件
/etc/my.cnf
/etc/my.cnf.d/
/etc/mysql/my.cnf
/etc/mysql/mariadb.conf.d/

video 视频标签的属性

一、核心 HTML5 属性

<video
  src="video.mp4"
  controls
  preload="metadata"
  poster="thumbnail.jpg"
  width="800"
  height="450"
  muted
  loop
  autoplay
  playsinline
  crossorigin="anonymous"
  class="video-player"
>
  <!-- 备用内容 -->
  <p>您的浏览器不支持 HTML5 视频</p>
</video>

二、针对 iOS/Safari 的关键属性

<video
  playsinline
  webkit-playsinline
  x5-playsinline
  t7-video-player-type="inline"
>

解释:
playsinline - 标准属性,防止 iOS 自动全屏
webkit-playsinline - WebKit 前缀版本(iOS 9-10 需要)
x5-playsinline - 腾讯 X5 内核(微信浏览器)
t7-video-player-type="inline" - 部分安卓浏览器

三、自动播放策略(iOS 限制)

<!-- iOS 允许自动播放的条件 -->
<video autoplay playsinline muted>
  <!-- 必须同时有:autoplay + playsinline + muted -->
</video>

<!-- 或使用 JavaScript 控制 -->
<video id="myVideo" playsinline controls>

// iOS 需要用户交互才能播放声音
document.addEventListener('touchstart', function() {
  const video = document.getElementById('myVideo');
  video.play().catch(e => console.log(e));
}, { once: true });

四、推荐的最佳实践配置

<video
  controls
  playsinline
  webkit-playsinline
  preload="metadata"
  poster="poster.jpg"
  width="100%"
  height="auto"
  style="object-fit: contain; background-color: #000;"
  crossorigin="anonymous"
  aria-label="视频描述"
>
  <!-- 多格式支持 -->
  <source src="video.mp4" type="video/mp4">
  <source src="video.webm" type="video/webm">
  <!-- 备用内容 -->
  <p>您的浏览器不支持 HTML5 视频</p>
</video>

五、重要 CSS 补充

video {
  /* 防止 iOS 默认控件 */
  -webkit-appearance: none;
  
  /* 移除 iOS 的蓝色高光 */
  -webkit-tap-highlight-color: transparent;
  
  /* 禁用文本选择 */
  user-select: none;
  -webkit-user-select: none;
  
  /* 响应式 */
  max-width: 100%;
  height: auto;
  display: block;
}

六、微信浏览器特殊处理

<video
  x5-video-player-type="h5"
  x5-video-player-fullscreen="true"
  x5-video-orientation="portrait"
>


php遍历获取当前目录及子目录下所有文件

/**
 * SELF_FIRST 目录从浅到深返回
 * CHILD_FIRST 先处理子节点,目录从深到浅返回
 */
function getAllFilesWithSize() {
        $files = [];
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($this->cacheBaseDir, FilesystemIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );
        foreach ($iterator as $SplFileInfo) {
            if ($SplFileInfo->isFile()) {
                $files[] = [
			'getRealPath' => $SplFileInfo->getRealPath(),
			'getPathname' => $SplFileInfo->getPathname(),
			'getExtension' => $SplFileInfo->getExtension(),
			'getFilename' => $SplFileInfo->getFilename(),
			'getSize' => $SplFileInfo->getSize(),
			'getType' => $SplFileInfo->getType(),
                ];
            }
        }
        
        return $files;
    }

参考:
PHP标准库 https://www.php.net/manual/zh/book.spl.php
递归目录迭代器 https://www.php.net/manual/zh/class.recursivedirectoryiterator.php

2026-01-29 星期四 农历腊月十一