分类 技术向 下的文章

'0xff'==255, true or false? 略谈所谓的“2019阿里面试题”

'0xff'==255 对还是错? 再谈所谓的“2019阿里面试题”

背景

近日,php吧有吧友发布了一个所谓的2019阿里面试题。且不论真假,
里面有一道题很有意思,而且目前还没有看见一个人出来纠正这个问题。

题目如下:

$x = null;
if ('0xFF' == 255) {
    $x = (int)'0xFF'; 
}
//var_dump($x); 

问题:$x的值是多少?

他们给了这样一个“公认”的答案: $x=0而不是255。 然后后面一字一句的说得头头是道,差点让人信以为真。可静下心来,再读这段代码,仔细推敲后,发现了“完全不一样”的答案。

令人深思的十大问题之一

令人觉得可笑的是,这道号称令人值得深思的十大问题之一的问题似乎并没有多少人拿到这道题真正的去深思,甚至哪怕是动手运行一下,显然,“拿来主义”并不是一个良好的学习方式。

那么答案到底是什么呢?

答案是,此题条件不足,无解或存在特解

说人话就是,在不同的php版本下,这段代码有着不同答案

答案

在php7+环境下,$x 的值为null. 对,这是一个你最不可能相信的答案。

在php5.6-环境下,$x的值为0.

寻找根源

这是一个非常奇怪的答案,不应该会出现这种情况,除非是刻意而为之。
一个很容易想到的关键,应该是'0xFF' == 255这里出现问题。

字符串与数字进行比较,根据C语言的类型转换运算,低类型应该向高类型进行隐式转换。所以这里字符串要转为int类型。明显根据经验,php会使用is_numeric进行转换,看来,问题的根源就在于此了。

证明猜测

为了证明猜测的正确性,我们可以用以下语句来检验。

$x = null;
if ('0xff' == 255) {
    $x = (int)'0xFF'; 
}
var_dump('0xff'+0); 
var_dump(is_numeric('0xff'));
var_dump((int)'0xff');
var_dump('0xff' == 255); 
语句php7.xphp5.x对比
'0xff'+0int(0)int(255)出现差异
is_numeric('0xff')bool(false)bool(true)出现差异
(int)'0xff'int(0)int(0)正常
'0xff' == 255bool(false)bool(true)出现差异

语句解释:

'0xff'+0 : 强制类型转换且不改变数值,非常常见的一种数值化字符串方法。

is_numeric('0xff'):判别字符串形式下的十六进制,php5.x与7.x相差较大,见后文说明。

(int)'0xff':使用int强制转换,从左到右读取数字,遇到非数字结束。

'0xff' == 255):对比结果。

很明显,结果出来了。确实是is_numeric出现了问题。
事实上,官网手册上也验证了我的猜测。

PHP 7.0.0+ Strings in hexadecimal (e.g. 0xf4c3b00c) notation are no longer regarded as numeric strings, i.e. is_numeric() returns FALSE now.

如此,为何

为何要更改对字符串形式的16进制的解析呢?这个问题说来也简单。因为is_numeric并不是一个安全的函数,解析字符串形式的16进制很可能引起sql注入的安全问题,这里不过多讨论,想了解更多的请百度相关文章。所以在php7+,is_numeric不再解析字符串形式的16进制,是为了更加的安全。不论这道题是否是所谓的“2019阿里面试题”,希望所有还在这条路上摸索的人,都要去质疑这种网上流传已久的“神”题。我更加希望这不是阿里的面试题,因为如果HR不加思索的从网上“拿”这个题目出来让这些phper去做,甚至连技术负责人把关都没把到,那可能又是一番笑话了。所以,环境才是最重要的,代码离开了环境,谁能保证永远坚持不懈的动下去。共勉

优化分支结构,向“简、并、雅”看齐

优化分支结构,简化代码,提高可读性

好久没有写文了,毕竟人是越来越懒的。

之前写过一文,说的是 减少if-else的滥用,提高代码可读性。里面提到了用if-return、表驱动等多种方法来代替if-else,可是具体该怎么用以及改进的方式并不是那些清晰。今天说的这个其实还是一样的,不过在此基础上,又添加了一些内容。

- 阅读剩余部分 -

epubBuilder——用php来实现txt转epub功能

背景

