2012年6月11日星期一

【转】htaccess 防止盗链,防止目录浏览等10大技巧

1. 反盗链
那些盗用了你的内容,还不愿意自己存储图片的网站是无耻的。你可以通过以下配置来放置别人盗用你的图片:
 
1 RewriteBase /
2 RewriteCond %{HTTP_REFERER} !^$
3 RewriteCond %{HTTP_REFERER} !^http://(www.)?yoursite.com/.*$ [NC]
4 RewriteRule .(gif|jpg|swf|flv|png)$ /feed/ [R=302,L]
2. 防止目录浏览
有时候目录浏览是有用的,但大部分情况会有安全问题。为了让你的网站更安全,你可以通过htaccess文件来禁用这个功能:
 
1 Options All -Indexes


3. SEO友好的301永久重定向
这一招是我常用的。每次我更改网站URL结构的时候,我都会做301重定向:
 
1 Redirect 301 http://www.yoursite.com/article.html http://www.yoursite.com/archives/article
4. 显示个性化的 404 错误页面
当用户访问了一个不存在的页面的时候,网页服务器会显示“404 file not found”错误。有很多CMS可以让你设置自定义的错误页面,但最简单的方法是更改htaccess:
 
1 ErrorDocument 404 /404.html


5. 设置目录的默认页面
假如你需要为不同的目录设置不同的默认页面,你可以很容易的通过 .htaccess 实现:
 
1 DirectoryIndex about.html
6. 基于referer来限制网站访问
站长通常不会限制网站访问,但是当你发现有一些网站尽给你带来垃圾流量的话,你就应该屏蔽他们:
 
1 <IfModule mod_rewrite.c>
2 RewriteEngine on  RewriteCond %{HTTP_REFERER} spamteam.com [NC,OR]
3 RewriteCond %{HTTP_REFERER} trollteam.com [NC,OR]
4 RewriteRule .* – [F]
5 </ifModule>
7. 限制PHP上传文件大小
这招在共享空间的服务器上很有用,可以让我的用户上传更大的文件。第一个是设置最大的上传文件大小,第二个是设置最大的POST请求大小,第三个PHP脚本最长的执行时间,最后一个是脚本解析上传文件的最长时间:
 
php_value upload_max_filesize 20M
2 php_value post_max_size 20M
3 php_value max_execution_time 200
4 php_value max_input_time 200


8. 压缩文件
你可以通过压缩文件来减少网络流量,也页面装载时间:
 
1 AddOutputFilterByType DEFLATE text/plain
2 AddOutputFilterByType DEFLATE text/html
3 AddOutputFilterByType DEFLATE text/xml
4 AddOutputFilterByType DEFLATE text/css
5 AddOutputFilterByType DEFLATE application/xml
6 AddOutputFilterByType DEFLATE application/xhtml+xml
7 AddOutputFilterByType DEFLATE application/rss+xml
8 AddOutputFilterByType DEFLATE application/javascript
9 AddOutputFilterByType DEFLATE application/x-javascript
9. 缓存文件
这一点还需要解释吗?
 
1 <FilesMatch “.(flv|gif|jpg|jpeg|png|ico|swf|js|css|pdf)$”>
2 Header set Cache-Control “max-age=2592000″
3 </FilesMatch>
10. 添加尾部的反斜杠
我并不确定,但是很多文章,很多人都说添加尾部反斜杠有益于SEO:
 
1 <IfModule mod_rewrite.c>
2 RewriteCond %{REQUEST_URI} /+[^\.]+$
3 RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
4 </IfModule>

 

摘自  PainsOnline的专栏

摘自:http://www.2cto.com/kf/201204/125949.html





 

[转]bluehost上定制.htaccess禁止浏览目录及网站安全知识

bluehost主机可以通过定制.htaccess来禁止浏览目录,以提高网站的安全性和灵活性,在.htaccess中加入下面的命令即可实现:

   # 禁止浏览目录    Options -indexes 

