<?php
/*
* 项目: iOrange(橘子)
* 作者: 离家出走(yzxh24)
* Email: yzxh24@gmail.com
* 主页: www.iorange.cc
*/
/* vim: set ts=4 sw=4: */
class SearchAction extends BbsAction
{
    public function run()
    {
        $this->getController()->isLogin();
        $search = $this->isAllowSearch();
        !$search && $this->NoPermission();
        
        $permissions = Members::single()->getPermissions($this->uid());
        $maxSearchResult = 500;
        $cacheLife = 3600;
        $searchCtrl = $permissions['searchctrl'] ? $permissions['searchctrl'] : 30;
        $time = CTIME;
        $ip = $_SERVER['REMOTE_ADDR'];
        
        $forums = Forums::single()->getForumsCache();
        $forumList = array();
        foreach ($forums as $forum)
        {
            if ($forum['type'] != 'category')
            {
                $forumList[$forum['fid']] = $forum['name'];
            }
        }
        
        if (isset($_GET['searchid']))
        {
            $searchId = S::gp('searchid','G',2);
            $sql = 'SELECT searchstring, keywords, threads, tids FROM '.SearchIndex::table().' WHERE id='.S::sqlEscape($searchId);
            $index = $this->db()->setQueryString($sql)->find(true);
            if (empty($index))
            {
                throw new iSystemException('错误的搜索请求');
            }
            $count = $this->db()->getValue('SELECT COUNT(*) FROM '.Threads::table().' WHERE id iN ('.$index['tids'].')');
            if (!$count)
            {
                throw new iSystemException('暂无记录');
            }
            $pageObj = new iPage();
            $pageObj->setPageSize(30);
            $pageObj->setTotalRecord($count);
            $sql = 'SELECT id,fid,subject,createdate,uid,username,topped,replies,hits,islock,isdigest,special,isupload,lastpost,type FROM '.Threads::table().' WHERE id IN ('.$index['tids'].') AND isdelete = 0'.S::sqlLimit($pageObj->getOffset(),$pageObj->getPageSize());
            $threads = $this->db()->setQueryString($sql)->find();
            
            $this->getController()->render('search_result', array(
                    'keyword' => $index['keywords'],
                    'pageObj' => $pageObj,
                    'threads' => $threads,
                )
            );
            exit(0);
        }
        
        if (isset($_POST['key']))
        {
            $type = S::gp('type','P',2);
            $fid = S::gp('fid','P',2);
            $keyWord = S::gp('key','P');
            $userName = S::gp('user','P');
            $sqlAdd = '';
            $searchType = $type == 2 ? 'fulltext' : 'title';
            
            if ($type == 2 && $search != 2)
            {
                throw new iSystemException('您当前用户组不能全文搜索');
            }
            if (empty($keyWord) && empty($userName))
            {
                throw new iSystemException('请输入关键字');
            }
            if (mb_strlen($keyWord) < 2 && empty($userName))
            {
                throw new iSystemException('关键字长度不能小于2个字');
            }
            
            $searchString = $searchType . '|' . addslashes($keyWord) . '|' . addslashes($userName). '|' . $fid;
            $searchIndex = array('id' => 0, 'createdate' => '0');
            $sql = "SELECT id, createdate,
        			('$searchCtrl'<>'0' AND ".(!$this->uid() ? "useip='$ip'" : "uid='{$this->uid()}'")." AND $time-createdate<$searchCtrl) AS flood,
        			(searchstring='$searchString' AND expiration>'$time') AS indexvalid
        			FROM ".SearchIndex::table()." 
        			WHERE ('$searchCtrl'<>'0' AND ".(!$this->uid() ? "useip='$ip'" : "uid='{$this->uid()}'")." AND $time-createdate<$searchCtrl) OR (searchstring='$searchString' AND expiration>'$time')
        			ORDER BY flood";
            $indexResult = $this->db()->setQueryString($sql)->find();
            if (!empty($indexResult))
            {
                foreach ($indexResult as $index)
                {
                    if($index['indexvalid'] && $index['createdate'] > $searchIndex['createdate'])
                    {
        				$searchIndex = array('id' => $index['id'], 'createdate' => $index['createdate']);
        				break;
        			}
        			elseif($index['flood'])
        			{
        				throw new iSystemException('对不起，您在 '.$searchCtrl.'秒内只能进行一次搜索，请返回。');
        			}
                }
            }
            
            if ($searchIndex['id'])
            {
                iforward(url('system',array('s'=>'bbs','a'=>'search','searchid'=>$searchIndex['id'])));
            }

            $sql = ' FROM '.Threads::table().' AS t '.('fulltext' == $searchType ? 'INNER JOIN '.ThreadsData::table().' as td ON t.id=td.tid ' : '');
            if (!empty($userName))
            {
                $uids = array();
                $userName = str_replace('*', '%', addcslashes($userName, '%_'));
                $msql = 'SELECT uid FROM '.Members::table()." WHERE username LIKE '" . str_replace('_', '\_', $userName) . "' LIMIT 50";
                $members = $this->db()->setQueryString($msql)->find();
                if (!empty($members))
                {
                    foreach ($members as $member)
                    {
                        $uids[] = $member['uid'];
                    }
                    $suid = implode(',', $uids);
                    $sqlAdd .= ' AND t.uid IN ('.implode(',', $uids).')';
                }
                else
                {
                    $sqlAdd .= " AND t.username LIKE '" . str_replace('_', '\_', $userName)."'";
                }
            }

            if (!empty($keyWord))
            {
                if (preg_match("(AND|\+|&|\s)", $keyWord) && ! preg_match("(OR|\|)", $keyWord))
                {
                    $andor = ' AND ';
                    $sqlTxtSrch = '1';
                    $keyWord = preg_replace("/( AND |&| )/is", "+", $keyWord);
                }
                else
                {
                    $andor = ' OR ';
                    $sqlTxtSrch = '0';
                    $keyWord = preg_replace("/( OR |\|)/is", "+", $keyWord);
                }
                $keyWord = str_replace('*', '%', addcslashes($keyWord, '%_'));
                foreach (explode('+', $keyWord) as $text)
                {
                    $text = trim($text);
                    if ($text)
                    {
                        $sqlTxtSrch .= $andor;
                        $sqlTxtSrch .= $searchType == 'fulltext' ? "(td.content LIKE '%" . str_replace('_', '\_', $text) . "%' OR t.subject LIKE '%$text%')" : "t.subject LIKE '%$text%'";
                    }
                }
                $sqlAdd .= " AND ($sqlTxtSrch)";
            }
            if ($fid)
            {
                $sqlAdd .= ' AND t.fid='.$fid;
            }
            
            $threads = $tids = 0;
            $sql = 'SELECT t.id '.$sql.' WHERE t.isdelete = 0 ' . $sqlAdd . ' LIMIT '.$maxSearchResult;
            $result = $this->db()->setQueryString($sql)->find();
            if (!empty($result))
            {
                $ids = array();
                foreach ($result as $thread)
                {
                    $ids[] = $thread['id'];
                    $threads++;
                }
                $tids = implode(',', $ids);
            }
            $expiration = $time + $cacheLife;
            $searchString = $searchType . '|' . addslashes($keyWord) . '|' . addslashes($userName) . '|' . $fid;
            $sql = 'INSERT INTO '.SearchIndex::table()." (keywords, searchstring, ip, uid, createdate, expiration, threads, tids)
					VALUES ('$keyWord', '$searchString', '{$_SERVER['REMOTE_ADDR']}', '{$this->uid()}', '$time', '$expiration', '$threads', '$tids')";
            $this->db()->query($sql);
            $searchId = $this->db()->getInsertId();
            iforward(url('system',array('s'=>'bbs','a'=>'search','searchid'=>$searchId)));
        }
        
        $fid = S::gp('fid','G',2);
        
        $this->getController()->render('search', array(
                'search' => $search,
                'forumList' => $forumList,
                'fid' => $fid,
            )
        );
    }
}