闲暇之时,喜欢在我的ireader上面看点读物,当然,也免不了无聊时看点打发时间的小说。ireader就这点好,看网文方便。尽管号称有50w的书源,但是我关注的一些正经小说在上面也找不到,毕竟独家版权的不在少数。那就只有到处找一些精校后的资源(一般都是完结两三年的,对作者的影响较小。也会看正版啦,只不过自带商城上面没有,也没有办法离线保存),除开一些别人已经精心制作好的,其他一些epub尽管能用,但是内容和排版却不是那么尽人意。自己动手的话,耗时也比较大。有人会问,为什么不用一些转换工具,比如EasyPub、ePUBee Magic等呢?甚至还有在线转换工具ePUBee之类的。是啊,这么多可选择的工具,还要去造轮子。

可是这些工具都有共通之处,那就是会在一些你看不到的地方甚至看得到的地方增加广告。或许是我过于追求完美,无法容忍。所以便花了两个夜晚的时间制作出来这个无广告、无门槛(?)的工具————epubBuilder。这只是一个非常初期的版本,可以在本地使用,稍微改改就能直接上线变成一个互联网工具。岂不美哉?

食用指南

打开 index.php ,看到如下内容,需要填写的内容都在后面有备注,按实际情况填写即可。填写完成之后用CLI模式,控制台直接输入 php index.php即可

<?php
define('ROOT', dirname(__FILE__) . '/');
define('TMPDIR', ROOT . 'tmp');
define('OS', TMPDIR . '/OEBPS/');
require ROOT . 'lib/epub.class.php';

## 填写区,勿动以上内容
$config = [
    'styles' => '', //自定义样式路径,本地
    'txtPath' => ROOT . '此处填写txt文件名称', //把txt文件放到index.php文件目录下
    'coverImg' => '', //自定义封面图片路径,可以为网络图片地址,建议放在本地
    'toc' => false, //是否要插入正文目录. ireader对正文目录的兼容效果不好(实际上是不支持dl dd标签),默认关闭。
    'patternType' => 1, //必填,书籍目录类型,见下方参数说明,
    'creater' => '', //作者,必填
    'bookName' => '', //书名,必填
    'language' => 'zh-CN', //语言,默认中文
    'date' => date("Y-m-d"), //发布时间,默认当前日期
];


## 填写区结束,勿动以下内容

(new epub($config))->epub_builder();

参数patternType说明

1 第xxx章/回/部/节/集/卷 xxxx。标准格式推荐,大作基本符合类型1. 示例: 第1520章 我有男朋友了

2 类型1 + 简介/前言/序章/楔子/终章/后记/尾声/番外。在类型1的基础上扩充了其他常见标题,标题不包括段前空白。示例: 番外 我与男朋有的那段往事

3 同类型2,区别在于类型3包括段前空白,容错率底(匹配更精准,建议选择这个)示例:简介 我叫你老公

4 Chapter/Section 序号 标题。 英文书籍常用此格式,示例: Chapter 1 我来自地球

5 正文 序号。非标准格式,示例:正文 12

6 序号 标题。晋江常用标题,示例: 1 我就是李明亮,阁下?

实现思路

实现方法比较简单。epub的本质就是zip,所以只需要生成对应的html章节页面,和对应的目录信息之后,然后压缩到一起。html和目录均采用模板文件生成,这样处理之后的所有标准格式。

说说php的try-catch那些事情

写在前面

  首先,区别 ErrorException 两个概念,这是两个不同的东西。错误是不可忽视的,异常/高级别的错误通常会引起程序停止,而低级别的错误如notice等是可选择忽视的,一般不会造成程序停止运行。当然,个人认为,在不区分语境的情况下,有时出错和出问题可以认为是同一个意思,尽管这两者产生的影响程度上有很大的差别。当我们说到抑错机制的时候,很自然的联想到try-catch接下来说的内容以try-catch的某些方面通过问题的形式展开。

- 阅读剩余部分 -

减少if-else的滥用,提高代码可读性

背景

我遇见不少人都是这样,多层逻辑嵌套,看似条例清晰、逻辑关系明了。实际上读起来真的很费力。看个最简单的例子,一吧友A想要发一个帖子宣传xx产品,需要征求所有吧主(bz1,bz2)一致同意后才可以发帖。

方案 

有人可能会这样写:

function getPostAgree(){
    $agree = false; //flag
    if ($bz1 == "agree){
        $agree = true;
        if ($bz == "agreem){
            $agree = true;
        }else{
            $agree = false;
        }
    } else {
        $agree = false;
    }
 return $agree;
}