"Options -indexes"是一个重要的安全性指令,是所有.htaccess文件中必不可少的一项,除非需要指定某一目录的特殊用途才可以省略这一句,例如:提供列出文件索引方式的下载服务。

特别注意:
上面谈到用.htaccess来禁止浏览目录是一个安全措施,但您一定要清楚,所谓的安全是建立在一个前提之下,也就是说服务必须要在正常的前提下.htaccess才会起作用,如果服务器被攻击上面的措施可能没有真正用处,所以说不要在/public_html下存放不必要但很重要的数据,才是抓住了安全问题的本质,比如说您不可以将备份数据存放在/public_html之下,/public_html意味着发布,是公众可以访问,也可以通过大规模猜测尝试下载文件的目录,因此在这里或者是其下的子目录中存放www.zip、website.zip、data.zip、mysql.tar.gzip等类似文件是一种很白痴的行为,不论您设不设Options -indexes结果都是一样不安全的。

这样的话如果我们必须要放这类文件放在哪里哪?答案是放在/public_html的上一级目录,也就是您bluehost帐户的根目录下,或者放在根目录下创建的其它目录中,这里是公众访问不到的,我们却可以使用cPanel的文件管理器、FTP、SFTP类的工具来访问和操作,这样的条件也是合租用户不具备的这个原因和后面将提到的黑客脚本获得提升权限两者说明了合租空间对于网站数据来说非常危险的。

前面我们提到了可以在bluehost帐户的根目录下保存一些不希望被公众访问的文件,那么我们可以在这里放多久哪?答案是尽可能的短时间临时存放,因为这里只是相对安全,任何一个几十Kb的攻击脚本都能夺取权限越级访问到包括这里的所有目录。因此一个重要的原则是:不要在远程存放任何不必须的重要文件,如果必须要放,只能暂时存放要快一些删除,再有要使用无法猜测的、复杂的随机文件名。

2011年末的拖库密码门就是一个警钟,要我们加强安全意识,在轻描淡写的损失不大、影响有限的托辞之下,但愿说者不要自己都被自己说服了麻痹了,有没有影响有多大影响真有话语权的应该是当事的用户,访客是经不起多少折腾的,看上去延绵广大的事物从来都是易散难聚的,辛苦做大的网站还是当心不要一夜间崩溃吧。


摘自:http://www.bluehost-cn.com/bluehost-htaccess-ban-index-directory

2012年6月7日星期四

(转)sqlite fts3自定义分词器

摘自:http://hi.baidu.com/xjtukanif/blog/item/8e7a4ea5362abf99d14358e2.html

   sqlite3通过使用fts3虚表支持全文搜索,默认支持simple和porter两种分词器,并提供了接口来自定义分词器。这里我们利用mmseg来构造自定义的中文分词器。
      虽然sqlite在fts3_tokenizer.h中提供了各种接口供用户自定义分词器,但其并未提供c函数供用户来注册自定义的分词器,分词器的注册必须使用sql语句来完成。
    SELECT fts3_tokenizer(<tokenizer-name>, <sqlite3_tokenizer_module ptr>);
    其中tokenizer-name是分词器的名称,sqlite3_tokenizer_module ptr只一个指向sqlite3_tokenizer_module结构的指针并且编码为SQL blob。下面是官方给出的注册函数:
int registerTokenizer(
        sqlite3 *db,
        char *zName,
        const sqlite3_tokenizer_module *p
        ){
    int rc;
    sqlite3_stmt *pStmt;
    const char *zSql = "SELECT fts3_tokenizer(?, ?)";
    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    if( rc!=SQLITE_OK ){
        return rc;
    }
    sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
    sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
    sqlite3_step(pStmt);
    return sqlite3_finalize(pStmt);
}

    要想实现自定义的分词器,最关键的时是得到指向sqlite3_tokenizer_module结构的一个指针,sqlite3_tokenizer_module结构体定义如下:
