changed git call from https to git readonly
[atutor.git] / mods / wiki / plugins / lib / opensearch.php
1 <?php
2 #
3 #  OpenSearch backend for ErfurtWiki with MySQL database, but should also
4 #  work for PhpWiki 1.2 installs (but you need to glue it yourself then).
5 #
6
7
8 #-- plugin registration
9 $wikiapi["wiki.search"] = "ewiki_opensearch_api";
10
11
12 #-- the interface
13 function ewiki_opensearch_api($query, $params) {
14
15    #-- database connection
16    // should already be established
17    
18    #-- check request params
19    $params = (array)$params
20    + array(
21       "n_hit" => 1000,
22       "m_title" => 3.0,
23       "q_pos" => 2.0,
24       "q_not" => 0.0,
25       "limit" => 5000,
26    );
27    $n_hit = $params["n_hit"];
28    $q_pos = $params["q_pos"];
29    $q_not = $params["q_not"];
30    $calc = array();
31
32    #-- search target field mapped to internal SQL row names
33    $fieldnames = array(
34       "title" => "title",
35       "text" => "text",
36       "" => "content",
37       "author" => "author",
38       "links" => "links",
39       "meta" => "meta",
40       "filename" => "title",
41    );
42
43    
44    #-- sort request terms into MUST and NOT ------------------------ SQL ---
45    $sql = array(
46      "MUST" => array(),
47      "NOT" => array(),
48    );
49    foreach ($query as $i=>$qterm) {
50       list($pattern, $dep, $field, $flags) = $qterm;
51       $f_regex = strpos($flags, "REGEX") !== false;
52       $f_nocase = strpos($flags, "NOCASE") !== false;
53       $m_field = isset($params["m_$field"]) ? $params["m_$field"] : 0;
54       
55       if ($field = $fieldnames[$field]) {
56
57          $pattern = mysql_escape_string($pattern);
58
59          if ($f_regex) {
60             $s = "$field REGEXP '$pattern'";
61          }
62          elseif ($f_nocase) {
63             $pattern = strtolower($pattern);
64             $s = "LOCATE('$pattern', LCASE($field)) > 0";
65          }
66          else {
67             $s = "LOCATE('$pattern', $field) > 0";
68          }
69
70          #-- add
71          $sql[$dep][] = "($s)";
72       }
73
74       $calc[] = array($pattern, $dep, $field, $f_regex, $f_nocase, $m_field);
75
76    }
77    if ($q_not) {
78       $sql_MUST = implode(" OR ", $sql["MUST"]);
79       $sql_NOT = "";
80    }
81    else {
82       $sql_MUST = implode(" AND ", $sql["MUST"]);
83       $sql_NOT = implode(" OR ", $sql["NOT"]);
84       if ($sql_NOT) { $sql_NOT = " AND NOT ($sql_NOT)"; }
85    }
86
87    #-- last validity checks
88    if (!$sql_MUST) {
89       // no way to send an error with ED xmlrpclib ?
90       return("551: at least one MUST search term must be given");
91    }
92    
93
94    #-- get hit list
95    $sql_DB_F_TEXT = "((flags & 1) > 0) AND";
96    $sql_query_result = mysql_query($sql="
97       SELECT
98          pagename AS id, version AS version,
99          pagename AS title,
100          content AS text,
101          CONCAT(pagename, content) AS content,
102          meta,
103          author,
104          refs AS links,
105          lastmodified,
106          created,
107          flags
108       FROM
109          ewiki
110       WHERE
111          $sql_DB_F_TEXT
112          $sql_MUST
113          $sql_NOT
114       GROUP BY id ORDER BY version
115    ");
116
117    #-- start hit score calculation ---------------------------------- CALC ---
118    $result_list = array();
119    $ordered_list = array();
120    if ($sql_query_result) while ($row = mysql_fetch_array($sql_query_result)) {
121
122       $score = 0.0;   // final score
123       $m_fin = 1.0;   // to eventually decrease it later
124
125       #-- score each search term for hit
126       foreach ($calc as $qterm) {
127          list($pattern, $dep, $field, $f_regex, $f_nocase, $m_field) = $qterm;
128          
129          #-- minscore
130          $add = $n_hit;
131          if ($m_field) {
132             $add *= $m_field;
133          }
134          
135          #-- regex hit
136          if ($f_regex) {
137             $ok = preg_match($pattern, $row["field"]);
138             if ($dep=="MUST") {
139                $score += $add * ($ok ? 1.0 : $q_not);
140             }
141             elseif ($dep=="NOT") {
142                if ($ok) {
143                   $m_fin *= $q_not;
144                }
145             }
146          }
147          #-- strsearch hit
148          else {
149             $text = $f_nocase ? strtolower($row[$field]) : $row[$field];
150             $len = strlen($text) + 1;
151
152             #-- add points for each hit, weighted by match position
153             if ($dep=="MUST") {
154                $p = -1;
155                while (false !== ($p = strpos($text, $pattern, $p+1))) {
156                   $score += $add * ($q_pos - ($q_pos - 1) * ($p / $len));
157                }
158             }
159             #-- NOT search term
160             elseif (strpos($text, $pattern) !== false) {
161                $m_fin *= $q_not;
162             }
163          }
164          
165       }
166       
167       #-- add to list
168       if ($score *= $m_fin) {
169          $result_list[] = array(
170             "title" => $row["title"],
171             "url" => ewiki_script_url("", $row["title"]),
172             "excerpt" => substr(strtr($row["text"], "\r\n\t\f", "    "), 0, 300),
173             "score" => $score,
174             "lastmodified" => $row["lastmodified"],
175          );
176          $ordered_list[] = $score;
177       }
178    }
179    
180    #-- sort result?
181    arsort($ordered_list);
182    foreach ($ordered_list as $i=>$uu) {
183       $ordered_list[$i] = $result_list[$i];
184       unset($result_list[$i]);
185    }
186    $result_list = & $ordered_list;
187
188
189    #-- done
190    return($ordered_list);
191 }
192
193
194 ?>