看上去很自然. 逻辑也很清楚,bz1同意了之后bz2再同意肯定就没啥问题了.
有人会这样写:

function getPostAgree(){
    $agree == false; //flag
    if($bz1 == 'agree' && $bz2 == "agree"){
        $agree = true;
    }else{
        $agree = false;
    }
    return $agree;
}

这样看上去逻辑更加清楚了,两个吧主同时同意.
还有第三种 第四种:

function getPostAgree(){
    $agree == false; //flag
    if($bz1 == 'disagree'){
        return $agree;
    }
    if($bz2 == 'disagree'){
        return $agree;
    }
    return $agree=true;
}
function getPostAgree(){
    $agree == false; //flag
    $bz = [$bz1,$bz2];
    if(!in_array('disagree',$bz)){
     $agree=true;
}
return $agree;

以上看上去都行得通,那么现在又多个1个吧主呢?10个呢?50个呢?
第一个嵌套50个if - else
第二个写49个&&
第三个写50个if
第四个,变成50的数组。而且,同时可以分离出所有bz

$bz = [$bz1,$bz2];
function getPostAgree()
{
    global $bz;
    $agree = false; //flag
    $agree == !in_array("disagree", $bz);
    return $agree;
}

如何改进?

  • 嵌套逻辑用平行逻辑代替
  • 使用表驱动减少判断
  • 不是必要的if-else,能不else就别else,不要if-elseif-elseif...-elseif-else
  • if-return 代替 if-else
    .....

翼讯netkeeper常见错误代码帮助

前言

本文档提取于高校客户端自带帮助文件,并依据实际情况做了一定的调整。部分操作可能需要对电脑有一定了解的童鞋才能流畅的进行,页面中带有相当量的截图以及大量的注释。如果仍有问题,可以在本页面下方附加评论。

代码大全

错误代码:112   获取拨号模块信息失败,找不到模块信息
错误代码:120   加载升级程序配置信息失败
错误代码:123   升级程序启动失败,请检查用户目录权限
错误代码:130   忘记账号
错误代码:131   忘记密码
错误代码:132   修改密码
错误代码:133   解除手机号码绑定
错误代码:134   程序未正常启动,可能是由于未正常安装或主程序被移动
错误代码:135   加载资源文件失败
错误代码:136   软件运行环境被破坏
错误代码:137   发现代理软件,请确认退出代理软件
错误代码:619   无法连接到指定的服务器,用于此连接的端口已关闭
错误代码:629   连接被远程计算机终止
错误代码:633   调制解调器(或其它连接设备)已在使用,或没有正确配置
错误代码:651   调制解调器(或其他连接设备)报告了一个错误
错误代码:678   远程计算机没有反应
错误代码:691   已拒绝远程连接,因为未识别出你提供的用户名和密码组合
错误代码:711   操作无法完成,因为他无法及时启动远程访问连接管理器服务,请重试此操作
错误代码:718   因为远程计算机不能及时反应,此连接已被终止。
错误代码:720   不能建立到远程计算机的连接,你可能需要更改此连接的网络设置
错误代码:756   已经拨打该连接
错误代码:769   无法连接到指定目标
错误代码:813   建立了前一个宽带连接的情况下,你在使用相同的设备或端口尝试建立一个宽带连接,请断开前一个连接,然后重新建立连接

Apache 和Nginx启用https 的一些要点心得

因为之前的域名比较敏感,所以ssl证书一直没办法通过审核。
最近终于狠下心,换了一个域名,开启了完美的ssl之旅~
Apache和nignx启用的实际上配置并不复杂,只不过有一些步骤非常容易忽略。
下面简单的说说启用https需要注意的要点:

Apache

模块的开启

  打开Apache根目录下 conf/httpd.conf 文件,
找到 #LoadModule ssl_module modules/mod_ssl.so
去掉前面的注释符号 #

配置

打开 vhosts.conf
添加如下内容


    DocumentRoot "C:/www/html"
#网站目录
    ServerName www.domain.com
#www.domain.com 你的域名
    SSLEngine on
    SSLCertificateFile   这里填入路径/2_www.domain.com_cert.crt
    SSLCertificateKeyFile  这里填入路径/3_www.domain.com.key
    SSLCertificateChainFile  这里填入路径/1_root_bundle.crt
 

注:

配置文件参数 说明
SSLEngine on 启用SSL功能
SSLCertificateFile 证书文件
SSLCertificateKeyFile 私钥文件
SSLCertificateChainFile 证书链文件

添加hosts

将下面两行加入hosts文件内
127.0.0.1 www.domain.com 127.0.0.1 domain.com
注:hosts 文件通常在 C:\Windows\System32\drivers\etc内,如果找不到建议在C盘内直接搜索hosts

Nginx

配置

打开 vhosts.conf
添加如下内容

server {
        listen 443;
        server_name www.domain.com; #填写绑定证书的域名
        ssl on;
        ssl_certificate 1_www.domain.com_bundle.crt;#同Apache,建议放到nginx/conf目录下,这样可以不用写绝对路径了
        ssl_certificate_key 2_www.domain.com.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #根据证书提供的协议配置,不可照搬
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照证书提供的套件配置,不可照搬
        ssl_prefer_server_ciphers on;
        location / {
            root   C:/www/html; #站点目录 
            index  index.html  index.php index.htm ;
        }
    }

注:

配置文件参数 说明
listen 443 SSL访问端口号为443
ssl on 启用SSL功能
ssl_certificate 证书文件
ssl_certificate_key 私钥文件
ssl_protocols 使用的协议
ssl_ciphers 配置加密套件,写法遵循openssl标准

添加hosts

将下面两行加入hosts文件内
127.0.0.1 www.domain.com 127.0.0.1 domain.com
注:hosts 文件通常在 C:\Windows\System32\drivers\etc内,如果找不到建议在C盘内直接搜索hosts

htaccess详解:URL重写与重定向


URL重定向是.htaccess的重头戏,它可以将长地址转为短地址、将动态地址转为静态地址、重定向丢失的页面、防止盗链、实现自动语言转换等。笔者觉得难点是在正则表达式的运用和理解上。

准备开始:mod_rewrite

实现所有这些神奇功能的模块叫做mod_rewrite,请确保你的服务器安装并启用了该模块:

sudo a2enmod rewrite

我们一般会把所有涉及URL重写或者重定向的代码这样放置:

<IfModule mod_rewrite.c>
 # Turn on rewrite engine
 Options +FollowSymlinks
 RewriteEngine on
 # More rules below
 ...
</IfModule>

一些我们需要注意的地方:

  • FollowSymlinks必须启用,这是rewrite引擎的安全需求。
  • 通常FollowSymlinks在Apache的主配置文件中就已经启用了,所以通常可以省略。
  • RewriteEngine命令用于启用rewrite引擎
  • IfModule命令用于判断Apache是否安装了mod_rewrite模块,之后笔者会省略该命令,但不代表这是个好习惯。
  • mod_rewrite会处理所有提交给Apache的URL请求,并与之后的规则进行匹配

下面我们开始讲解一些例子。

利用.htaccess实现URL重写(rewrite)与URL重定向(redirect)

将.htm页面映射到.php

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*).htm$ $1.php [NC]

