Web开发
.htaccess 防盗链 URL重写 ReWrite 目录访问权限
0.htaccess 可以做很多事!
一、防盗链
用 http 协议的 referer 字段,判断对文件请求是否来自相同的域名,如果是,可以正常访问,否则,跳转到其他 url。先来看一小段代码:
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://(.)+\.leakon\.com.* [NC]
RewriteRule .*\.(jpg|gif|bmp)$ http://www\.leakon\.com [L,NC]
他的作用是,当请求以 jpg、gif 或 bmp 为扩展名的文件,但 referer 字段不能匹配 http://*.leakon.com* 这个表达式时,服务器返回 302 状态码,重定向到 http://www.leakon.com。
这段代码用于图片站的图片防盗链是能够起到很大作用的,但不太适用于下载站。因为用户如果使用迅雷等专用软件下载文件,下载软件在发送请求的时候,会自动把目标文件所在的域名和路径作为 referer 加到请求里一起发给服务器。除非你能保证用户浏览网站页面的路径和文件所处的下载路径有很大区别,并且精心设计过上面的判断条件,否则,还是找其他办法来做到防盗链吧。
对使用 Windows 的 IIS 服务器的朋友, 如果你想给自己的网站加上防盗链功能,我向你推荐一款功能十分强大的防盗链软件:防盗链专家 ,这是我的一个好朋友开发的,现在已经稳定地运行在几万台 IIS 服务器上,而且很多下载站用的都是这套系统。
二、目录访问权限
有的时候,我们的程序需要读取一些配置文件,配置文件里可能包含一些重要的系统文件的路径,甚至是密码等信息。出于某些条件的限制,这些路径和文件又不能隐藏在 htdocs 目录的下面,都暴露给外网了。
怎样才能保护这些文件,避免被别人浏览到呢?
.htaccess 可以帮你做到。
这个功能使用起来非常简单,只需在你想保护的目录下面放置这个 .htaccess 文件,并添加一行代码即可:
deny all
这时所有对这个目录,以及这个目录的所有子目录的文件的请求都会被拒绝!
load data infile 导入数据 InnoDB 外键约束
0用户表:user
主键:id
内容表:post
主键:id
外键:user_id(关联到 user 表的主键 id)
post 表的数据文件存在文本文件中,字段之间用 tab 分隔,当要把文件导入到 post 表时,因 user 和 post 都是 InnoDB 引擎的,有外键约束,运行导入语句:
load data infile '/home/leakon/post.sql' ignore into table post ignore 1 lines ( user_id, title, unixtime );
MySQL 报错,信息如下:
Cannot add or update a child row: a foreign key constraint fails (`leakon/post`, CONSTRAINT `post_FK_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`))
反复尝试,总是失败,后来查了一下解决办法,只要在装载数据之前,插入下述语句,即可暂时关闭外键约束检查:
SET FOREIGN_KEY_CHECKS = 0;
然后再次运行 load data infile 语句,即可立即导入数据。
Symfony 数据库连接 utf8 (二)
1前文所述的代码,可以加在每个 Module 的 Actions 类的构造函数中,这样就确保了每次数据库链接时都是按照 utf8 编码进行传输和读取的。
但如果 Module 多了,到处重复代码可是一件烦人的事,也严重违反了 DRY(Don’t Repeat Youself) 原则,另外,有些 action 只显示一些表单或其他内容,并不需要数据库连接,而在构造函数中调用那段代码,每次都会连接数据库,造成了不必要的性能损失,因此,我们要进行一下小小的重构。
研究了 Symfony 的框架,发现他在做数据库方面的处理时,用了第三方的工具来封装,Creole 和 Propel,这 2 个工具之间的关系我还没深入研究,据我目前的理解,Creole 是对 MySQL 等数据库的底层封装,Propel 提供了应用层的逻辑代码,也就是说,在写跟逻辑有关代码时,用 Propel 把 SQL 语句封装起来,等语句都拼接好后,调用 Creole 的接口连接数据库。
我看了 Creole 的代码,找到了 getConnection 这个静态方法,他负责解析 DSN 并返回一个数据库连接。我们要做的,就是在每个需要数据库连接会话开始时,发送一条
语句,这个方法正好给了我们这个机会,因此,我在这个方法的 return 语句前面,调用了另一个方法:
self::setUTF8($obj);
?>
$obj 是 getConnection 要 return 的数据库连接。
打开 symfony/vendor/creole/Creole.php ,在 getConnection 方法的 return 前面加入上面这条语句,然后写出方法的定义:
if( !defined( 'IS_CONN_UTF8' ) ) {
define( 'IS_CONN_UTF8', 1 );
$query = 'SET NAMES "utf8"';
$statement = $connection->prepareStatement($query);
return $statement->executeQuery();
}
}
?>
说明:为了保证 SQL 语句只被发送一次,定义了宏作为判断标志。下次调用这个方法的时候,不会执行任何操作。
Symfony 数据库连接 utf8
0
$query = 'SET NAMES "utf8"';
$statement = $connection->prepareStatement($query);
$resultset = $statement->executeQuery();
?>
Symfony 在处理 PHP 与 MySQL 连接的时候,用的可能是 latin1 编码,也就是说,用户在表单里提交一个多字节字符串,比如“你好”,经历了如下几步,才进入到数据库:
1、浏览器把用户在输入框输入的内容按 utf8 编码,然后提交到服务端,PHP 接收到这个字符串;
2、PHP 建立 MySQL 连接,这个时候,用的是默认连接,如果当时 MySQL 服务器的连接编码是 latin1(通常默认都是 latin1),那么,PHP 会把接收到的字符串按 latin1 转码,然后传输给数据库;
3、数据库接收到这个字符串,要把它存到表里,由于接收过来的是 latin1 编码的字符串,则就按照这个编码存到表里。
这时会有个问题,数据库、表、字符串字段都是 utf8_general_ci 的编码方式,用 phpMyAdmin 查看,按说是能正常看到中文的。但是,由于 PHP 与 MySQL 是用 latin1 通讯,所以存到表里的是 latin1 字节序的字符,因此得到的是乱码。但是并不妨碍前端显示,因为在 PHP 取数据的时候,会按 latin1 -> utf8 的转换方式还原回来。虽然可以在前端页面正常显示,但我们维护数据库,备份、导入导出的时候看到一大堆乱码,显然很麻烦。
所以,有了最开始的那串代码,它的作用是,让 PHP 与 MySQL 用 utf8 编码方式进行通讯,数据库在往表里写入的时候,就是按照 utf8 字节序写的,因此我们用 phpMyAdmin 或者导出数据库文本文件的时候,都可以正常看到中文。
才疏学浅,不知所云
