一、前提
环境: Ubuntu服务器,已经默认安装了apache2和php7,账号具备sudo权限。 问题:
-
- 本地数据从JAVA平台导出,同时考虑易用和数据安全,采用Sqlite3数据库并基于Sqlcipher v4方式加密;
-
- 需要在这台服务器上搭建一个php简易网站,并从本地读取数据用于显示;
故需要在服务器上开启php sqlite3扩展支持,并且支持能够和JAVA平台兼容的如上加密方式。
二、步骤
首先是查询Sqlcipher相关信息,发现这玩意虽然是开源的,但是对于多平台都是企业支持,包括SQLCipher for JDBC,对于PHP的支持,stack overflow上推荐的官网教程页面也打不开,可能已经被移除了。
1.JAVA平台
于是查询采用其他开源方案,JDBC使用sqlite-jdbc-encrypt,可以在github上下载最新的jar并导入java工程,该包支持对多种sqlite3的多种加密方式,其中包括Sqlcipher,具体信息可以查询其github主页说明,在java平台的代码示例如下:
private static final String SQL_URL = "jdbc:sqlite:file:mydata.db?cipher=sqlcipher&legacy=4&key=mykey";
private static Connection mConn = null;
public static boolean open() {
System.out.println("open...");
if (mConn != null) return true;
try{
mConn = DriverManager.getConnection(SQL_URL);
} catch (SQLException e) {
e.printStackTrace();
}
return mConn != null;
}
public static void viewData() {
System.out.println("viewData...");
try (Statement st = mConn.createStatement()) {
ResultSet rs = st.executeQuery("SELECT * FROM mytable;");
int columnCount = rs.getMetaData().getColumnCount();
while (rs.next()) {
for (int i=0; i<columnCount ; ++i) {
System.out.print(rs.getString(i));
}
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close() {
System.out.println("close...");
try {
if (mConn != null && !mConn.isClosed())
mConn.close();
} catch (SQLException e) {
e.printStackTrace();
}
mConn = null;
}
2. PHP平台
PHP平台支持sqlite3加密确实比较麻烦,全网上也没搜到啥完整的教程,根据查到各种信息一步一步自己摸索。
2.1 编译
首先是编译带加密的sqlite3扩展库,先去官网上下载对应版本的PHP源码,在Ubuntu上输入php -v 可以看到版本号,这里是PHP7.0.33 ;
进入PHP官网-Download页面,点击进入右侧的Old archives页面,在这个页面下搜对应版本,选择喜欢的格式下载源码,之后在Ubuntu下解压备用;
然后就是下载加密扩展的源码,一开始是打算下载sqlcipher源码,奈何官网教程打不开,于是转向另一个开源的wxSqlite3项目,在Release中选择版本(最好选择与PHP版本兼容的sqlite3版本,可以在php源码ext/sqlite3/libsqlite/sqlite3.c 中查看),这里下载的是wxsqlite3-4.5.1,下载源码在Ubuntu下解压备用;
从wxSQLite3 4.6.0(sqlite3.32.0)版本开始,加密扩展已经作为独立源码移到另外一个SQLite3MultipleCiphers项目,src 下的代码对应wxsqlite3的sqlite3secure/src 下的代码
然后进入编译阶段,先把wxsqlite3源码的sqlite3secure/src 下的代码复制覆盖到php源码的ext/sqlite3/libsqlite/sqlite3.c 目录,然后cd到php源码的"ext/sqlite3/"目录下依次执行(SQLite3MultipleCiphers源码CFLAG配置参考对应的官方文档):
$ ./configure CFLAGS="-DSQLITE_HAS_CODEC -DCODEC_TYPE=WXSQLITE3_USE_SQLCIPHER_LEGACY -DWXSQLITE3_USE_SQLCIPHER_LEGACY=4"
$ phpize
$ make && sudo make install
成功后,可以看到类似如下信息:
Installing shared extensions: /usr/lib/php/20151012/
Installing header files: /usr/include/php/20151012/
2.2 开启php的sqlite3扩展
进入到/etc/php/7.0/apache2/conf.d 目录,执行ls -al ,可以看到这里以链接方式包含所有从apache2方式启动php的扩展配置文件:
...
20-ftp.ini -> /etc/php/7.0/mods-available/ftp.ini
20-gettext.ini -> /etc/php/7.0/mods-available/gettext.ini
20-iconv.ini -> /etc/php/7.0/mods-available/iconv.ini
20-json.ini -> /etc/php/7.0/mods-available/json.ini
20-phar.ini -> /etc/php/7.0/mods-available/phar.ini
20-posix.ini -> /etc/php/7.0/mods-available/posix.ini
20-readline.ini -> /etc/php/7.0/mods-available/readline.ini
20-shmop.ini -> /etc/php/7.0/mods-available/shmop.ini
20-simplexml.ini -> /etc/php/7.0/mods-available/simplexml.ini
20-sockets.ini -> /etc/php/7.0/mods-available/sockets.ini
...
参考已有的配置文件格式,配置sqlite3扩展:
-
a) 使用vi创建一个sqlite3配置文件 sudo vi /etc/php/7.0/mods-available/sqlite3.ini -
b) 在vi界面按Inert 键启动编辑,写入内容 extension=sqlite3.so -
c) 按Esc 退出编辑,同时按Shift +: 键,输入wq 保存文件 -
d)在当前/etc/php/7.0/apache2/conf.d 目录下创建链接 sudo ln -s /etc/php/7.0/mods-available/sqlite3.ini 20-sqlite3.ini -
e) 重启apache2服务使配置生效 sudo service apache2 restart
如果需要同时开启php调试信息显示,可以在步骤d之后,编辑/etc/php/7.0/apache2/php.ini 文件,将其中的display_errors = Off 改为display_errors = On ,然后执行步骤e重启服务生效
2.3.PHP使用加密数据库
最后就是在PHP平台上操作加密数据库。虽然编译生成的sqlite3扩展库已经支持加密了,但是php对其依然只能使用默认sqlite3支持的操作接口,无法通过wxsqlite3特定的接口实现加密配置和操作。
关于这一步也没有搜到相关的信息,除了这篇《利用wxsqlite3实现php-sqlite3加密扩展》的博客涉及到windows平台的编译和针对php平台添加额外的加密接口,其他的基本都是人云亦云;
最后在下载的wxsqlite3-4.5.1源码下的sqlite3secure/readme.md 中找到相关的信息(github文档,SQLite3MultipleCiphers源码参考对应的官方文档),可以采用SQL语句的方式调用对应的接口实现加密配置和操作,具体php代码参考如下:
$db=new SQLite3("mydata.db");
$result = $db->query("SELECT wxsqlite3_config('default:cipher', 'sqlcipher');");
var_dump($result->fetchArray(SQLITE3_ASSOC));
$result = $db->query("SELECT wxsqlite3_config('sqlcipher', 'legacy', 4);");
var_dump($result->fetchArray(SQLITE3_ASSOC));
$result = $db->exec("PRAGMA key='mykey'");
var_dump($result);
$result = $db->exec("create table mytable (name varchar(200));");
var_dump($result);
$db->exec("insert into mytable (name) values ('xxxxxx')");
$result = $db->query('SELECT * FROM mytable;');
while($row = $result->fetchArray(SQLITE3_ASSOC)) {
var_dump($row);
}
$db->close();
实测在PHP下使用该方法的配置和操作,可以和JAVA平台通过sqlite-jdbc-encrypt配置和操作的本地Sqlite3数据库完美兼容,至此问题解决。
二、最后
由于在Ubuntu基于PHP中扩展使用加密的sqlite3的资料实在甚少,官方社区对涉及三方库的问题支持也比较模糊,故有此文作为记录和参考,有需要的朋友也可参考。
|