注意事项:

  • 该RewriteRule能够将.htm静态页面映射到.php动态页面
  • 如果通过.htm进入,浏览器地址栏显示的是.htm扩展名,但服务器上实际执行的是.php
  • 必须保证服务器上有对应的.php,否则会404
  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页
  • 如果该目录上存在.htm,将被忽略
  • [NC]表示“不区分大小写”

临时重定向(R=302)与永久重定向(R=301)

RewriteEngine on
RewriteBase /
RewriteRule ^(.*).htm$ $1.php [R,NC,L]

注意事项:

  • 该RewriteRule能够将.htm静态页面重定向到.php动态页面
  • 如果通过.htm进入,浏览器地址栏会自动转为.php,这也是重定向的本质
  • 必须保证服务器上有对应的.php,否则会404
  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页
  • 如果该目录上存在.htm,将被忽略
  • RewriteBase定义了重写基准目录
  • 例如,如果你将虚拟站点设置在/var/www目录下,删除这行将会导致重定向到http://yourdomain.com/var/www/1.php。显然这是找不到的,而且你也不会希望用户看见你的服务器的目录结构。
  • 再举个例子,如果RewriteBase /base/,那么将会重定向到http://yourdomain.com/base/1.php。
  • 对于重写基准目录,我们还可以通过将$1.php变成/$1.php实现直接变换,这时就可以将RewriteBase省略。
  • 字母R表示临时重定向,相当于[R=302,NC]
  • 字母L表示如果能匹配本条规则,那么本条规则是最后一条(Last),忽略之后的规则。

