thinkcmf5(tp5.0) + workman实现简单客服聊天功能

配置过程中遇到的问题及说明:

1、首先需要对长连接相关概念有一定了解。

2、通过composer默认安装的workman版本不对,报错,使用命令composer require topthink/think-worker=1.0.1

3、通过1、发现composer包列表网址,https://packagist.org,可以通过该网址查找composer包,包括说明。

4、报错:stream_socket_server() has been disabled for security reasons … ,修改php.ini,disable_functions项,去掉stream_socket_server。

 

安装步骤说明:

1、composer安装命令,composer包安装倒了vendor/workerman/目录中。


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

2、在项目根目录中新建server文件,内容如下:


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

3、服务器端控制器代码:


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

4、linux进入项目根目录,启用服务监听端口。

1
php server start
1
2
3
4
5
6
7
8
Workerman[server] start in DEBUG mode
------------------------------------------- WORKERMAN --------------------------------------------
Workerman version:3.5.17 PHP version:5.6.36
-------------------------------------------- WORKERS ---------------------------------------------
proto user worker listen processes status
tcp root none websocket://0.0.0.0:2346 1 [OK]
--------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

5、前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<style>
        .content{<br />            width: 700px;<br />            margin: auto;<br />        }<br />        .box{<br />            padding-bottom: 3px;<br />            padding-top: 3px;<br />        }<br />        .box input{<br />            width: 70%;<br />        }<br />        .box button{<br />            width: 25%;<br />        }<br />    </style>

&nbsp;
<h3>CHAT TEST</h3>

<hr />

<div class="content">
<div class="box"><input name="name" type="text" />
<button id="setName">设置昵称</button></div>
<div class="box"><input name="message" type="text" />
<button id="send">发送</button></div>
<div id="content" class="box"></div>
</div>
<script>
    var ws;
    var connected = false;

    $(function () {

        ws = new WebSocket("ws://local.hillmatrix.com:2346");
        ws.onopen = function() {
            console.log('WebSocket 连接成功');
            connected = true;
        };
        ws.onmessage = function(e) {
            // e.data
            console.log(e.data);
            try {
                var data = JSON.parse(e.data);
                //非法数据,不处理
                if (!data.hasOwnProperty("code")) return;
                if (data.code != 0){
                    if (data.hasOwnProperty("msg")){
                        alert(data.msg);
                    }
                    return
                }

                if (!data.hasOwnProperty("data") || !data.hasOwnProperty("type") || !data.hasOwnProperty("data")) return;

                switch (data.type){
                    case 'private_message':
                        addChatItem(data.data.name + '(悄悄的...)',data.data.message)
                        break;
                    case 'message':
                        addChatItem(data.data.name,data.data.message)
                        break;
                    case 'msg':
                        alert(data.data.msg)
                        break;
                }

            }catch (ex) {

            }
        };

    });

    $("#setName").click(function () {
        var name = $('input[name=name]').val().trim();
        if (name==''){
            alert('昵称不能为空');
            return;
        }
        sendData('setName',{name:name});
    });

    $("#send").click(function () {
        var message = $('input[name=message]').val().trim();
        if (message==''){
            alert('内容不能为空');
            return;
        }

        if(message.indexOf(":") >= 0){
            sendData('private_message',{message:message});
        }else{
            sendData('message',{message:message});
        }

    })

    function addChatItem( name,message ) {
        var temp = '</p>
<p>
</p>
<div class="box"><p>
</p>
<p>__NAME__ 说:</p>
<p>
</p>
<p>__CONTENT__</p>
<p>
</div>
<p>
</p>
<p>';
        temp = temp.replace( "__NAME__",name );
        temp = temp.replace( "__CONTENT__",message );
        $("#content").append(temp);
    }

    function sendData(type,data) {
        if(ws.readyState != 1){
            alert(connected ? "连接已中断" : "连接不成功");
            return;
        }
        ws.send(JSON.stringify({type:type,data:data}));
    }
</script>

6、测试效果

参考代码:https://gitee.com/goto8848/build_a_simple_chat_room_with_workerman

官方文档:http://doc.workerman.net/faq/send-data-to-client.html

