go 调用windows api

go调用windows api分为两种方式,一种是懒加载(第一次调用函数时才加载dll),一种是立即加载。

需要注意的是,windows api里面有很多常量和结构体需要自己转化成go的才可以用(文档中有对应的说明),如下获取系统进程列表时需要用到的部分其实都是根据官方文档转化而来。windows api 链接地址

需要特别注意的是,API函数的参数都是uintptr类型,对指针类型需要通过unsafe.Pointer函数来转换,如果是false和null就用0代替

不再需要使用DLL里的函数之后可以卸载DLL,可使用syscall.FreeLibrary来卸载。

1、懒加载:kernel32 =syscall.NewLazyDLL(“kernel32.dll”)

package main

import (
"fmt"
"syscall"
"unsafe"
)

//todo windows api 相关
type (
BOOL uint32
BOOLEAN byte
BYTE byte
DWORD uint32
DWORD64 uint64
HANDLE uintptr
HLOCAL uintptr
LARGE_INTEGER int64
LONG int32
LPVOID uintptr
SIZE_T uintptr
UINT uint32
ULONG_PTR uintptr
ULONGLONG uint64
WORD uint16
)

type PROCESSENTRY32 struct {
dwSize DWORD
cntUsage DWORD
th32ProcessID DWORD
th32DefaultHeapID ULONG_PTR
th32ModuleID DWORD
cntThreads DWORD
th32ParentProcessID DWORD
pcPriClassBase LONG
dwFlags DWORD
szExeFile [260]byte
}

const (
//Tool Help Library tlhelp.h
//CreateToolhelp32Snapshot==>可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。说到底,可以获取系统中正在运行的进程信息,线程信息,等。
TH32CS_INHERIT = 0x80000000 //声明快照句柄是可继承的
TH32CS_SNAPHEAPLIST = 0x00000001 //在快照中包含在th32ProcessID中指定的进程的所有的堆
TH32CS_SNAPMODULE = 0x00000008 //在快照中包含在th32ProcessID中指定的进程的所有的模块
TH32CS_SNAPMODULE32 = 0x00000010 //包括所有的 32 位模块的 th32ProcessID 在快照时从 64 位进程调用中指定的进程
TH32CS_SNAPPROCESS = 0x00000002 //在快照中包含系统中所有的进程
TH32CS_SNAPTHREAD = 0x00000004 //在快照中包含系统中所有的线程
TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) //在快照中包含系统中所有的进程和线程。
)

func main() {
//懒加载获取进程列表==>懒加载
Kernel32 := syscall.NewLazyDLL("Kernel32.dll")
//获取快照
CreateToolhelp32Snapshot := Kernel32.NewProc("CreateToolhelp32Snapshot")
//调用函数
phandle, _, _ := CreateToolhelp32Snapshot.Call(uintptr(TH32CS_SNAPPROCESS), uintptr(0))
//延迟关闭快照句柄
defer func() {
CloseHandle := Kernel32.NewProc("CloseHandle")
_, _, _ = CloseHandle.Call(phandle)
}()

Process32Next := Kernel32.NewProc("Process32Next")
for {
var pe32 PROCESSENTRY32
pe32.dwSize = DWORD(unsafe.Sizeof(pe32))

rt, _, _ := Process32Next.Call(uintptr(phandle), uintptr(unsafe.Pointer(&pe32)))
if int(rt) == 1 {
fmt.Println("进程pid:",pe32.th32ProcessID,"进程名称:",string(pe32.szExeFile[0:]),"线程数量:",pe32.cntThreads)
} else {
break
}
}
}

2、立即加载:kernel32,_ = syscall.LoadLibrary(“kernel32.dll”)

package main

import (
"fmt"
"syscall"
"unsafe"
)

//todo windows api 相关
type (
BOOL uint32
BOOLEAN byte
BYTE byte
DWORD uint32
DWORD64 uint64
HANDLE uintptr
HLOCAL uintptr
LARGE_INTEGER int64
LONG int32
LPVOID uintptr
SIZE_T uintptr
UINT uint32
ULONG_PTR uintptr
ULONGLONG uint64
WORD uint16
)