在讨论R=302临时重定向后,理解R=301永久重定向也就容易多了:

RewriteEngine on
RewriteRule ^(.*)$ http://newdomain.com/$1 [R=301,NC,L]
  • 这个规则告诉浏览器和搜索引擎,网站地址发生了永久性变更,用户的URL请求将会被发送给新的域名(主机)处理。
  • 由于是重定向到新的主机地址,RewriteBase也就没有出现的必要了。

为什么要用重定向?——重定向和URL重写的区别

  • 通过重定向,浏览器知道页面位置发生变化,从而改变地址栏显示的地址
  • 通过重定向,搜索引擎意识到页面被移动了,从而更新搜索引擎索引,将原来失效的链接从搜索结果中移除
  • 临时重定向(R=302)和永久重定向(R=301)都是亲搜索引擎的,是SEO的重要技术
  • URL重写用于将页面映射到本站另一页面,若重写到另一网络主机(域名),则按重定向处理

长短地址转换

利用URL重写,我们可以很方便地实现长短地址的转换,但是用重定向就不合适了。

RewriteEngine On
RewriteRule ^grab /public/files/download/download.php

若访问
http://mysite/grab?file=my.zip
则会执行该页面:
http://mysite/public/files/download/download.php?file=my.zip

去掉www

Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]

加上www

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*)$
RewriteRule (.*) http://www.%1/$1 [R=301,L]

支持多域名访问

如果你不凑巧买到了不支持多域名的主机,那么.htaccess或许可以帮助你。现在假设你有域名domain-one.com和domain-two.com,并且在服务器根目录有对应文件夹one和two,那么通过下面的改写就能让Apache同时接受者两个域名的请求:

#two domains served from one root..
RewriteCond %{HTTP_HOST} domain-one.com
RewriteCond %{REQUEST_URI} !^/one
RewriteRule ^(.*)$ /one/$1 [L]

RewriteCond %{HTTP_HOST} domain-two.com
RewriteCond %{REQUEST_URI} !^/two
RewriteRule ^(.*)$ /two/$1 [L]

改写查询字符串QUERY_STRING

查询字符串是指URL请求中“问号”后面的部分。比如,http://mysite/grab?foo=bar中粗体部分就是查询字符串,其中变量名是foo,值是bar。

利用QSA转换查询字符串QUERY_STRING

QSA标志( Query String Appending)用于在URI中截取查询字符串,这个截取操作是通过小括号正则表达式实现的:

RewriteEngine On
RewriteRule /pages/(.+) /page.php?page=$1 [QSA]
  • 将会把请求/pages/123?one=two 映射到 /page.php?page=123&one=two
  • 注意粗体部分几乎是相同的,除了“问号”变成了“与”符号
  • 如果没有QSA标志,那么会映射到/page.php?page=123
  • 如果没有用到小括号正则表达式,就不需要QSA,这在上节“长短地址转换”中已经例证过了。
  • 小括号正则表达式可以截取查询字符串中的内容,但是如果没有开启QSA标志,那么在/page.php?page=$1中“问号”之后将会被剥离丢弃。这种特性可以用于实现“剥离查询字符串”

通过QSA,我们可以将简单链接/simple/flat/link/ 映射成 server-side.php?first-var=flat&second-var=link

RewriteEngine On
RewriteRule ^/([^/]+)/([^/]+)/? /index.php?first-var=$1&second-var=$2 [QSA]

利用RewriteCond改写查询字符串QUERY_STRING

RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.*)
RewriteRule ^grab(.*) /page.php?bar=%1
  • 该规则将访问请求http://mysite/grab?foo=bar转换为http://mysite/page.php?bar=bar
  • RewriteCond用于捕获查询字符串(QUERY_STRING)中变量foo的值,并存储在%1
  • QUERY_STRING是Apache定义的“变量=值”向量(数组)

QSA与RewriteCond双剑齐发

RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.+)
RewriteRule ^grab/(.*) /%1/index.php?file=$1 [QSA]
  • 会把/grab/foobar.zip?level=5&foo=bar 映射到 /bar/index.php?file=foobar.zip&level=5&foo=bar
  • 转换后根目录是bar目录
  • foobar.zip?level=5中的“问号”变成了foobar.zip&level=5中的“与”符号

