OSDN Git Service

MERGE: リビジョン1873〜1893。skinnable-masterのマージ
[nucleus-jp/nucleus-next.git] / nucleus / libs / SEARCH.php
1 <?php
2
3 /*
4  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5  * Copyright (C) 2003-2009 The Nucleus Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * (see nucleus/documentation/index.html#license for more info)
12  */
13 /**
14  * SEARCH(querystring) offers different functionality to create an
15  * SQL query to find certain items. (and comments)
16  *
17  * based on code by David Altherr:
18  * http://www.evolt.org/article/Boolean_Fulltext_Searching_with_PHP_and_MySQL/18/15665/
19  * http://davidaltherr.net/web/php_functions/boolean/funcs.mysql.boolean.txt
20  *
21  * @license http://nucleuscms.org/license.txt GNU General Public License
22  * @copyright Copyright (C) 2002-2009 The Nucleus Group
23  * @version $Id: SEARCH.php 1886 2012-06-17 08:27:27Z sakamocchi $
24  */
25
26
27
28 class Search
29 {
30         var $querystring;
31         var $marked;
32         var $inclusive;
33         var $blogs;
34
35
36         function SEARCH($text) {
37                 global $blogid;
38                 $text = preg_replace ("/[<,>,=,?,!,#,^,(,),[,\],:,;,\\\,%]/","",$text);
39                 $this->querystring      = $text;
40                 $this->marked           = $this->boolean_mark_atoms($text);
41                 $this->inclusive        = $this->boolean_inclusive_atoms($text);
42                 $this->blogs            = array();
43
44                 // get all public searchable blogs, no matter what, include the current blog allways.
45                 $res = DB::getResult('SELECT bnumber FROM '.sql_table('blog').' WHERE bincludesearch=1 ');
46                 foreach ( $res as $row )
47                         $this->blogs[] = intval($row['bnumber']);
48         }
49
50         function  boolean_sql_select($match){
51                 if (i18n::strlen($this->inclusive) > 0) {
52                    /* build sql for determining score for each record */
53                    $result=preg_split("# #",$this->inclusive);
54                    for($cth=0;$cth<count($result);$cth++){
55                            if(i18n::strlen($result[$cth])>=4){
56                                    $stringsum_long .=  " $result[$cth] ";
57                            }else{
58                                    $stringsum_a[] = ' '.$this->boolean_sql_select_short($result[$cth],$match).' ';
59                            }
60                    }
61
62                    if(i18n::strlen($stringsum_long)>0){
63                                 $stringsum_long = DB::quoteValue($stringsum_long);
64                                 $stringsum_a[] = " match ({$match}) against ({$stringsum_long}) ";
65                    }
66
67                    $stringsum .= implode("+",$stringsum_a);
68                    return $stringsum;
69                 }
70         }
71
72         function boolean_inclusive_atoms($string){
73                 $result = trim($string);
74                 $result = preg_replace("#([[:space:]]{2,})#", ' ', $result);
75
76                 # replaced eregi_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
77                 # just added delimiters to regex and the 'i' for case-insensitive matching
78
79                 /* convert normal boolean operators to shortened syntax */
80                 $result = preg_replace('# not #i', ' -', $result);
81                 $result = preg_replace('# and #i', ' ', $result);
82                 $result = preg_replace('# or #i', ',', $result);
83
84                 /* drop unnecessary spaces */
85                 $result = str_replace(' ,', ',', $result);
86                 $result = str_replace(', ', ',', $result);
87                 $result = str_replace('- ', '-', $result);
88                 $result = str_replace('+', '', $result);
89
90                 /* strip exlusive atoms */
91                 $result = preg_replace(
92                         "#\-\([A-Za-z0-9]{1,}[A-Za-z0-9\-\.\_\,]{0,}\)#",
93                         '',
94                         $result);
95
96                 $result = str_replace('(', ' ', $result);
97                 $result = str_replace(')', ' ', $result);
98                 $result = str_replace(',', ' ', $result);
99
100                 return $result;
101         }
102
103     function boolean_sql_where($match){
104
105         $result = $this->marked;
106
107         $this->boolean_sql_where_cb1($match); // set the static $match
108
109         $result = preg_replace_callback(
110
111             "/foo\[\(\'([^\)]{4,})\'\)\]bar/",
112
113             array($this,'boolean_sql_where_cb1'),
114
115             $result);
116
117         $this->boolean_sql_where_cb2($match); // set the static $match
118
119         $result = preg_replace_callback(
120
121             "/foo\[\(\'([^\)]{1,3})\'\)\]bar/",
122
123             array($this,'boolean_sql_where_cb2'),
124
125             $result);
126
127         return $result;
128
129     }
130
131     function boolean_sql_where_cb1($matches){
132
133         static $match;
134
135         if (!is_array($matches)) $match=$matches;
136
137         else return ' match ('.$match.') against ('.DB::quoteValue($matches[1]).') > 0 ';
138
139     }
140
141     function boolean_sql_where_cb2($matches){
142
143         static $match;
144
145         if (!is_array($matches)) $match=$matches;
146
147         else return ' ('.$this->boolean_sql_where_short($matches[1], $match).') ';
148
149     }   
150
151         function boolean_mark_atoms($string){
152                 $result = trim($string);
153                 $result = preg_replace("/([[:space:]]{2,})/",' ',$result);
154
155                 # replaced eregi_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
156                 # just added delimiters to regex and the 'i' for case-insensitive matching
157
158                 /* convert normal boolean operators to shortened syntax */
159                 $result = preg_replace('# not #i', ' -', $result);
160                 $result = preg_replace('# and #i', ' ', $result);
161                 $result = preg_replace('# or #i', ',', $result);
162
163                 /* strip excessive whitespace */
164                 $result = str_replace('( ', '(', $result);
165                 $result = str_replace(' )', ')', $result);
166                 $result = str_replace(', ', ',', $result);
167                 $result = str_replace(' ,', ',', $result);
168                 $result = str_replace('- ', '-', $result);
169                 $result = str_replace('+', '', $result);
170
171                 // remove double spaces (we might have introduced some new ones above)
172                 $result = trim($result);
173                 $result = preg_replace("#([[:space:]]{2,})#", ' ', $result);
174
175                 /* apply arbitrary function to all 'word' atoms */
176
177                 $result_a = preg_split('# #', $result);
178
179                 for($word = 0;$word<count($result_a);$word++)
180                 {
181                         $result_a[$word] = "foo[('" . $result_a[$word] . "')]bar";
182                 }
183
184                 $result = implode(' ', $result_a);
185
186                 /* dispatch ' ' to ' AND ' */
187                 $result = str_replace(' ', ' AND ', $result);
188
189                 /* dispatch ',' to ' OR ' */
190                 $result = str_replace(',', ' OR ', $result);
191
192                 /* dispatch '-' to ' NOT ' */
193                 $result = str_replace(' -', ' NOT ', $result);
194                 return $result;
195         }
196
197         function boolean_sql_where_short($string,$match){
198                 $match_a = preg_split('#,#',$match);
199                 for($ith=0;$ith<count($match_a);$ith++){
200                         $like_a[$ith] = ' $match_a[$ith] LIKE ' . DB::quoteValue("% {$string} %") . ' ';
201                 }
202                 $like = implode(" OR ",$like_a);
203
204                 return $like;
205         }
206         function boolean_sql_select_short($string,$match){
207                 $match_a = preg_split('#,#',$match);
208                 $score_unit_weight = .2;
209                 for($ith=0;$ith<count($match_a);$ith++){
210                         $score_a[$ith] =
211                                                    " $score_unit_weight*(
212                                                    LENGTH(" . DB::quoteValue($match_a[$ith]) . ") -
213                                                    LENGTH(REPLACE(LOWER(" . DB::quoteValue($match_a[$ith]) . "),LOWER(" . DB::quoteValue($string) . "),'')))
214                                                    /LENGTH(" . DB::quoteValue($string) . ") ";
215                 }
216                 $score = implode(" + ",$score_a);
217
218                 return $score;
219         }
220 }
221 ?>