type PROCESSENTRY32 struct {
dwSize DWORD
cntUsage DWORD
th32ProcessID DWORD
th32DefaultHeapID ULONG_PTR
th32ModuleID DWORD
cntThreads DWORD
th32ParentProcessID DWORD
pcPriClassBase LONG
dwFlags DWORD
szExeFile [260]byte
}

const (
//Tool Help Library tlhelp.h
//CreateToolhelp32Snapshot==>可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。说到底,可以获取系统中正在运行的进程信息,线程信息,等。
TH32CS_INHERIT = 0x80000000 //声明快照句柄是可继承的
TH32CS_SNAPHEAPLIST = 0x00000001 //在快照中包含在th32ProcessID中指定的进程的所有的堆
TH32CS_SNAPMODULE = 0x00000008 //在快照中包含在th32ProcessID中指定的进程的所有的模块
TH32CS_SNAPMODULE32 = 0x00000010 //包括所有的 32 位模块的 th32ProcessID 在快照时从 64 位进程调用中指定的进程
TH32CS_SNAPPROCESS = 0x00000002 //在快照中包含系统中所有的进程
TH32CS_SNAPTHREAD = 0x00000004 //在快照中包含系统中所有的线程
TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) //在快照中包含系统中所有的进程和线程。
)

func main() {
//获取进程列表==>立即加载
kernel32,_:=syscall.LoadLibrary("kernel32")
//调用函数
CreateToolhelp32Snapshot, _ :=syscall.GetProcAddress(kernel32,"CreateToolhelp32Snapshot")
//其他参数补0就行了
pHandle,_,_:=syscall.Syscall(CreateToolhelp32Snapshot,2, uintptr(TH32CS_SNAPPROCESS), uintptr(0),0)
if int(pHandle) == 0{
panic("CreateToolhelp32Snapshot调用失败")
}

Process32Next,err:=syscall.GetProcAddress(kernel32,"Process32Next")
if err != nil{
panic(Process32Next)
}

for {
var pe32 PROCESSENTRY32
pe32.dwSize = DWORD(unsafe.Sizeof(pe32))
ret, _, _ := syscall.Syscall(Process32Next,2,uintptr(pHandle), uintptr(unsafe.Pointer(&pe32)),0)
if int(ret) == 1 {
fmt.Println("进程 pid:",pe32.th32ProcessID,"进程名称:",string(pe32.szExeFile[0:]),"线程数量:",pe32.cntThreads)
} else {
break
}
}
}

其他的api调用套路都是这样,其他就需要是对文档熟悉程度,用到哪块就调用哪块就行了。

最后的最后,一个简易网页版进程管理:https://gitee.com/iwhot/task-manager

tp部署服务器500

在index.php开启错误根据错误去调试就好了

error_reporting(E_ALL);
ini_set('display_errors', '1');

大部分是fastcgi部分配置有问题导致访问不到目录,一般在里面直接加个“../”让它能访问上级目录就行了

fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/../:/tmp/:/proc/";

用lnmp一键安装包安装的话也可以改.user.ini

.user.ini必须解锁才能删除

删除命令:chattr -i .user.ini

相关命令:

 chatter: 锁定文件,不能删除,不能更改
        +a:  只能给文件添加内容,但是删除不了,
              chattr +a  文件名
        -d:      不可删除
        加锁:chattr +i  文件名       文件不能删除,不能更改,不能移动
        查看加锁: lsattr 文件名      文件加了一个参数 i 表示锁定

Go web 分页

这是一个自己写的比较简单的web分页,按钮样式主要是根据bootstrap调整的,如有需要的话可以自行调整:

package page

import (
	"html/template"
	"math"
	"strconv"
)

type page struct {
	Pre      string //上一页样式
	Next     string //下一页样式
	Count    int    //总数
	NowPage  int    //当前页
	PageSize int    //一页条数
	Current  int    //当前页
	PrePage  int    //上一页
	NextPage int    //下一页
	MaxNum   int    //页数按钮显示多少个
}

var Pagination = newPage()

func newPage() *page {
	return &page{
		Pre:    "«",
		Next:   "»",
		MaxNum: 10,
	}
}

