初探dedecms的搜索原理(一)

dedecms


    


上图为dedecms中自带的搜索界面。搜索界面很简单,由一个text,一个select,一个button,构建为一个form表单,具体代码如下:

<form action="/plus/search.php" name="formsearch"><div class="form">
<h4>搜索</h4>
<input type="hidden" value="0" name="kwtype">
<input id="search-keyword" class="search-keyword" type="text" onblur="if(this.value==''){this.value='在这里搜索...';}" onfocus="if(this.value=='在这里搜索...'){this.value='';}" value="在这里搜索..." name="q">
<select id="search-option" class="search-option" name="searchtype">
<option selected="1" value="title">检索标题</option>
<option value="titlekeyword">智能模糊</option>
</select>
<button class="search-submit" type="submit">搜索</button>
</div>
</form>

进入search.php文件

开头代码

require_once(dirname(__FILE__)."/../include/common.inc.php");
require_once(DEDEINC."/arc.searchview.class.php");
$pagesize = (isset($pagesize) && is_numeric($pagesize)) ? $pagesize : 10;
$typeid = (isset($typeid) && is_numeric($typeid)) ? $typeid : 0;
$channeltype = (isset($channeltype) && is_numeric($channeltype)) ? $channeltype : 0;
$kwtype = (isset($kwtype) && is_numeric($kwtype)) ? $kwtype : 0;
$mid = (isset($mid) && is_numeric($mid)) ? $mid : 0;


这些参数的过滤由common.inc.php中处理并定义的,相关代码为

  CheckRequest($_REQUEST);
    CheckRequest($_COOKIE);


    foreach(Array('_GET','_POST','_COOKIE') as $_request)
    {
        foreach($$_request as $_k => $_v) 
        {
            if($_k == 'nvarname') ${$_k} = $_v;
            else ${$_k} = _RunMagicQuotes($_v);
        }
    }
}

具体怎么过滤的,暂且不表。


接下来的一些,为防止sql注入,而进行的简单的正则替换

if(!isset($orderby)) $orderby='';
else $orderby = preg_replace("#[^a-z]#i", '', $orderby);

if(!isset($searchtype)) $searchtype = 'titlekeyword';
else $searchtype = preg_replace("#[^a-z]#i", '', $searchtype);

if(!isset($keyword)){
    if(!isset($q)) $q = '';
    $keyword=$q;
}



$oldkeyword = $keyword = FilterSearch(stripslashes($keyword));

接下来是查找栏目信息,目前不是很了解它是做什么的,正好研究一下。代码为

//查找栏目信息
if(empty($typeid))
{


    $typenameCacheFile = DEDEDATA.'/cache/typename.inc';
    if(!file_exists($typenameCacheFile) || filemtime($typenameCacheFile) < time()-(3600*24) )
    {
        $fp = fopen(DEDEDATA.'/cache/typename.inc', 'w');
        fwrite($fp, "<"."?php\r\n");
        $dsql->SetQuery("Select id,typename,channeltype From `#@__arctype`");
        $dsql->Execute();
        while($row = $dsql->GetArray())
        {
            fwrite($fp, "\$typeArr[{$row['id']}] = '{$row['typename']}';\r\n");
        }
        fwrite($fp, '?'.'>');
        fclose($fp);
    }
    //引入栏目缓存并看关键字是否有相关栏目内容
    require_once($typenameCacheFile);
    if(isset($typeArr) && is_array($typeArr))
    {
        foreach($typeArr as $id=>$typename)
        {
            //$keywordn = str_replace($typename, ' ', $keyword);
            $keywordn = $keyword;
            if($keyword != $keywordn)
            {
                $keyword = HtmlReplace($keywordn);
                $typeid = intval($id);
                break;
            }
        }
    }
}

首先它把栏目缓存了,如果没有或者是过期的话,会重新生成。

然后foreach把栏目依次输出,但是下面我就不知道他有什么意义了,

$keywordn = $keyword;

 $keywordn = $keyword;
            if($keyword != $keywordn)

这样的写法简直是滑稽,导致整个查找栏目信息没有任何意义。


接着往下看,

$keyword = addslashes(cn_substr($keyword,30));
$typeid = intval($typeid);

if($cfg_notallowstr !='' && preg_match("#".$cfg_notallowstr."#i", $keyword))
{
    ShowMsg("你的搜索关键字中存在非法内容,被系统禁止!","-1");
    exit();
}

if(($keyword=='' || strlen($keyword)<2) && empty($typeid))
{
    ShowMsg('关键字不能小于2个字节!','-1');
    exit();
}

前两行对keyword进行php自带函数addslashes简单过滤,对typeid的int化,而后出现一个$cfg_notallowstr变量,经过断点追溯,找到其是存在/data/config.cache.inc.php中的,相关代码为

$cfg_notallowstr = '非典|艾滋病|阳痿';
$cfg_replacestr = '她妈|它妈|他妈|你妈|去死|贱人';
$cfg_feedbackcheck = 'N';

这个应该是可以从后台直接操作的,暂时不表。


继续往下看代码

//检查搜索间隔时间
$lockfile = DEDEDATA.'/time.lock.inc';
$lasttime = file_get_contents($lockfile);
if(!empty($lasttime) && ($lasttime + $cfg_search_time) > time())
{
    ShowMsg('管理员设定搜索时间间隔为'.$cfg_search_time.'秒,请稍后再试!','-1');
    exit();
}

引入了一个时间锁的配置文件,其文件里存一个时间戳工具,原理是,每查询一次,向里注入最新的时间戳,我也在文件的最后找到了相关代码

PutFile($lockfile, time());

不过我对这个机制不是很理解,它这样设置,是针对整个服务器进行设置的,也就是说,如果A和B能过两台电脑,两个ip段进行在误差$cfg_search_time内进行查询的话,理论上有一个人是查询不到的。这样是避免了恶意查询,但是把用户体验我认为是做到了最差。

如果单纯的防止用户恶意查询,用cookie或者session是可行的。如果单纯是为了减轻服务器的压力,可以在想别的办法,比如说sphinx全文索引,完善的缓存机制,以及其他的技术手段实现,而不能用这么简单暴力的方法。



继续往下看

//开始时间
if(empty($starttime)) $starttime = -1;
else
{
    $starttime = (is_numeric($starttime) ? $starttime : -1);
    if($starttime>0)
    {
       $dayst = GetMkTime("2008-1-2 0:0:0") - GetMkTime("2008-1-1 0:0:0");
       $starttime = time() - ($starttime * $dayst);
  }
}

我现在还不知道$starttime是怎么来的,我得到它的值一直都为空,无从追溯,现在姑且认为这希它的值定义为-1吧...

继续往下看

$t1 = ExecTime();

 此函数定义在/include/helpers/debug.help.php中,具体代码为

if ( ! function_exists('ExecTime'))
{
    function ExecTime()
    {
        $time = explode(" ", microtime());
        $usec = (double)$time[0];
        $sec = (double)$time[1];
        return $sec + $usec;
    }
}

具体用处是把micrtome()返回的 类似于这样的格式 0.83355200 1411874405 重组为 1411874405.8336 然后返回给$t1


继续往下看代码,最后三行

$sp = new SearchView($typeid,$keyword,$orderby,$channeltype,$searchtype,$starttime,$pagesize,$kwtype,$mid);
$keyword = $oldkeyword;
$sp->Display();


这段代码没什么好说的,只是开始调用类了,并初始化$keyword。


下面在开一文研究这类

2014-09-29 10:44:50

php
php

这是介绍的地方

本文相关标签

推荐应用

友情链接


皖ICP备14007051号-2 关于穆子龙