]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/msql.php
Added real back-link searches.
[SourceForge/phpwiki.git] / lib / msql.php
1 <!-- $Id: msql.php,v 1.6.2.1 2001-08-18 00:34:27 dairiki Exp $ -->
2 <?php
3
4    /*
5       Database functions:
6       MakePageHash($dbhash)
7       MakeDBHash($pagename, $pagehash)
8       OpenDataBase($dbname)
9       CloseDataBase($dbi)
10       RetrievePage($dbi, $pagename, $pagestore)
11       InsertPage($dbi, $pagename, $pagehash)
12       SaveCopyToArchive($dbi, $pagename, $pagehash) 
13       IsWikiPage($dbi, $pagename)
14       InitTitleSearch($dbi, $search)
15       TitleSearchNextMatch($dbi, &$pos)
16       InitFullSearch($dbi, $search)
17       FullSearchNextMatch($dbi, &$pos)
18       MakeBackLinkSearchRegexp($pagename)
19       InitBackLinkSearch($dbi, $pagename) 
20       BackLinkSearchNextMatch($dbi, &$pos) 
21       GetAllWikiPageNames($dbi)
22    */
23
24
25    // open a database and return the handle
26    // ignores MAX_DBM_ATTEMPTS
27
28    function OpenDataBase($dbinfo) {
29       global $msql_db;
30
31       if (! ($dbc = msql_connect())) {
32          $msg = gettext ("Cannot establish connection to database, giving up.");
33          $msg .= "<BR>";
34          $msg .= sprintf(gettext ("Error message: %s"), msql_error());
35          ExitWiki($msg);
36       }
37       if (!msql_select_db($msql_db, $dbc)) {
38          $msg = gettext ("Cannot open database %s, giving up.");
39          $msg .= "<BR>";
40          $msg .= sprintf(gettext ("Error message: %s"), msql_error());
41          ExitWiki($msg);
42       }
43
44       $dbi['dbc'] = $dbc;
45       $dbi['table'] = $dbinfo['table'];           // page metadata
46       $dbi['page_table'] = $dbinfo['page_table']; // page content
47       return $dbi;
48    }
49
50
51    function CloseDataBase($dbi) {
52       // I found msql_pconnect unstable so we go the slow route.
53       return msql_close($dbi['dbc']);
54    }
55
56
57    // This should receive the full text of the page in one string
58    // It will break the page text into an array of strings
59    // of length MSQL_MAX_LINE_LENGTH which should match the length
60    // of the columns wikipages.LINE, archivepages.LINE in schema.minisql
61
62    function msqlDecomposeString($string) {
63       $ret_arr = array();
64
65       // initialize the array to satisfy E_NOTICE
66       for ($i = 0; $i < MSQL_MAX_LINE_LENGTH; $i++) {
67          $ret_arr[$i] = "";
68       }
69       $el = 0;
70    
71       // zero, one, infinity
72       // account for the small case
73       if (strlen($string) < MSQL_MAX_LINE_LENGTH) { 
74          $ret_arr[$el] = $string;
75          return $ret_arr;
76       }
77    
78       $words = array();
79       $line = $string2 = "";
80    
81       // split on single spaces
82       $words = preg_split("/ /", $string);
83       $num_words = count($words);
84    
85       reset($words);
86       $ret_arr[0] = $words[0];
87       $line = " $words[1]";
88    
89       // for all words, build up lines < MSQL_MAX_LINE_LENGTH in $ret_arr
90       for ($x = 2; $x < $num_words; $x++) {
91          $length = strlen($line) + strlen($words[$x]) 
92                    + strlen($ret_arr[$el]) + 1;
93
94          if ($length < MSQL_MAX_LINE_LENGTH) {
95             $line .= " " .  $words[$x];
96          } else {
97             // put this line in the return array, reset, continue
98             $ret_arr[$el++] .= $line;
99             $line = " $words[$x]"; // reset     
100          }
101       }
102       $ret_arr[$el] = $line;
103       return $ret_arr;
104    }
105
106
107    // Take form data and prepare it for the db
108    function MakeDBHash($pagename, $pagehash)
109    {
110       $pagehash["pagename"] = addslashes($pagename);
111       if (!isset($pagehash["flags"]))
112          $pagehash["flags"] = 0;
113       if (!isset($pagehash["content"])) {
114          $pagehash["content"] = array();
115       } else {
116          $pagehash["content"] = implode("\n", $pagehash["content"]);
117          $pagehash["content"] = msqlDecomposeString($pagehash["content"]);
118       }
119       $pagehash["author"] = addslashes($pagehash["author"]);
120       if (empty($pagehash["refs"])) {
121          $pagehash["refs"] = "";
122       } else {
123          $pagehash["refs"] = serialize($pagehash["refs"]);
124       }
125
126       return $pagehash;
127    }
128
129
130    // Take db data and prepare it for display
131    function MakePageHash($dbhash)
132    {
133       // unserialize/explode content
134       $dbhash['refs'] = unserialize($dbhash['refs']);
135       return $dbhash;
136    }
137
138
139    // Return hash of page + attributes or default
140    function RetrievePage($dbi, $pagename, $pagestore) {
141       $pagename = addslashes($pagename);
142       $table = $pagestore['table'];
143       $pagetable = $pagestore['page_table'];
144
145       $query = "select * from $table where pagename='$pagename'";
146       // echo "<p>query: $query<p>";
147       $res = msql_query($query, $dbi['dbc']);
148       if (msql_num_rows($res)) {
149          $dbhash = msql_fetch_array($res);
150
151          $query = "select lineno,line from $pagetable " .
152                   "where pagename='$pagename' " .
153                   "order by lineno";
154
155          $msql_content = "";
156          if ($res = msql_query($query, $dbi['dbc'])) {
157             $dbhash["content"] = array();
158             while ($row = msql_fetch_array($res)) {
159                 $msql_content .= $row["line"];
160             }
161             $dbhash["content"] = explode("\n", $msql_content);
162          }
163
164          return MakePageHash($dbhash);
165       }
166       return -1;
167    }
168
169
170    // Either insert or replace a key/value (a page)
171    function InsertPage($dbi, $pagename, $pagehash) {
172
173       $pagehash = MakeDBHash($pagename, $pagehash);
174       // $pagehash["content"] is now an array of strings 
175       // of MSQL_MAX_LINE_LENGTH
176
177       // record the time of modification
178       $pagehash["lastmodified"] = time();
179
180       if (IsWikiPage($dbi, $pagename)) {
181
182          $PAIRS = "author='$pagehash[author]'," .
183                   "created=$pagehash[created]," .
184                   "flags=$pagehash[flags]," .
185                   "lastmodified=$pagehash[lastmodified]," .
186                   "pagename='$pagehash[pagename]'," .
187                   "refs='$pagehash[refs]'," .
188                   "version=$pagehash[version]";
189
190          $query  = "UPDATE $dbi[table] SET $PAIRS WHERE pagename='$pagename'";
191
192       } else {
193          // do an insert
194          // build up the column names and values for the query
195
196          $COLUMNS = "author, created, flags, lastmodified, " .
197                     "pagename, refs, version";
198
199          $VALUES =  "'$pagehash[author]', " .
200                     "$pagehash[created], $pagehash[flags], " .
201                     "$pagehash[lastmodified], '$pagehash[pagename]', " .
202                     "'$pagehash[refs]', $pagehash[version]";
203
204
205          $query = "INSERT INTO $dbi[table] ($COLUMNS) VALUES($VALUES)";
206       }
207
208       // echo "<p>Query: $query<p>\n";
209
210       // first, insert the metadata
211       $retval = msql_query($query, $dbi['dbc']);
212       if ($retval == false) {
213          printf(gettext ("Insert/update failed: %s"), msql_error());
214          print "<br>\n";
215       }
216
217
218       // second, insert the page data
219       // remove old data from page_table
220       $query = "delete from $dbi[page_table] where pagename='$pagename'";
221       // echo "Delete query: $query<br>\n";
222       $retval = msql_query($query, $dbi['dbc']);
223       if ($retval == false) {
224          printf(gettext ("Delete on %s failed: %s"), $dbi[page_table],
225             msql_error());
226          print "<br>\n";
227       }
228
229       // insert the new lines
230       reset($pagehash["content"]);
231
232       for ($x = 0; $x < count($pagehash["content"]); $x++) {
233          $line = addslashes($pagehash["content"][$x]);
234          $query = "INSERT INTO $dbi[page_table] " .
235                   "(pagename, lineno, line) " .
236                   "VALUES('$pagename', $x, '$line')";
237          // echo "Page line insert query: $query<br>\n";
238          $retval = msql_query($query, $dbi['dbc']);
239          if ($retval == false) { 
240             printf(gettext ("Insert into %s failed: %s"), $dbi[page_table],
241                msql_error());
242             print "<br>\n";
243          }
244       }
245    }
246
247
248    // for archiving pages to a separate table
249    function SaveCopyToArchive($dbi, $pagename, $pagehash) {
250       global $ArchivePageStore;
251
252       $pagehash = MakeDBHash($pagename, $pagehash);
253       // $pagehash["content"] is now an array of strings 
254       // of MSQL_MAX_LINE_LENGTH
255
256       if (IsInArchive($dbi, $pagename)) {
257
258          $PAIRS = "author='$pagehash[author]'," .
259                   "created=$pagehash[created]," .
260                   "flags=$pagehash[flags]," .
261                   "lastmodified=$pagehash[lastmodified]," .
262                   "pagename='$pagehash[pagename]'," .
263                   "refs='$pagehash[refs]'," .
264                   "version=$pagehash[version]";
265
266          $query  = "UPDATE $ArchivePageStore[table] SET $PAIRS WHERE pagename='$pagename'";
267
268       } else {
269          // do an insert
270          // build up the column names and values for the query
271
272          $COLUMNS = "author, created, flags, lastmodified, " .
273                     "pagename, refs, version";
274
275          $VALUES =  "'$pagehash[author]', " .
276                     "$pagehash[created], $pagehash[flags], " .
277                     "$pagehash[lastmodified], '$pagehash[pagename]', " .
278                     "'$pagehash[refs]', $pagehash[version]";
279
280
281          $query = "INSERT INTO archive ($COLUMNS) VALUES($VALUES)";
282       }
283
284       // echo "<p>Query: $query<p>\n";
285
286       // first, insert the metadata
287       $retval = msql_query($query, $dbi['dbc']);
288       if ($retval == false) {
289          printf(gettext ("Insert/update failed: %s"), msql_error());
290          print "<br>\n";
291       }
292
293       // second, insert the page data
294       // remove old data from page_table
295       $query = "delete from $ArchivePageStore[page_table] where pagename='$pagename'";
296       // echo "Delete query: $query<br>\n";
297       $retval = msql_query($query, $dbi['dbc']);
298       if ($retval == false) {
299          printf(gettext ("Delete on %s failed: %s"),
300           $ArchivePageStore[page_table], msql_error());
301          print "<br>\n";
302       }
303
304       // insert the new lines
305       reset($pagehash["content"]);
306
307       for ($x = 0; $x < count($pagehash["content"]); $x++) {
308          $line = addslashes($pagehash["content"][$x]);
309          $query = "INSERT INTO $ArchivePageStore[page_table] " .
310                   "(pagename, lineno, line) " .
311                   "VALUES('$pagename', $x, '$line')";
312          // echo "Page line insert query: $query<br>\n";
313          $retval = msql_query($query, $dbi['dbc']);
314          if ($retval == false) {
315             printf(gettext ("Insert into %s failed: %s"),
316               $ArchivePageStore[page_table], msql_error());
317             print "<br>\n";
318          }
319       }
320
321
322    }
323
324
325    function IsWikiPage($dbi, $pagename) {
326       $pagename = addslashes($pagename);
327       $query = "select pagename from wiki where pagename='$pagename'";
328       // echo "Query: $query<br>\n";
329       if ($res = msql_query($query, $dbi['dbc'])) {
330          return(msql_affected_rows($res));
331       }
332    }
333
334
335    function IsInArchive($dbi, $pagename) {
336       $pagename = addslashes($pagename);
337       $query = "select pagename from archive where pagename='$pagename'";
338       // echo "Query: $query<br>\n";
339       if ($res = msql_query($query, $dbi['dbc'])) {
340          return(msql_affected_rows($res));
341       }
342    }
343
344
345
346    // setup for title-search
347    function InitTitleSearch($dbi, $search) {
348       $search = addslashes($search);
349       $query = "select pagename from $dbi[table] " .
350                "where pagename clike '%$search%' order by pagename";
351       $res = msql_query($query, $dbi['dbc']);
352
353       return $res;
354    }
355
356
357    // iterating through database
358    function TitleSearchNextMatch($dbi, $res) {
359       if($o = msql_fetch_object($res)) {
360          return $o->pagename;
361       }
362       else {
363          return 0;
364       }
365    }
366
367
368    // setup for full-text search
369    function InitFullSearch($dbi, $search) {
370       // select unique page names from wikipages, and then 
371       // retrieve all pages that come back.
372       $search = addslashes($search);
373       $query = "select distinct pagename from $dbi[page_table] " .
374                "where line clike '%$search%' " .
375                "order by pagename";
376       $res = msql_query($query, $dbi['dbc']);
377
378       return $res;
379    }
380
381    // iterating through database
382    function FullSearchNextMatch($dbi, $res) {
383       global $WikiPageStore;
384       if ($row = msql_fetch_row($res)) {
385         return RetrievePage($dbi, $row[0], $WikiPageStore);
386       } else {
387         return 0;
388       }
389    }
390
391    ////////////////////////
392    // new database features
393
394    // Compute PCRE suitable for searching for links to the given page.
395    function MakeBackLinkSearchRegexp($pagename) {
396       global $WikiNameRegexp;
397
398       // Note that in (at least some) PHP 3.x's, preg_quote only takes
399       // (at most) one argument.  Also it doesn't quote '/'s.
400       // It does quote '='s, so we'll use that for the delimeter.
401       $quoted_pagename = preg_quote($pagename);
402       if (preg_match("/^$WikiNameRegexp\$/", $pagename)) {
403          # FIXME: This may need modification for non-standard (non-english) $WikiNameRegexp.
404          return "=(?<![A-Za-z0-9!])$quoted_pagename(?![A-Za-z0-9])=";
405       }
406       else {
407          // Note from author: Sorry. :-/
408          return ( '='
409                   . '(?<!\[)\[(?!\[)' // Single, isolated '['
410                   . '([^]|]*\|)?'     // Optional stuff followed by '|'
411                   . '\s*'             // Optional space
412                   . $quoted_pagename  // Pagename
413                   . '\s*\]=' );       // Optional space, followed by ']'
414          // FIXME: the above regexp is still not quite right.
415          // Consider the text: " [ [ test page ]".  This is a link to a page
416          // named '[ test page'.  The above regexp will recognize this
417          // as a link either to '[ test page' (good) or to 'test page' (wrong).
418       } 
419    }
420
421    // setup for back-link search
422    function InitBackLinkSearch($dbi, $pagename) {
423       global $WikiLinksStore;
424      
425       $topage = addslashes($pagename);
426
427       // FIXME: this is buggy.  If a [multiword link] is split accross
428       // multiple lines int the page_table, we wont find it.
429       // (Probably the best fix is to implement the link table, and use it.)
430       $res['regexp'] = MakeBackLinkSearchRegexp($pagename);
431       $res['res'] = msql_query( "SELECT pagename, line FROM $dbi[page_table]"
432                                 . " WHERE line LIKE '%$topage%'"
433                                 . " ORDER BY pagename",
434                                 $dbi["dbc"]);
435       $res['lastpage'] = '';
436       
437       return $res;
438    }
439
440
441    // iterating through database
442    function BackLinkSearchNextMatch($dbi, $res) {
443       while (true) {
444          if ( ! ($o = msql_fetch_object($res['res']))) {
445             return 0;
446          }
447          if ( $res['lastpage'] == $o->pagename )
448             continue;
449          if ( ! preg_match($res['regexp'], $a->line) )
450             continue;
451          $res['lastpage'] = $o->pagename;
452          return $o->pagename;
453       }
454    }
455
456    function IncreaseHitCount($dbi, $pagename) {
457
458       $query = "select hits from hitcount where pagename='$pagename'";
459       $res = msql_query($query, $dbi['dbc']);
460       if (msql_num_rows($res)) {
461          $hits = msql_result($res, 0, 'hits');
462          $hits++;
463          $query = "update hitcount set hits=$hits where pagename='$pagename'";
464          $res = msql_query($query, $dbi['dbc']);
465
466       } else {
467          $query = "insert into hitcount (pagename, hits) " .
468                   "values ('$pagename', 1)";
469          $res = msql_query($query, $dbi['dbc']);
470       }
471
472       return $res;
473    }
474
475    function GetHitCount($dbi, $pagename) {
476
477       $query = "select hits from hitcount where pagename='$pagename'";
478       $res = msql_query($query, $dbi['dbc']);
479       if (msql_num_rows($res)) {
480          $hits = msql_result($res, 0, 'hits');
481       } else {
482          $hits = "0";
483       }
484
485       return $hits;
486    }
487
488
489
490    function InitMostPopular($dbi, $limit) {
491
492       $query = "select * from hitcount " .
493                "order by hits desc, pagename limit $limit";
494
495       $res = msql_query($query, $dbi['dbc']);
496       
497       return $res;
498    }
499
500    function MostPopularNextMatch($dbi, $res) {
501
502       if ($hits = msql_fetch_array($res)) {
503          return $hits;
504       } else {
505          return 0;
506       }
507    }
508
509    function GetAllWikiPageNames($dbi_) {
510       $res = msql_query("select pagename from wiki", $dbi['dbc']);
511       $rows = msql_num_rows($res);
512       for ($i = 0; $i < $rows; $i++) {
513          $pages[$i] = msql_result($res, $i, 'pagename');
514       }
515       return $pages;
516    }
517
518    ////////////////////////////////////////
519    // functionality for the wikilinks table
520
521    // takes a page name, returns array of scored incoming and outgoing links
522
523 /* Not implemented yet. The code below was copied from mysql.php...
524
525    function GetWikiPageLinks($dbi, $pagename) {
526       $links = array();
527       $pagename = addslashes($pagename);
528       $res = msql_query("select wikilinks.topage, wikiscore.score from wikilinks, wikiscore where wikilinks.topage=wikiscore.pagename and wikilinks.frompage='$pagename' order by score desc, topage", $dbi['dbc']);
529
530       $rows = msql_num_rows($res);
531       for ($i = 0; $i < $rows; $i++) {
532          $out = msql_fetch_array($res);
533          $links['out'][] = array($out['topage'], $out['score']);
534       }
535
536       $res = msql_query("select wikilinks.frompage, wikiscore.score from wikilinks, wikiscore where wikilinks.frompage=wikiscore.pagename and wikilinks.topage='$pagename' order by score desc, frompage", $dbi['dbc']);
537       $rows = msql_num_rows($res);
538       for ($i = 0; $i < $rows; $i++) {
539          $out = msql_fetch_array($res);
540          $links['in'][] = array($out['frompage'], $out['score']);
541       }
542
543       $res = msql_query("select distinct hitcount.pagename, hitcount.hits from wikilinks, hitcount where (wikilinks.frompage=hitcounts.pagename and wikilinks.topage='$pagename') or (wikilinks.topage=pagename and wikilinks.frompage='$pagename') order by hitcount.hits desc, wikilinks.pagename", $dbi['dbc']);
544       $rows = msql_num_rows($res);
545       for ($i = 0; $i < $rows; $i++) {
546          $out = msql_fetch_array($res);
547          $links['popular'][] = array($out['pagename'], $out['hits']);
548       }
549
550       return $links;
551    }
552
553
554    // takes page name, list of links it contains
555    // the $linklist is an array where the keys are the page names
556    function SetWikiPageLinks($dbi, $pagename, $linklist) {
557       $frompage = addslashes($pagename);
558
559       // first delete the old list of links
560       msql_query("delete from wikilinks where frompage='$frompage'",
561                 $dbi["dbc"]);
562
563       // the page may not have links, return if not
564       if (! count($linklist))
565          return;
566       // now insert the new list of links
567       while (list($topage, $count) = each($linklist)) {
568          $topage = addslashes($topage);
569          if($topage != $frompage) {
570             msql_query("insert into wikilinks (frompage, topage) " .
571                      "values ('$frompage', '$topage')", $dbi["dbc"]);
572          }
573       }
574
575       msql_query("delete from wikiscore", $dbi["dbc"]);
576       msql_query("insert into wikiscore select w1.topage, count(*) from wikilinks as w1, wikilinks as w2 where w2.topage=w1.frompage group by w1.topage", $dbi["dbc"]);
577    }
578 */
579
580 ?>