func (p *page) Pagination(nowPage, pageSize, count int, param string) template.HTML {
	p.NowPage = nowPage
	p.Count = count
	if nowPage <= 1 {
		nowPage = 1
	}
	//总页数
	num := float64(count) / float64(pageSize)
	pageCount := int(math.Ceil(num))

	if count <= 1 || pageCount <= 1 {
		return template.HTML(`<ul class="pagination"><li class="disabled"><span>` + p.Pre + `</span></li><li class="active"><span>1</span></li><li class="disabled"><span>` + p.Next + `</span></li></ul>`)
	}

	p.Current = nowPage //当前页
	p.Count = pageCount //总页数

	if nowPage <= 1 {
		p.PrePage = 1 //上一页
	} else {
		p.PrePage = nowPage - 1 //上一页
	}

	if nowPage >= pageCount {
		p.NextPage = pageCount //下一页
	} else {
		p.NextPage = nowPage + 1 //下一页
	}

	var htmls string
	//拼接上面的
	htmls = `<ul class="pagination">`
	if p.Current <= 1 {
		htmls += `<li class="disabled"><span>` + p.Pre + `</span></li>`
	} else {
		htmls += `<li><a href="?p=` + strconv.Itoa(p.PrePage) + `">` + p.Pre + `</a></li>`
	}

	htmls += middleStr(p.Current, pageCount, p.MaxNum, param)

	//拼接底页
	if p.Current >= pageCount {
		htmls += `<li class="disabled"><span>` + p.Next + `</span></li>`
	} else {
		htmls += `<li><a href="?p=` + strconv.Itoa(p.NextPage) + `">` + p.Next + `</a></li>`
	}

	htmls += `</ul>`

	return template.HTML(htmls)
}

//中间部分拼接
func middleStr(current, pageCount, maxCount int, param string) string {
	var htmls string
	var i int
	//如果总页数不是很多就全部展示出来
	if pageCount <= maxCount {
		for i = 1; i <= pageCount; i++ {
			if current == i {
				htmls += `<li class="active"><span>` + strconv.Itoa(i) + `</span></li>`
			} else {
				if param != "" {
					htmls += `<li><a href="?p=` + strconv.Itoa(i) + `">` + strconv.Itoa(i) + `</a></li>`
				} else {
					htmls += `<li><a href="?` + param + `&p=` + strconv.Itoa(i) + `">` + strconv.Itoa(i) + `</a></li>`
				}

			}
		}
		return htmls
	}
	//如果分页比较多就展示部分按钮,其他部分用...代替
	if current > 1 {
		htmls += `<li><a href="?p=1">...</a></li>`
	}
	//获取最大值
	maxCount -= 1
	now := maxCount + current
	if now >= pageCount {
		now = pageCount
	}
	//里面必须有特定个数的按钮
	cnum := now - maxCount
	for i = cnum; i <= now; i++ {
		if current == i {
			htmls += `<li class="active"><span>` + strconv.Itoa(i) + `</span></li>`
		} else {
			if param != "" {
				htmls += `<li><a href="?p=` + strconv.Itoa(i) + `">` + strconv.Itoa(i) + `</a></li>`
			} else {
				htmls += `<li><a href="?` + param + `&p=` + strconv.Itoa(i) + `">` + strconv.Itoa(i) + `</a></li>`
			}
		}
	}
	//...结尾
	if now < pageCount && current >= 1 {
		htmls += `<li><a href="?p=` + strconv.Itoa(now) + `">...</a></li>`
	}
	return htmls
}

用法如下:

pagine := page.Pagination.Pagination(page, pageSize, count, param)

返回的是html,可以直接传入模板使用。效果如下:

go mod的使用

按照当前的趋势估计go之后的版本都是用go mod来管理了,gopath这种模式感觉会被淘汰。

go mod help查看帮助
go mod init<项目模块名称>初始化模块,会在项目根目录下生成 go.mod文件。
go mod tidy根据go.mod文件来处理依赖关系。
go mod vendor将依赖包复制到项目下的 vendor目录。建议一些使用了被墙包的话可以这么处理,方便用户快速使用命令go build -mod=vendor编译
go list -m all显示依赖关系。go list -m -json all显示详细依赖关系。
go mod download 下载依赖。参数是非必写的,path是包的路径,version是包的版本。

