开发中,一般有三个环境,本地环境、线上测试环境、线上正式环境。

各个环境可能有其对应的数据库配置信息,Redis配置信息;有些情境下,本地环境到线上测试环境的发布可能比较频繁;那么如何在保证开发效率的同时保证发布的安全呢?

本地环境搭建

首先,需要 搭建本地调试环境,使其可以通过某个自定义域名进行访问。

如果开发环境需要用到 MySQL,可参考 OS X - MySQL 的安装

配置文件独立

将配置文件独立出来,不要和其他代码耦合,以需要用到 MySQL 以及 COOKIE_DOMAINConf.php 为例,在本地环境中,配置文件永远是本地环境的信息,也就是说即使本地工程泄露,线上的隐私也不会泄露出去。

1
2
3
4
5
6
7
8
9
10
11
class Conf
{
const DEBUG = true;

const MYSQL_HOST = '127.0.0.1';
const MYSQL_DB_NAME = 'my_db';
const MYSQL_ACCOUNT = 'my_account';
const MYSQL_PASSWORD = 'my_password';

const COOKIE_DOMAIN = '.local.com';
}

发布脚本独立

DEBUG 标识位

DEBUG 标识位是第一道保险,毕竟一键发布过于方便可能会造成手误。当标识位为 true 的时候,企图发布到正式环境会失败;当它为 false 的时候,企图发布到测试环境会失败。

使用脚本替换配置文件信息

在执行发布脚本时,需要去替换配置文件信息。为此可以独立写一个功能脚本,根据实际情况去替换配置信息。

在同步到线上环境之前,把配置文件替换为线上环境的相应信息;同步完成之后,再将配置文件替换为本地环境的相应信息。

发布脚本示例:

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
DEBUG_MODE=`cat ${CONFIG_PATH} | grep 'const DEBUG =' | sed -n "s/^.*const\ DEBUG\ =\ \([a-z]*\).*$/\1/p"`

if [ "$1" == "release" ]; then
if [ "${DEBUG_MODE}" != "false" ]; then
echo "SEHLL DEBUG_MODE: false"
echo "PHP DEBUG_MODE: ${DEBUG_MODE}"
echo "发布失败!!!"
exit
fi

SYNC_MODE='release'
else
if [ "${DEBUG_MODE}" != "true" ]; then
echo "SEHLL DEBUG_MODE: true"
echo "PHP DEBUG_MODE: ${DEBUG_MODE}"
echo "发布失败!!!"
exit
fi
SYNC_MODE='debug'
fi

## 替换配置文件
php change_config.php ${SYNC_MODE}

### 接下来,同步到线上环境 ###
……
……
……
echo "发布成功!!!"

### 同步完毕之后,将配置文件复原回本机配置
php change_config.php "local"
echo "已复原回本地配置"
替换功能脚本示例:
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
<?php

if(count($argv) < 2)
{
die('PHP 参数错误');
}


$target = $argv[1];

if($target == 'release')
{
$MYSQL_HOST = 'MYSQL_HOST_REAL';
$MYSQL_DB_NAME = 'MYSQL_DB_NAME_REAL';
$MYSQL_ACCOUNT = 'MYSQL_ACCOUNT_REAL';
$MYSQL_PASSWORD = 'MYSQL_PASSWORD_REAL';
$COOKIE_DOMAIN = 'COOKIE_DOMAIN_REAL';
}
else if($target == 'debug')
{
$MYSQL_HOST = 'MYSQL_HOST_DEBUG';
$MYSQL_DB_NAME = 'MYSQL_DB_NAME_DEBUG';
$MYSQL_ACCOUNT = 'MYSQL_ACCOUNT_DEBUG';
$MYSQL_PASSWORD = 'MYSQL_PASSWORD_DEBUG';
$COOKIE_DOMAIN = 'COOKIE_DOMAIN_DEBUG';
}
else if($target == 'local')
{
$MYSQL_HOST = 'MYSQL_HOST_LOCAL';
$MYSQL_DB_NAME = 'MYSQL_DB_NAME_LOCAL';
$MYSQL_ACCOUNT = 'MYSQL_ACCOUNT_LOCAL';
$MYSQL_PASSWORD = 'MYSQL_PASSWORD_LOCAL';
$COOKIE_DOMAIN = 'COOKIE_DOMAIN_LOCAL';
}
else
{
die('参数不合法');
}

function replace_variables($data, $var_name)
{
$reg = sprintf("#(const\ %s\ =\ ')[^']*(')#", $var_name);
$var_value = $GLOBALS[$var_name];

return preg_replace_callback($reg, function ($matches) use($var_value) {
return sprintf('%s%s%s', $matches[1], $var_value, $matches[2]);
},
$data
);
}

$file = 'YOUR_CONFIG_FILE_PATH';
$data = file_get_contents($file);

$data = replace_variables($data, 'MYSQL_HOST');
$data = replace_variables($data, 'MYSQL_DB_NAME');
$data = replace_variables($data, 'MYSQL_ACCOUNT');
$data = replace_variables($data, 'MYSQL_PASSWORD');
$data = replace_variables($data, 'COOKIE_DOMAIN');

if($target == 'local')
{
$data = preg_replace("#(const\ DEBUG\ =\ )[^;]*(;)#", "$1true$2", $data);
}

file_put_contents($file, $data);

实践

假设发布脚本名为 sync.sh

发布到线上测试环境

1
./sync.sh

发布到线上正式环境

首先,先去修改配置文件,将 DEBUG 标识位 设置为 false,然后执行命令。

1
./sync.sh release

为了安全,发布到正式环境必须加一个步骤进行确认;而正式发版这个工作并不频繁,多一个步骤也并不过分。