剥离查询字符串

只需在要开始剥离的链接后面加个“问号”,并且不要启用QSA标志,就可剥离查询字符串

RewriteEngine On
# Whatever QS is
RewriteCond %{QUERY_STRING} . 
# I don't want it with Question mark
RewriteRule foo.php(.*) /foo.php? [L] 

利用RewriteCond和RewriteRule进行访问控制

我们在第一篇.htaccess基础中提到了很多有用的访问控制方法,其实通过Rewrite也能实现类似的功能,而且可以更强大!

文件访问控制

之前利用Order、Files及FilesMatch命令实现的访问控制可以满足大部分要求,但是当用户被拒绝时,他们看到的是硕大的“403 Forbidden”,如果你不想伤害用户的感情,就需要显示一些别的东西,通过Rewrite就可以实现这个特性:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^(.+).css$
RewriteCond %{REQUEST_FILENAME} !^(.+).js$
RewriteCond %{REQUEST_FILENAME} !special.zip$
RewriteRule ^(.+)$ /chat/ [NC]
  • 该规则将仅允许用户请求.css, .js类型的文件,还有special.zip文件
  • RewriteRule 后面指定了限制规则:映射到/char/目录下处理
  • RewriteCond 后面的“感叹号”(!)起到了“否定”作用,它表明,对不满足后面正则表达式者应用RewriteRule规则,也就是对当前类型的文件将不应用规则
  • RewriteCond 之间是以逻辑“与”连接的,也就是只有当三个条件都不满足时才执行RewriteRule
  • 该规则也会限制访问.htm, .jpg等格式
  • 该规则不可以放在虚拟站点根目录(/)下,否则会死循环
  • 如果是二级目录,如/test/,那么传入RewriteCond的参数是以/test/开始的,因此从(.+)获得的文件名也含有/test/,读者必须对此多加小心
  • 要想仅获得文件名,可以将(.+)替换成([^/]+),并且去掉符号^,如下所示:
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !([^/]+).css$
    RewriteCond %{REQUEST_FILENAME} !([^/]+).js$
    RewriteRule ^(.+)$ /chat/ [NC]
    

用.htaccess阻止User-agent

什么是User-agent?User-agent用于浏览器向服务器“自报家门”,更确切的说是所有HTTP客户端都得用User-agent向服务器“自报家门”,以便服务器对不同的客户端作出不同响应。比如,某站点可能需要对浏览器、搜索引擎crawl还有各类下载工具作出不同的响应。服务器就是通过所谓的User-agent进行区分的。
如果你的服务器提供某些资源的下载,那么你就必须多加小心诸如“迅雷”等下载软件,因为它们可能把你网站资源吸干,并且影响你的正常访客访问。为此,我们可以利用Rewrite限制某些UA的访问:

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC]
RewriteRule . abuse.txt [L]
  • 该规则限制“迅雷”客户端下载资源,并将下载文件重置到abuse.txt
  • HTTP_USER_AGENT是Apache的内置变量
  • 2.0.50727是迅雷User-agent的特征字符串
  • RewriteRule后面的“点”表示“任意URI”,也就是不管请求的是什么,都输出abuse.txt

通常,我们不会仅限制一个UA。利用[OR]即可实现对多个UA作出统一处理:

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^BlackWidow [NC,OR]
# etc..
RewriteCond %{HTTP_USER_AGENT} ^Net Vampire [NC]
RewriteRule . abuse.txt [L]

用.htaccess阻止盗链(hot-linking)

盗链,特别是图片,是非常可耻的!哪怕将图片复制到自己服务器上,也比盗用他人的图片链接来得光彩!(吐糟完毕)
.htaccess的Rewrite功能可以提供非常简单、有效的方法阻止这种可耻行为:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?52fisher.cn/ [NC]
RewriteCond %{REQUEST_URI} !hotlink.png [NC]
RewriteRule .*.(gif|jpg|png)$ /hotlink.png [NC]

简单解释一下该规则的功能:

  • 除本站以外其他网站都不得引用本站图片,具体可以理解为
  • 如果引用站点为“空”或者是“本站”,或者,所引用对象是“hotlink.png”,那么就允许访问
  • 再次提醒,RewriteCond之间默认的逻辑连接词是逻辑“与”
  • 这里的难点是理解逻辑转换,即德·摩根定律