thinkphp5.1 + workerman 留着以后参考:https://blog.csdn.net/qq_27238185/article/details/81477303

PDF文档数字签名

fpdf官网:http://www.fpdf.org/?lang=zh

tcpdf官网:https://tcpdf.org/

1、对证书签名与验签逻辑优化,在linux系统中生成根证书CA,用CA为子证书签名,最后使用子证书为pdf做签名,防止pdf伪造自签证书。

1
2
3
4
5
6
7
8
#1、生成根证书 #a).生成根证书私钥(key文件)
openssl genrsa -aes256 -out ca.key 2048

#b).生成根证书签发申请文件(csr文件)
openssl req -new -key ca.key -out ca.csr -config /usr/lib/ssl/openssl.cnf

#c).自签发根证书(crt文件)
openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt
1
2
3
4
5
6
7
8
9
10
11
#2、用根证书签发server端证书
#a).生成根证书私钥(key文件)
openssl genrsa -aes256 -out tcpdf.key 2048

#b).生成根证书签发申请文件(csr文件)
openssl req -new -key tcpdf.key -out tcpdf.csr -config /usr/lib/ssl/openssl.cnf

#c).使用根证书签发服务端证书
openssl ca -in tcpdf.csr -out tcpdf.crt -days 730 -cert ca.crt -keyfile ca.key -config /usr/lib/ssl/openssl.cnf

#The organizationName field needed to be the same in the CA certificate (Timeswealth Global Root CA)

若发生错误: I am unable to access the ./demoCA/newcerts directory ./demoCA/newcerts: No such file or directory

做如下处理

1
2
3
4
5
mkdir demoCA
mkdir demoCA/newcerts
mkdir demoCA/private
touch demoCA/index.txt
echo "01" &gt;&gt; demoCA/serial

备注:一下是tcpdf官方提供的生成自签名证书方法,测试用,如果用于实际会有逻辑漏洞,没有根证书约束。

1
2
3
4
5
6
7
8
9
10
11
/* NOTES:

- To create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt

- To export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12

- To export p12 to pfx: openssl pkcs12 -export -inkey tcpdf.crt -in tcpdf.crt -out tcpdf.pfx

- To convert pfx certificate to pem: openssl pkcs12 -in tcpdf.pfx -out tcpdf.crt -nodes

*/

自己封装的tcpdf操作类


