OSDN Git Service

git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/nucleus-jp/trunk@1211 1ca29...
[nucleus-jp/nucleus-jp-ancient.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-2011 The Nucleus Group
23  * @version $Id$
24  * @version $NucleusJP: SEARCH.php,v 1.7 2006/07/20 08:01:52 kimitake Exp $
25  */
26
27 class SEARCH {
28
29         var $querystring;
30         var $marked;
31         var $inclusive;
32         var $blogs;
33
34         function SEARCH($text) {
35                 global $blogid;
36 //              $text = preg_replace ("/[<,>,=,?,!,#,^,(,),[,\],:,;,\\\,%]/","",$text);
37                 /* * * for jp * * * * * * * * * * */
38                 $this->encoding = strtolower(preg_replace('|[^a-z0-9-_]|i', '', _CHARSET));
39                 if ($this->encoding != 'utf-8') {
40                         $text = mb_convert_encoding($text, "UTF-8", $this->encoding);
41                 }
42                 $text = str_replace ("\xE3\x80\x80",' ',$text);
43                 $text = preg_replace ("/[<>=?!#^()[\]:;\\%]/","",$text);
44
45                 $this->ascii       = '[\x00-\x7F]';
46                 $this->two               = '[\xC0-\xDF][\x80-\xBF]';
47                 $this->three       = '[\xE0-\xEF][\x80-\xBF][\x80-\xBF]';
48
49                 $this->jpmarked = $this->boolean_mark_atoms_jp($text);
50                 /* * * * * * * * * * * * * * * * */
51
52                 $this->querystring = $text;
53 //              $this->marked     = $this->boolean_mark_atoms($text);
54                 $this->inclusive   = $this->boolean_inclusive_atoms($text);
55                 $this->blogs       = array();
56
57                 // get all public searchable blogs, no matter what, include the current blog allways.
58                 $res = sql_query('SELECT bnumber FROM ' . sql_table('blog') . ' WHERE bincludesearch=1 ');
59                 while ($obj = sql_fetch_object($res)) {
60                         $this->blogs[] = intval($obj->bnumber);
61                 }
62         }
63
64         function  boolean_sql_select($match) {
65                 if (!isset($stringsum)) {
66                         $stringsum = '';
67                 }
68                 if (strlen($this->inclusive) > 0) {
69                         /* build sql for determining score for each record */
70                         $result=explode(" ",$this->inclusive);
71                         if (!isset($stringsum_long)) {
72                                 $stringsum_long = '';
73                         }
74                         for ($cth = 0; $cth < count($result); $cth++) {
75                                 if (strlen($result[$cth])>=4) {
76                                         $stringsum_long .=  " $result[$cth] ";
77                                 } else {
78                                         $stringsum_a[] = ' ' . $this->boolean_sql_select_short($result[$cth], $match) . ' ';
79                                 }
80                         }
81
82                         if (strlen($stringsum_long) > 0) {
83                                 $stringsum_long = sql_real_escape_string($stringsum_long);
84                                 $stringsum_a[]  = " match ($match) against ('$stringsum_long') ";
85                         }
86
87                         $stringsum .= implode("+", $stringsum_a);
88
89                         return $stringsum;
90                 }
91         }
92
93         
94
95         function boolean_inclusive_atoms($string) {
96                 $result = trim($string);
97                 $result = preg_replace("#([[:space:]]{2,})#", ' ', $result);
98                 
99                 # replaced eregi_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
100                 # just added delimiters to regex and the 'i' for case-insensitive matching
101                 
102                 /* convert normal boolean operators to shortened syntax */
103                 $result = preg_replace('# not #i', ' -', $result);
104                 $result = preg_replace('# and #i', ' ', $result);
105                 $result = preg_replace('# or #i', ',', $result);
106                 
107                 /* drop unnecessary spaces */
108                 $result = str_replace(' ,', ',', $result);
109                 $result = str_replace(', ', ',', $result);
110                 $result = str_replace('- ', '-', $result);
111                 $result = str_replace('+', '', $result);
112                 
113                 /* strip exlusive atoms */
114                 $result = preg_replace(
115                         "#\-\(([A-Za-z0-9]|$this->two|$this->three){1,}([A-Za-z0-9\-\.\_\,]|$this->two|$this->three){0,}\)#",
116                         '',
117                         $result);
118                 
119                 $result = str_replace('(', ' ', $result);
120                 $result = str_replace(')', ' ', $result);
121                 $result = str_replace(',', ' ', $result);
122                 if ($this->encoding != 'utf-8') {
123                         $result = mb_convert_encoding($result, $this->encoding, "UTF-8");
124                 }
125                 return $result;
126         }
127
128         function boolean_sql_where($match) {
129 /*
130                 $result = $this->marked;
131                 $result = preg_replace(
132                         "/foo\[\(\'([^\)]{4,})\'\)\]bar/e",
133                         " 'match ('.\$match.') against (\''.\$this->copyvalue(\"$1\").'\') > 0 ' ",
134                         $result);
135                 $result = preg_replace(
136                         "/foo\[\(\'([^\)]{1,3})\'\)\]bar/e",
137                         " '('.\$this->boolean_sql_where_short(\"$1\",\"$match\").')' ",
138                         $result);
139 */
140                 $result = $this->jpmarked; /* for jp */
141                 $result = $this->boolean_sql_where_jp_short($result, $match);/* for jp */
142                 if ($this->encoding != 'utf-8') {
143                         $result = mb_convert_encoding($result, $this->encoding, "UTF-8");
144                 }
145                 return $result;
146         }
147
148         // there must be a simple way to simply copy a value with backslashes in it through
149         // the preg_replace, but I cannot currently find it (karma 2003-12-30)
150         function copyvalue($foo) {
151                 return $foo;
152         }
153 /*
154         function boolean_mark_atoms($string){
155                 $result=trim($string);
156                 $result=preg_replace("/([[:space:]]{2,})/",' ',$result);
157
158                 # replaced eregi_replace() below with preg_replace(). ereg* functions are deprecated in PHP 5.3.0
159                 # just added delimiters to regex and the 'i' for case-insensitive matching
160
161                 $result = preg_replace('# not #i', ' -', $result);
162                 $result = preg_replace('# and #i', ' ', $result);
163                 $result = preg_replace('# or #i', ',', $result);
164
165                 // strip excessive whitespace
166                 $result=str_replace('( ','(',$result);
167                 $result=str_replace(' )',')',$result);
168                 $result=str_replace(', ',',',$result);
169                 $result=str_replace(' ,',',',$result);
170                 $result=str_replace('- ','-',$result);
171                 $result=str_replace('+','',$result);
172
173                 // remove double spaces (we might have introduced some new ones above)
174                 $result=trim($result);
175                 $result=preg_replace("#([[:space:]]{2,})#",' ',$result);
176
177                 // apply arbitrary function to all 'word' atoms
178
179                 $result_a = explode(' ',$result);
180                 for($word=0;$word<count($result_a);$word++)
181                 {
182                         $result_a[$word] = "foo[('".$result_a[$word]."')]bar";
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 = explode(',',$match);
199                 for($ith=0;$ith<count($match_a);$ith++){
200                         $like_a[$ith] = " $match_a[$ith] LIKE '% $string %' ";
201                 }
202                 $like = implode(" OR ",$like_a);
203
204                 return $like;
205         }
206 */
207
208         function boolean_sql_select_short($string, $match) {
209                 $match_a                   = explode(',', $match);
210                 $score_unit_weight = .2;
211                 for ($ith = 0; $ith< count($match_a); $ith++){
212                         $score_a[$ith] =
213                                                         " $score_unit_weight*(
214                                                         LENGTH(" . sql_real_escape_string($match_a[$ith]) . ") -
215                                                         LENGTH(REPLACE(LOWER(" . sql_real_escape_string($match_a[$ith]) . "),LOWER('" . sql_real_escape_string($string) . "'),'')))
216                                                         /LENGTH('" . sql_real_escape_string($string) . "') ";
217                 }
218                 $score = implode(" + ", $score_a);
219
220                 return $score;
221         }
222
223 /***********************************************
224         Make "WHERE" (jp)
225 ***********************************************/
226
227         function boolean_mark_atoms_jp($string) {
228                 $result = trim($string);
229                 $result = preg_replace("/([[:space:]]{2,})/", ' ', $result);
230                 
231                 /* convert normal boolean operators to shortened syntax */
232                 $result = preg_replace('# not #i', ' -', $result);
233                 $result = preg_replace('# and #i', ' ',  $result);
234                 $result = preg_replace('# or #i',  ',',  $result);
235                 
236                 /* strip excessive whitespace */
237                 $result = str_replace(', ', ',',  $result);
238                 $result = str_replace(' ,', ',',  $result);
239                 $result = str_replace('- ', '-',  $result);
240                 $result = str_replace('+',  '',   $result);
241                 $result = str_replace(',',  ' ,', $result);
242
243                 return $result;
244         }
245
246         function boolean_sql_where_jp_short($string, $match) {
247                 $match_a = explode(',', $match);
248                 $key_a   = explode(' ', $string);
249
250                 for ($ith=0; $ith<count($match_a); $ith++) {
251 //                      $temp_a[$ith] = "(i.$match_a[$ith] LIKE '%" . sql_real_escape_string($key_a[0]) . "%') ";
252                         $binKey    = preg_match('/[a-zA-Z]/', $key_a[0]) ? '' : 'BINARY';
253                         $temp_a[$ith] = "(i.$match_a[$ith] LIKE " . $binKey . " '%" . sql_real_escape_string($key_a[0]) . "%') ";
254                 }
255                 $like = '('.implode(' or ',$temp_a).')';
256
257                 for ($kn = 1; $kn < count($key_a); $kn++) {
258                         $binKey    = preg_match('/[a-zA-Z]/', $key_a[$kn]) ? '' : 'BINARY';
259                         if (substr($key_a[$kn], 0, 1) == ",") {
260                                 for($ith = 0; $ith < count($match_a); $ith++) {
261 //                                      $temp_a[$ith] = " (i.$match_a[$ith] LIKE '%" . sql_real_escape_string(substr($key_a[$kn],1)) . "%') ";
262                                         $temp_a[$ith] = " (i.$match_a[$ith] LIKE " . $binKey . " '%" . sql_real_escape_string(substr($key_a[$kn], 1)) . "%') ";
263                                 }
264                                 $like .=' OR ('. implode(' or ', $temp_a).')';
265                         }elseif(substr($key_a[$kn],0,1) != '-'){
266                                 for($ith=0;$ith<count($match_a);$ith++){
267 //                                      $temp_a[$ith] = " (i.$match_a[$ith] LIKE '%" . sql_real_escape_string($key_a[$kn]) . "%') ";
268                                         $temp_a[$ith] = " (i.$match_a[$ith] LIKE " . $binKey . " '%" . sql_real_escape_string($key_a[$kn]) . "%') ";
269                                 }
270                                 $like .=' AND ('. implode(' or ', $temp_a).')';
271                         }else{
272                                 for($ith=0;$ith<count($match_a);$ith++){
273 //                                      $temp_a[$ith] = " NOT(i.$match_a[$ith] LIKE '%" . sql_real_escape_string(substr($key_a[$kn],1)) . "%') ";
274                                         $temp_a[$ith] = " NOT(i.$match_a[$ith] LIKE " . $binKey . " '%" . sql_real_escape_string(substr($key_a[$kn], 1)) . "%') ";
275                                 }
276                                 $like .=' AND ('. implode(' and ', $temp_a).')';
277                         }
278                 }
279                 
280                 $like = '('.$like.')';
281                 return $like;
282         }
283 }
284 ?>