struct sqlite3_tokenizer_module {
int iVersion; //版本号,必须设置为0
int (*xCreate)( //创建虚表时自动调用并创建分词器
    int argc,                          
    const char *const*argv,           
    sqlite3_tokenizer **ppTokenizer   
);
int (*xDestroy)(sqlite3_tokenizer *pTokenizer); //数据库连接关闭时自动调用,用于销毁资源
int (*xOpen)( //插入数据或检索时自动调用以进行分词
    sqlite3_tok enizer *pTokenizer,     
    const char *pInput, int nBytes,    
    sqlite3_tokenizer_cursor **ppCursor
);

int (*xClose)(sqlite3_tokenizer_cursor *pCursor); //分词结果提取完毕后自动调用

int (*xNext)( //逐个提取分词结果
    sqlite3_tokenizer_cursor *pCursor,  
    const char **ppToken, int *pnBytes,
    int *piStartOffset,
    int *piEndOffset,
    int *piPosition
);
};
    有几点需要注意的是:
    1 分词引擎使用sql语句注册意味着每建立一个sqlite连接都必须注册一次分词器,对于需要使用词库的中文分词器来说也意味着巨大的内存消耗。
    2 在检索时分词结果的提取和语义的解析式交替进行的。例如我们搜索"kanif OR sqlite"的时候,引擎先将全部传入到分词器,在调用一次next获取到词 kanif后,在将词sqlite传入到分词器,直到全部解析完毕。
    3 由于中文分词本身的特殊性,例如"北京市"很有可能视为一个完整的词,这样在搜索"北京"的时候就无法获取到结果。如果分词器支持将"北京市"切分为"北 京市"和"北京"或者将十一月切分为"11月"和"十一",那么需注意(*xNext)函数中的piStartOffset和piEndOffset参 数。经测试在插入数据的时候这两个参数无实际用途,但在查询的时候这两个参数决定了下一次的输入串。

附:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>

#include "fts3_tokenizer.h"
#include "mmseg/mmseg.cpp"

static bool loadDic = true;

typedef struct cus_tokenizer {
sqlite3_tokenizer base;
} cus_tokenizer;

typedef struct cus_tokenizer_cursor {
sqlite3_tokenizer_cursor base;
char *pInput;
int nBytes;
int iToken;
char *pToken;
rmmseg::Algorithm *pAlgor;
} cus_tokenizer_cursor;

void initmmseg(void){
    if(!loadDic)
        return;
    mmseg_load_words("chars.dic");
    mmseg_load_words("words.dic");
    loadDic = False;
}

static int cusCreate(
int argc, const char * const *argv,
sqlite3_tokenizer **ppTokenizer
){
cus_tokenizer *t;
t = (cus_tokenizer *) sqlite3_malloc(sizeof(*t));
if( t==NULL ) return SQLITE_NOMEM;
memset(t, 0, sizeof(*t));
initmmseg();
*ppTokenizer = &t->base;
return SQLITE_OK;
}

static int cusDestroy(sqlite3_tokenizer *pTokenizer){
sqlite3_free(pTokenizer);
return SQLITE_OK;
}