GeSHi Error: GeSHi could not find the language php (using path /home/wwwroot/www.hillmatrix.com/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

操作类的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<pre>require_once APP_ROOT_PATH."/system/utils/tcpdf_proxy.php";

$tcpdf = new TcpdfProxy();

$html = '&lt;html&gt;content&lt;/html&gt;';

$singConf = array();

$singConf['image'] = APP_ROOT_PATH.app_conf('CONTRACT_SEAL');

$singConf['sign_info'] = array(
    'Name' =&gt; app_conf('SHOP_TITLE'),
);

$tcpdf-&gt;setSignConf($singConf);

$tcpdf-&gt;outputPdf($html,'contract.pdf');</pre>

Git服务器搭建与客户端简单操作

服务器端准备工作:

1. 安装git

1
apt-get install git

2. 为了安全,新建一个专门用于代码部署的无特权用户

1
2
3
useradd -m git
#设置该用户的密码
passwd git

3. 新建一个目录作为要部署代码的根目录,如:

1
mkdir /var/www/git/item.git

4. 将这个目录的属主和属组都改为上面新建的用户git

1
2
cd /var/www/git
chown git:git item.git

5. 切换到部署代码的专用用户

1
su git

6. 进入项目根目录,初始化为git仓库

1
2
cd item.git
git init Initialized empty Git repository in /var/www/git/item.git/.git/

7. 必要的配置

1
2
3
4
5
6
7
8
#让仓库接受代码提交
git config receive.denyCurrentBranch ignore

#可选
git config core.worktree ~/www

#可选,禁止强制推送
git config --bool receive.denyNonFastForwards false

注意!

我们可以在自己的服务器上创建git仓库,有两种方式:

git –bare init (裸仓库)

git init

两者区别:

1,普通git仓库的目录结构就和你的代码目录结构一致,只多了.git目录,.git目录中包含了git的一些配置等数据

2,裸仓库只保存了一些配置信息等,肉眼是找不到我们所上传的代码的

额外说明:用”git init”初始化的版本库用户也可以在该目录下执行所有git方面的操作。但别的用户在将更新push上来的时候容易出现冲突。比如有用户在该目录(就称为远端仓库)下执行git操作,且有两个分支(master 和 b1),当前在master分支下。另一个用户想把自己在本地仓库(就称为本地仓库)的master分支的更新提交到远端仓库的master分支,他就想当然的敲了git push origin master:master于是乎出现错误 ,因为远端仓库的用户正在master的分支上操作,而你又要把更新提交到这个master分支上,当然就出错了。

确定一个repository是否为bare库的关键在于core.bare属性(boolean型属性)。core.bare属性可以有git config命令设置,也可以通过修改config文件的方式设置,conf文件指的就是当前库下面的conf配置文件,如果这里 bare = true 那么即使有.git文件夹也还是不能进行相关操作。 如果使用了git init初始化,则远程仓库的目录下,也包含work tree,当本地仓库向远程仓库push时, 如果远程仓库正在push的分支上(如果当时不在push的分支,就没有问题), 那么push后的结果不会反应在work tree上, 也即在远程仓库的目录下对应的文件还是之前的内容,必须得使用git reset –hard才能看到push后的内容.

本地仓库准备工作:

1. 通过 git clone 或 git pull 从仓库上将代码获取到本地

1
2
3
4
Administrator@PC-20170526BRPS MINGW32 /d/www/gitgit clone git@t.024ea.com:/var/www/git/item.git

Cloning into 'item'...
git@t.024ea.com's password: warning: You appear to have cloned an empty repository.

接下来接个phpstrom编辑更改代码提交,就简单了。

git利用post-receive自动化部署:

1. 更新服务端 git 仓库状态并检出文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd /var/www/git/item.git
git update-server-info
git checkout -f

# OR:

# 如果push的不是master分支
# git checkout branch_name

ls
new.html
cat new.html
#已经能看到提交文件
hello new git!

2.设置服务器钩子

1
2
3
4
5
6
#仓库配置文件
cd /var/www/git/item.git/.git/hooks

#默认没有这文件,新建了一个
touch post_receive
vim post_receive

shell脚本

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
chown www-data /var/www/git/item.git -R
DEPLOY_PATH=/var/www/git/item.git

unset  GIT_DIR #这条命令很重要
cd $DEPLOY_PATH
git reset --hard
git pull
chown www-data -R $DEPLOY_PATH
chgrp www-data -R $DEPLOY_PATH

关于unset GIT_DIR的说明:

经过查找资料,如过没有unset命令,在文件中添加 git pull 时会报错,提示:”fatal: Not a git repository: ‘.'”。hook脚本执行了cd之后,继续执行git语句拉取的时候还是在hooks文件夹下,而不是cd的文件路径。git的hooks里面默认有一些环境变量,会导致无论在哪个语句之后执行git命令都会有一个默认的环境路径,既然这样unset 掉默认的GIT环境变量就可以了。

参考:http://alfred-long.iteye.com/blog/1836347

补充

关于本地第一次使用clone命令无法使用git用户登陆,需要先使用命令ssh-keygen,参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@office-host-ubuntu:/var/www/git# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa)/home/git/.ssh/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/git/.ssh/id_rsa.
Your public key has been saved in /home/git/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:eXBtsym+2BZfcbWIk3E7Xh6doWn7q1lzMotX1zXxsbY
root@office-host-ubuntu The key's randomart image is:
+---[RSA 2048]----+
|                 |
|           o . +.|
|        . . O = @|
|         + = @.O=|
|        S o * *o*|
|         o.. o.E+|
|          .o .++o|
|         o....+=o|
|        ..o .+o..|
+----[SHA256]-----+

在Ubuntu上安装Chrome浏览器和ChromeDriver

一.安装Chrome浏览器

1.安装依赖

1
sudo apt-get install libxss1 libappindicator1 libindicator7

2.下载Chrome安装包

1
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb

3.安装

1
2
sudo dpkg -i google-chrome*.deb
sudo apt-get install -f

二.安装ChromeDriver

1.安装xvfb以便我们可以无头奔跑地运行Chrome

1
sudo apt-get install xvfb

2.安装依赖

1
sudo apt-get install unzip

3.下载安装包

1
wget -N http://chromedriver.storage.googleapis.com/对应版本/chromedriver_linux64.zip

 
chromedriver与chrome的对应关系表:
各个版本的下载地址:淘宝镜像

chromedriver版本 支持的Chrome版本
v2.41 v67-69
v2.40 v66-68
v2.39 v66-68
v2.38 v65-67
v2.37 v64-66
v2.36 v63-65
v2.35 v62-64
v2.34 v61-63
v2.33 v60-62
v2.32 v59-61
v2.31 v58-60
v2.30 v58-60
v2.29 v56-58
v2.28 v55-57
v2.27 v54-56
v2.26 v53-55
v2.25 v53-55
v2.24 v52-54
v2.23 v51-53
v2.22 v49-52
v2.21 v46-50
v2.20 v43-48
v2.19 v43-47
v2.18 v43-46
v2.17 v42-43
v2.13 v42-45
v2.15 v40-43
v2.14 v39-42
v2.13 v38-41
v2.12 v36-40
v2.11 v36-40
v2.10 v33-36
v2.9 v31-34
v2.8 v30-33
v2.7 v30-33
v2.6 v29-32
v2.5 v29-32
v2.4 v29-32

4.解压缩+添加执行权限

1
unzip chromedriver_linux64.zip

5.移动

1
sudo mv -f chromedriver /usr/local/share/chromedriver

6.建立软连接

1
2
sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver

三.无头运行Chrome

1.安装Python依赖

1
2
pip3 install selenium
pip3 install pyvirtualdisplay

2.开整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from selenium import webdriver
from selenium.webdriver.chrome.options import Options 
chrome_options = Options()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get(url)
iframe=driver.find_elements_by_tag_name('iframe')
    if len(iframe)>0:
        iframe = iframe[0]        
        driver.switch_to.frame(iframe)        
        ibody = driver.find_elements_by_tag_name('body')        
        if len(ibody)>0:            
            ibody=ibody[0]            
            video =ibody.find_element_by_tag_name('video')            
            if video is not None:                
                src = video.get_attribute("src")                
                if src !"" and src is not None:                    
                    res = {'src':src}                    
                    return str(res)

 

Linux禁止root帐号直接登录

Linux的默认管理员名即是root,只需要知道ROOT密码即可直接登录SSH。禁止Root从SSH直接登录可以提高服务器安全性。经过以下操作后即可实现。

本文适用于CentOS、Debian等Linux系统。
一、新建帐户

1
useradd kwxgd

SSH执行以上命令,可以创建名为“kwxgd”的帐号,可以自定义。
二、设置帐户密码

1
passwd kwxgd

使用passwd命令即可给相应帐户设置或修改密码。
根据图示,设置或修改密码需要填写两次,第二次为效验密码,输入完毕后请回车确认。
三、不允许root直接登陆1、修改相关文件

1
vi /etc/ssh/sshd_config

SSH执行以上命令,修改sshd_config文件
2、禁止root登陆查找“#PermitRootLogin yes”,将前面的“#”去掉,短尾“Yes”改为“No”,并保存文件。

四、下次登陆
1、先使用新建账号“kwxgd”以普通用户登陆。
2、若要获得ROOT权限,在SSH中执行以下命令

1
su root

执行以上命令并输入root密码后即可获得root权限。

Linux简单性能测试命令

1.top
Top命令显示了实际CPU使用情况,默认情况下,它显示了服务器上占用CPU的任务信息并且每5秒钟刷新一次。你可以通过多种方式分类它们,包括PID、时间和内存使用情况。
第一行的load average即为系统负载,就是说整个VPS资源占用情况,如果正常建站,一般很少有超过5的时候;
第三行的,这个是CPU占用资源。还有后面的??%wa这个是硬盘状态,正常情况下CPU最好不要超过30%占用.wa指数长期30%以上,基本上硬盘就是不给力状态。
第四行是内存,总内存,已使用内存,空闲内存。我这里是W2的VPS,内存为1GB,大家可以参考下。

2.查看CPU,硬盘和内存信息

1
2
3
cat /proc/cpuinfo(CPU信息)
cat /proc/meminfo(内存信息)
df –lh(查看硬盘信息)

3.下载测试

1
wget http://cachefly.cachefly.net/100mb.test

4.磁盘I/O测试

1
dd if=/dev/zero of=test bs=64k count=16k oflag=dsync

这个命令,是测试磁盘I/O性能的,图中有磁盘写入速率,可以作为参考。
或者使用此命令:

1
dd if=/dev/zero of=test bs=64k count=4k oflag=dsync

SSD磁盘用这个命令:

1
hdparm -t /dev/xvda

经过上面两步测试,磁盘多出了2个文件:100mb.test,test,我们用命令删除它们。

1
2
rm 100mb.test
rm test

5.UBI跑分综合性能测试

1
wget http://www.CTOHome.com/linux-vps-pack/unixbench.sh;sh ./unixbench.sh;

一般高于400分就算正常水准,如果高于1000的话,就是非常给力。

6.其他测试命令

1
2
3
iostat  (磁盘和内存使用率)
Vmstat  (进程、内存、页面I/O块和CPU等信息的监控)
wget -qO- bench.sh | bash

linux 系统中 /etc/passwd 和 /etc/shadow文件详解

在linux操作系统中, /etc/passwd文件中的每个用户都有一个对应的记录行,记录着这个用户的一下基本属性。该文件对所有用户可读。

而/etc/shadow文件正如他的名字一样,他是passwd文件的一个影子,/etc/shadow文件中的记录行与/etc/passwd中的一一对应,它由pwconv命令根据/etc/passwd中的数据自动产生。但是/etc/shadow文件只有系统管理员才能够进行修改和查看。

/etc/passwd文件介绍
首先,我们通过命令行

1
cat /etc/passwd

进行查看/etc/passwd文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
messagebus:x:102:106::/var/run/dbus:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
dnsmasq:x:104:65534:dnsmasq,,,:/var/lib/misc:/bin/false
avahi-autoipd:x:105:113:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
kernoops:x:106:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
rtkit:x:107:114:RealtimeKit,,,:/proc:/bin/false
saned:x:108:115::/home/saned:/bin/false
whoopsie:x:109:116::/nonexistent:/bin/false
speech-dispatcher:x:110:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
avahi:x:111:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
lightdm:x:112:118:Light Display Manager:/var/lib/lightdm:/bin/false
colord:x:113:121:colord colour management daemon,,,:/var/lib/colord:/bin/false
hplip:x:114:7:HPLIP system user,,,:/var/run/hplip:/bin/false
pulse:x:115:122:PulseAudio daemon,,,:/var/run/pulse:/bin/false
yaofei:x:1000:1000:ubuntu14.04,,,:/home/yaofei:/bin/bash
sshd:x:116:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:117:125:MySQL Server,,,:/nonexistent:/bin/false

从文件中我们可以看到,/etc/passwd中一行记录对应着一个用户,每行记录又被冒号(:)分隔为7个字段,其格式和具体含义如下:
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell

用户名(login_name):是代表用户账号的字符串。通常长度不超过8个字符,并且由大小写字母和/或数字组成。登录名中不能有冒号(:),因为冒号在这里是分隔符。为了兼容起见,登录名中最好不要包含点字符(.),并且不使用连字符(-)和加号(+)打头。
口令(passwd):一些系统中,存放着加密后的用户口令字。虽然这个字段存放的只是用户口令的加密串,不是明文,但是由于/etc/passwd文件对所有用户都可读,所以这仍是一个安全隐患。因此,现在许多Linux系统(如SVR4)都使用了shadow技术,把真正的加密后的用户口令字存放到/etc/shadow文件中,而在/etc/passwd文件的口令字段中只存放一个特殊的字符,例如“x”或者“*”。
用户标识号(UID):是一个整数,系统内部用它来标识用户。一般情况下它与用户名是一一对应的。如果几个用户名对应的用户标识号是一样的,系统内部将把它们视为同一个用户,但是它们可以有不同的口令、不同的主目录以及不同的登录Shell等。取值范围是0-65535。0是超级用户root的标识号,1-99由系统保留,作为管理账号,普通用户的标识号从100开始。在Linux系统中,这个界限是500。
组标识号(GID):字段记录的是用户所属的用户组。它对应着/etc/group文件中的一条记录。
注释性描述(users):字段记录着用户的一些个人情况,例如用户的真实姓名、电话、地址等,这个字段并没有什么实际的用途。在不同的Linux系统中,这个字段的格式并没有统一。在许多Linux系统中,这个字段存放的是一段任意的注释性描述文字,用做finger命令的输出。
主目录(home_directory):也就是用户的起始工作目录,它是用户在登录到系统之后所处的目录。在大多数系统中,各用户的主目录都被组织在同一个特定的目录下,而用户主目录的名称就是该用户的登录名。各用户对自己的主目录有读、写、执行(搜索)权限,其他用户对此目录的访问权限则根据具体情况设置。
登录Shell(Shell):用户登录后,要启动一个进程,负责将用户的操作传给内核,这个进程是用户登录到系统后运行的命令解释器或某个特定的程序,即Shell。Shell是用户与Linux系统之间的接口。Linux的Shell有许多种,每种都有不同的特点。常用的有

1
2
3
4
5
sh(BourneShell)
csh(CShell)
ksh(KornShell)
tcsh(TENEX/TOPS-20typeCShell)
bash(BourneAgainShell)

等。系统管理员可以根据系统情况和用户习惯为用户指定某个Shell。如果不指定Shell,那么系统使用sh为默认的登录Shell,即这个字段的值为/bin/sh。
/etc/shadow文件介绍
/etc/shadow文件格式与/etc/passwd文件格式类似,同样由若干个字段组成,字段之间用“:”隔开。
通过命令行输入

1
sudo cat /etc/shadow

进行文件内容查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
root:!:17043:0:99999:7:::
daemon:*:16652:0:99999:7:::
bin:*:16652:0:99999:7:::
sys:*:16652:0:99999:7:::
sync:*:16652:0:99999:7:::
games:*:16652:0:99999:7:::
man:*:16652:0:99999:7:::
lp:*:16652:0:99999:7:::
mail:*:16652:0:99999:7:::
news:*:16652:0:99999:7:::
uucp:*:16652:0:99999:7:::
proxy:*:16652:0:99999:7:::
www-data:*:16652:0:99999:7:::
backup:*:16652:0:99999:7:::
list:*:16652:0:99999:7:::
irc:*:16652:0:99999:7:::
gnats:*:16652:0:99999:7:::
nobody:*:16652:0:99999:7:::
libuuid:!:16652:0:99999:7:::
syslog:*:16652:0:99999:7:::
messagebus:*:16652:0:99999:7:::
usbmux:*:16652:0:99999:7:::
dnsmasq:*:16652:0:99999:7:::
avahi-autoipd:*:16652:0:99999:7:::
kernoops:*:16652:0:99999:7:::
rtkit:*:16652:0:99999:7:::
saned:*:16652:0:99999:7:::
whoopsie:*:16652:0:99999:7:::
speech-dispatcher:!:16652:0:99999:7:::
avahi:*:16652:0:99999:7:::
lightdm:*:16652:0:99999:7:::
colord:*:16652:0:99999:7:::
hplip:*:16652:0:99999:7:::
pulse:*:16652:0:99999:7:::
yaofei:$1$5M0Rbozg$1fWsJaQB.TFAL24b96xi41:17043:0:99999:7:::
sshd:*:17043:0:99999:7:::
mysql:!:17048:0:99999:7:::

文件中字段主要含义为:登录名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效时间:标志

“登录名”是与/etc/passwd文件中的登录名相一致的用户账号
“口令”字段存放的是加密后的用户口令字:
如果为空,则对应用户没有口令,登录时不需要口令;
星号代表帐号被锁定;
双叹号表示这个密码已经过期了;
$6$ 开头的,表明是用SHA-512加密;
$1$ 表明是用MD5加密;
$2$ 是用Blowfish加密;
$5$ 是用 SHA-256加密;
“最后一次修改时间”表示的是从某个时刻起,到用户最后一次修改口令时的天数。时间起点对不同的系统可能不一样。例如在SCOLinux中,这个时间起点是1970年1月1日。
“最小时间间隔”指的是两次修改口令之间所需的最小天数。
“最大时间间隔”指的是口令保持有效的最大天数。
“警告时间”字段表示的是从系统开始警告用户到用户密码正式失效之间的天数。
“不活动时间”表示的是用户没有登录活动但账号仍能保持有效的最大天数。
“失效时间”字段给出的是一个绝对的天数,如果使用了这个字段,那么就给出相应账号的生存期。期满后,该账号就不再是一个合法的账号,也就不能再用来登录了。

The following packages have been kept back 的解决方法

ubuntu 16.04

1
2
3
4
5
6
7
8
9
10
sudo apt-get upgrade
Reading package lists… Done
Building dependency tree
Reading state information… Done
The following packages have been kept back:
ginn hplip hplip-data libgrip0 libhpmud0 libsane-hpaio libunity-2d-private0
libunity-core-5.0-5 linux-generic linux-headers-generic linux-image-generic
printer-driver-hpcups printer-driver-hpijs unity unity-2d-common
unity-2d-panel unity-2d-shell unity-2d-spread unity-common unity-services
0 upgraded, 0 newly installed, 0 to remove and 20 not upgraded.

是因为有部份packages的安装版比release版新而出现”The following packages have been kept back”这个问题,解决方法是使用

1
apt-get -u dist-upgrade

统一更新到发布的版本。这条命令会强制更新软件包到最新版本,并自动解决缺少的依赖包。

Ubuntu Server配置SVN

1.安装SVN

1
apt-get install subversion

2.创建项目目录

1
2
3
4
mkdir svn //创建一个文件夹,用来存放一个或多个项目
cd ./svn //进入这个目录
mkdir project//创建一个新的项目目录
svnadmin create ./svn/project //创建svn文件仓库(这一步是让这个新的文件夹变成svn的版本库)

3.权限设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd ./svn/project/conf
vim passwd //添加用户设置密码
root = 123456
user1 = 123456
user2 = 123456
vim authz //编辑用户权限
admin = user1,user2,root
@admin=rw
*=r
vim svnserve.conf //控制访问权限
anon-access = none #匿名用户(anonymous users)的访问权限
auth-access = write #授权用户(authenticated users)的访问权限
password-db = passwd #密码数据库文件的位置,这里指向同级目录下的passwd文件
authz-db = authz #用户授权规则文件的位置,这里指向同级目录下的authz文件

4.启动SVN
启动svn

1
svnserve -d -r /svn 

这里的/svn 的目录就是你第一步创建用来存放项目的那个目录

关闭svn
在配置过程中如果需要关闭svn则kill

1
2
3
4
ps aux | grep svn
root 21618 0.0 0.0 69596 616 ? Ss 19:07 0:00 svnserve -d -r /svn
root 21927 0.0 0.2 11748 2156 pts/0 S+ 19:10 0:00 grep –color=auto svn
kill 21618

5.配置钩子
在这里svn提供了好的钩子模板,你可以根据自己的情况选择模板,一般都是选择post-commit.tmpl(提交后更新)

1
2
cd ./svn/project/hooks
vim post-commit //新建文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
EPOS="$1"
REV="$2"
TXN_NAME="$3"
export.UTF-8
SVN=/usr/bin/svn
WEB=/home/wwwroot/projectDIR
LOG=/tmp/www.log
$SVN update $WEB –username svnuser–password yourpasswd > $LOG || exit 1
chown wwwroot:www $WEB -R
exit 0
ifthen
echo "ok" >> /tmp/www.out
fi

6.设置模板执行权限

1
chmod 755 post-commit

7.上传代码纳入版本管理

1
svn import -m "import" /home/project svn://192.168.213.31/project

8.检出到WEB目录

1
/usr/bin/svn checkout svn://serverIP/project/ /home/wwwroot/project