基本上用的时候就是,首先go init一下,然后编译的时候会把对应git上的包自己编译进去,编译之前可以go tidy处理一些依赖关系。如果网速慢也可以用vendor下载下来。

在此建议使用go mod的时候建议配置上goproxy,毕竟国内被墙的厉害,就是环境变量加个 GOPROXY=https://goproxy.io 就ok。

vmware centos 使用open-vm-tools 共享文件夹

一、安装open-vm-tools
yum install open-vm-tools
二、重启服务器 reboot 三、右键虚拟机,点开设置–选项–共享文件夹
四、创建挂载目录并挂载
mkdir /mnt/hgfs
vmhgfs-fuse .host:/ /mnt/hgfs
五、其他
更详细的使用方法可以用命令 “vmhgfs-fuse -h”查看
# 1.显示是配置
vmware-hgfsclient  ##我的显示是配置的learn
#2. 使用 vmhgfs-fuse .host:/workspace /mnt/hgfs 命令挂载该共享文件夹(注意:带.号的哦),其中.host:/workspace是共享名,只需把workspace换成
使用vmware-hgfsclient 命令得到的目录,/mnt/hgfs是挂载点
vmhgfs-fuse .host:/learn /mnt/hgfs
# 3. 到此为止是可以使用该共享文件夹了,但每次都得重复mount一次,所以需要设置为随机启动后自动挂载
编辑 /etc/fstab,添加下面一行
.host:/www	/data/www	fuse.vmhgfs-fuse	allow_other,uid=1000,gid=1000,umask=022	0 0 (按需写) 这个我添加了以后,开机会变成命令行模式,
最后,记得要重启!!!

编译安装PHP

./configure \
--prefix=/opt/php72 \
--with-config-file-path=/etc \
--enable-fpm \
--with-fpm-user=nginx \
--with-fpm-group=nginx \
--enable-inline-optimization \
--disable-debug \
--disable-rpath \
--enable-shared \
--enable-soap \
--with-libxml-dir \
--with-xmlrpc \
--with-openssl \
--with-mhash \
--with-pcre-regex \
--with-sqlite3 \
--with-zlib \
--enable-bcmath \
--with-iconv \
--with-bz2 \
--enable-calendar \
--with-curl \
--with-cdb \
--enable-dom \
--enable-exif \
--enable-fileinfo \
--enable-filter \
--with-pcre-dir \
--enable-ftp \
--with-gd \
--with-openssl-dir \
--with-jpeg-dir \
--with-png-dir \
--with-zlib-dir \
--with-freetype-dir \
--enable-gd-jis-conv \
--with-gettext \
--with-gmp \
--with-mhash \
--enable-json \
--enable-mbstring \
--enable-mbregex \
--enable-mbregex-backtrack \
--with-libmbfl \
--with-onig \
--enable-pdo \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-zlib-dir \
--with-pdo-sqlite \
--enable-session \
--enable-shmop \
--enable-simplexml \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-wddx \
--with-libxml-dir \
--with-xsl \
--enable-zip \
--enable-mysqlnd-compression-support \
--with-pear \
--enable-opcache

php利用Gd库添加文字水印乱码

报错信息类似: Warning ‘yii\base\ErrorException’ with message ‘imagefttext(): any2eucjp(): invalid code in input string’

其实是php编译参数 –enable-gd-jis-conv开启了

–enable-gd-jis-conv:

如果PHP编译时启用–enable-gd-jis-conv选项的话,那么非ASCII字符(例如汉字、拼音、希腊文和箭头) 会被当成EUC-JP编码,最终导致正常的中文变成乱码

解决方案:

1.关闭–enable-gd-jis-conv 选项,重新编译php

2.将字符转换为html实体

mb_convert_encoding ('测试', 'HTML-ENTITIES', 'UTF-8');//用这种方法的时候一定要使用支持中文的字体包,要不然还是小方块