static int cusOpen(
sqlite3_tokenizer *pTokenizer,         /* The tokenizer */
const char *pInput, int nBytes,        /* String to be tokenized */
sqlite3_tokenizer_cursor **ppCursor    /* OUT: Tokenization cursor */
){
cus_tokenizer_cursor *c;
if(pInput == 0){
    nBytes = 0;
}else if(nBytes < 0)
     nBytes = (int)strlen(pInput);

c = (cus_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if(c == NULL)
      return SQLITE_NOMEM;

c->iToken = c->nBytes = 0;
c->pInput = c->pToken = NULL;
c->pAlgor = mmseg_algor_create(pInput, nBytes);
c->nBytes = nBytes;
*ppCursor = &c->base;
return SQLITE_OK;
}

static int cusClose(sqlite3_tokenizer_cursor *pCursor){
cus_tokenizer_cursor *c = (cus_tokenizer_cursor *) pCursor;
if(c->pInput != NULL){
    sqlite3_free(c->pInput);
}
if(c->pToken != NULL){
    sqlite3_free(c->pToken);
}
if(c->pAlgor != NULL){
    mmseg_algor_destroy(c->pAlgor);
}
c->pInput = c->pToken = NULL;
c->pAlgor = NULL;
sqlite3_free(c);
return SQLITE_OK;
}

/*
1 sqlite只有在插入数据的时候才使用cursor遍历
2 在进行数据查询时,只会进入一次,然后使用piStartOffset与piEndOffset根据原始串重新生成查询串
*/
static int cusNext(
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by cusOpen */
const char **ppToken,               /* OUT: *ppToken is the token text */
int *pnBytes,                       /* OUT: Number of bytes in token */
int *piStartOffset,                 /* OUT: Starting offset of token */
int *piEndOffset,                   /* OUT: Ending offset of token */
int *piPosition                     /* OUT: Position integer of token */
){
cus_tokenizer_cursor *c = (cus_tokenizer_cursor *) pCursor;
cus_tokenizer *t = (cus_tokenizer *) pCursor->pTokenizer;
if(c->pToken != NULL){
    sqlite3_free(c->pToken);
    c->pToken = NULL;
}
struct Token token = mmseg_next_token(c->pAlgor);
if(token.length != 0 ){
    int l = token.length;
    c->pToken = (char *)sqlite3_malloc(l+1);
    if(c->pToken == NULL)
        return SQLITE_NOMEM;
    c->pToken[l] = 0;
    memcpy(c->pToken, token.text, l);
    *ppToken = c->pToken;
    *pnBytes = l;
    *piStartOffset = token.offset;
    *piEndOffset = token.offset + token.length;
    *piPosition = c->iToken++;
    return SQLITE_OK;
}
//一般来说只有插入数据时才会进入到这里
return SQLITE_DONE;
}
static const sqlite3_tokenizer_module cusTokenizerModule = {
0,
cusCreate,
cusDestroy,
cusOpen,
cusClose,
cusNext,
};

int registerTokenizer(
        sqlite3 *db,
        char *zName,
        const sqlite3_tokenizer_module *p
        ){
    int rc;
    sqlite3_stmt *pStmt;
    const char *zSql = "SELECT fts3_tokenizer(?, ?)";
    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    if( rc!=SQLITE_OK ){
        return rc;
    }
    sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
    sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
    sqlite3_step(pStmt);
    return sqlite3_finalize(pStmt);
}

int main(){
    const sqlite3_tokenizer_module *ptr = &cusTokenizerModule;
    sqlite3 *pDB;
    sqlite3_stmt * stmt;
    char * errMsg = NULL;
    const char *zTail;

    int rc = sqlite3_open("test.sqlite3", &pDB);
    if(rc){
        printf("create error. %s\n",sqlite3_errmsg(pDB));
        return rc;
    }
    char token_name[] = "custoken";
    registerTokenizer(pDB, token_name, ptr);

    rc = sqlite3_exec(pDB, "CREATE VIRTUAL TABLE foo USING fts3(tokenize=custoken)", 0, 0, &errMsg);
    if(rc != SQLITE_OK){
        printf("create virtual error, %s\n", errMsg);
    if(rc != SQLITE_OK){
        printf("create virtual error, %s\n", errMsg);
        return rc;
    }
    rc = sqlite3_exec(pDB, "INSERT INTO foo VALUES('\xe5\x8c\x97\xe4\xba\xac\xe5\xb8\x82')", 0, 0, &errMsg);
    if(rc != SQLITE_OK){
        printf("insert value error, %s\n", errMsg);
        return rc;
    }
    int nrow = 0, ncolumn = 0;
    char **azResult; //二维数组存放结果
    sqlite3_get_table(pDB , "SELECT * FROM foo WHERE content MATCH '\xe5\x8c\x97\xe4\xba\xac\xe5\xb8\x82'" , &azResult , &nrow , &ncolumn , &errMsg );
    int i = 0 ;
    printf( "row:%d column=%d \n" , nrow , ncolumn );
    printf( "\nThe result of querying is : \n" );
    for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
          printf( "azResult[%d] = %s\n", i , azResult[i] );
    sqlite3_free_table( azResult );
    sqlite3_close(pDB);
    return 0;
}


PHP操作SQLITE3(转)

偶尔看到的,很有价值,可以作为参考,最吸引我的是Sqlite不用在客户端安装,或者做应用时在客户端不需要安装Sqlite软件,这样最大程度上方便的应用程序的分发。以下全文转过来,保留作者的博客信息。

------------------------------------------------------------------------------

http://julabs.me/blog/php/php-pdo-sqlite3/

 Sqlite是一个跨平台的软件,不需要安装或设置,只需在最终用户的系统上创建一个数据库文件就可以了,在平台和系统之间移植非常方便。由于它具有跨平台、规模小的特点,所以被很多公司使用,如MozillaAdobe,Symbian等。

这段时间我也打算学习下Sqlite,做一些简单的演示时非常方便,不用在最终用户的系统安装数据库环境了。但在利用PHP操作数据库时发现PHP默认只支持到Sqlite2,不支持最新版的Sqlite3。如果想支持Sqlite3就要使用PDO。要想使用PDO,需要在php.ini里面载入php_pdo.dllphp_pdo_sqlite.dll两个模块。如下:

extension=php_pdo.dll  extension=php_pdo_sqlite.dll  

如果这两段代码前面有;,就把它去掉。下面是我编写的Sqlite操作代码,一共有五个函数,分别是链接数据库、插入新数据、删除数据、更新数据和显示数据。

  /**   * 创建一个 sqlite3 链接   * @author Jon   * @return object 返回一个数据链接对象  */  function connectSqlite(){      // 设置数据库的位置      $db = "sqlite:".$_SERVER['DOCUMENT_ROOT']."/sqlite/web.db";      echo $_SERVER['DOCUMENT_ROOT']."/sqlite/web.db" . '
'
; $user = ""; $pass = ""; $dbHandle = new PDO($db,$user,$pass); echo 'Connected to database
'
; return $dbHandle; } /** * 插入新数据 */ function insertSqlite($conn){ $qry = $conn->query('select * from site'); //如果不存在,则创建表 if($qry ==false){ $conn->exec('create table mysite(name VARCHAR(30),url VARCHAR(50))'); } // 准备存入数据 $insert = $conn->prepare("INSERT into mysite VALUES(?,?)"); // 存入数据 $insert->execute(array('julabs','julabe.com')); $insert->execute(array('google','www.google.com')); } /** * 删除数据 */ function deleteSqlite($conn){ $conn->exec("DELETE FROM mysite WHERE name = 'google'"); } /** * 更新数据 */ function updateSqlite($conn){ $conn->exec("UPDATE mysite set url='julabs.me' WHERE name = 'julabs'"); } /** * 显示数据 */ function showSqlite($conn){ $sth = $conn->prepare("SELECT * FROM mysite"); $sth->execute(); $result = $sth->fetchAll(PDO::FETCH_ASSOC); echo '
共有'
. count($result) . '条数据
'; echo ''; echo''; foreach($resultas$row){ echo''; foreach($rowas$key => $val){ echo''; } echo''; } echo'
名称地址
'; echo $val; echo '
'
; } $connect = connectSqlite(); insertSqlite($connect); showSqlite($connect); updateSqlite($connect); showSqlite($connect); deleteSqlite($connect); showSqlite($connect); $connect = NULL;

 摘自:http://wwling2001.blogbus.com/logs/161014072.html