[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare - Wiki DB-Layer * 4 * http://www.egroupware.org * 5 * Written by Ralf Becker <RalfBecker@outdoor-training.de> * 6 * originaly based on WikkiTikkiTavi tavi.sf.net and www.axisgroupware.org: * 7 * former files lib/pagestore.php + lib/page.php * 8 * -------------------------------------------- * 9 * This program is free software; you can redistribute it and/or modify it * 10 * under the terms of the GNU General Public License as published by the * 11 * Free Software Foundation; either version 2 of the License, or (at your * 12 * option) any later version. * 13 \**************************************************************************/ 14 15 /* $Id: class.sowiki.inc.php 21443 2006-04-25 05:51:38Z ralfbecker $ */ 16 17 define ('WIKI_ACL_ALL',0); // everyone incl. anonymous 18 define ('WIKI_ACL_USER',1); // everyone BUT anonymous 19 define ('WIKI_ACL_ADMIN',2); // only admins (access to the admin app !) 20 21 /** 22 * Class representing a wiki-page, usualy gets instanciated via sowiki::page() 23 * @class soWikiPage 24 * @author RalfBecker-AT-outdoor-training.de 25 * @license GPL 26 */ 27 class soWikiPage 28 { 29 var $name = ''; // Name of page. 30 var $title = ''; // Title of page. 31 var $text = ''; // Page's text in wiki markup form. 32 var $time = ''; // Page's modification time. 33 var $hostname = ''; // Hostname of last editor. 34 var $username = ''; // Username of last editor. 35 var $comment = ''; // Description of last edit. 36 var $version = -1; // Version number of page. 37 var $mutable = 1; // Whether page may be edited (depricated !) 38 var $readable = WIKI_ACL_ALL; // who can read the page 39 var $writable = WIKI_ACL_ALL; // who can write the page 40 var $exists = 0; // Whether page already exists. 41 var $db; /* @var $db db */ // Database object. 42 var $PgTbl; 43 var $colNames = array( // column-name - class-var-name pairs 44 'wiki_id' => 'wiki_id', 45 'wiki_name' => 'name', 46 'wiki_lang' => 'lang', 47 'wiki_version' => 'version', 48 'wiki_time' => 'time', 49 'wiki_supercede' => 'supercede', 50 'wiki_readable' => 'readable', 51 'wiki_writable' => 'writable', 52 'wiki_hostname' => 'hostname', 53 'wiki_username' => 'username', 54 'wiki_comment' => 'comment', 55 'wiki_title' => 'title', 56 'wiki_body' => 'text', 57 ); 58 var $debug = 0; // overwritten by constructor, set it in the sowiki class, not here 59 60 /** 61 * Constructor of the soWikiPage class, gets instanciated via the soWiki::page function 62 * 63 * @param object $db db-object 64 * @param string $PgTbl name of pages-table 65 * @param string $name name of the wiki-page 66 * @param string/boolean $lang requested language or False 67 * @param int $wiki_id which wiki to use 68 * @param int $debug debug-value 69 */ 70 function soWikiPage($db,$PgTbl,$name = '',$lang=False,$wiki_id=0,$debug=0) 71 { 72 $this->db = $db; // to have an independent result-pointer 73 $this->db->set_app('wiki'); 74 $this->PgTbl = $PgTbl; 75 76 $this->name = $name; 77 $this->lang = $lang; 78 $this->wiki_id = (int) $wiki_id; 79 $this->memberships = $GLOBALS['egw']->accounts->membership(); 80 foreach($this->memberships as $n => $data) 81 { 82 $this->memberships[$n] = (int) $data['account_id']; 83 } 84 $this->user_lang = $GLOBALS['egw_info']['user']['preferences']['common']['lang']; 85 $this->use_langs = array($this->user_lang,''); 86 // english as fallback, should be configurable or a pref 87 if ($this->user_lang != 'en') $this->use_langs[] = 'en'; 88 $this->lang_priority_sql = "CASE WHEN wiki_body IS NULL THEN ".(count($this->use_langs)+1).' ELSE (CASE wiki_lang'; 89 90 foreach($this->use_langs as $order => $lang) 91 { 92 $this->lang_priority_sql .= ' WHEN '.$this->db->quote($lang)." THEN $order"; 93 } 94 $this->lang_priority_sql .= ' ELSE '.count($this->use_langs).' END) END AS lang_priority'; 95 96 // $GLOBALS['config'] is set by lib/init 97 if (!is_array($GLOBALS['config'])) 98 { 99 $c =& CreateObject('phpgwapi.config','wiki'); 100 $c->read_repository(); 101 $GLOBALS['config'] = $c->config_data; 102 unset($c); 103 } 104 $this->config = &$GLOBALS['config']; 105 } 106 107 /** 108 * filter to and into query to get only readable / writeable page of current user 109 * 110 * @param boolean $readable generate SQL for readable or writable filter, default True == readable 111 * @param boolean $add_wiki_id add code to filter only the actual wiki 112 * @return string SQL to AND into the query 113 */ 114 function acl_filter($readable = True,$add_wiki_id=True) 115 { 116 static $filters = array(); 117 118 $filter_id = "$readable-$add_wiki_id"; 119 if (isset($filters[$filter_id])) 120 { 121 return $filters[$filter_id]; 122 } 123 $user = $GLOBALS['egw_info']['user']['account_id']; 124 125 $filters[] = WIKI_ACL_ALL; 126 127 if ($GLOBALS['egw_info']['user']['account_lid'] != $GLOBALS['config']['AnonymousUser']) 128 { 129 $filters[] = WIKI_ACL_USER; 130 } 131 if (@$GLOBALS['egw_info']['user']['apps']['admin']) 132 { 133 $filters[] = WIKI_ACL_ADMIN; 134 } 135 $filters = array_merge($filters,$this->memberships); 136 137 $sql = '('.($add_wiki_id ? " wiki_id=$this->wiki_id AND " : ''). 138 ($readable ? 'wiki_readable' : 'wiki_writable').' IN ('.implode(',',$filters).'))'; 139 140 if ($this->debug) echo "<p>sowiki::acl_filter($readable,$add_wiki_id) = '$sql'</p>\n"; 141 142 return $filters[$filter_id] = $sql; 143 } 144 145 /** 146 * check if page is readable or writeable by the current user 147 * 148 * If we have an anonymous session and the anonymous session-type is NOT editable, 149 * all pages are readonly (even if their own setting is editable by all) !!! 150 * 151 * * @paramboolean $readable check if page is readable or writable, default False == writeable 152 * @return boolean true if check was successful, false otherwise 153 */ 154 function acl_check($readable = False) 155 { 156 if (!$readable && $this->config['Anonymous_Session_Type'] != 'editable' && 157 $GLOBALS['egw_info']['user']['account_lid'] == $this->config['anonymous_username']) 158 { 159 return False; // Global config overrides page-specific setting 160 } 161 switch ($acl = $readable ? $this->readable : $this->writable) 162 { 163 case WIKI_ACL_ALL: 164 return True; 165 166 case WIKI_ACL_USER: 167 return $GLOBALS['egw_info']['user']['account_lid'] != $this->config['anonymous_username']; 168 169 case WIKI_ACL_ADMIN: 170 return isset($GLOBALS['egw_info']['user']['apps']['admin']); 171 172 default: 173 return in_array($acl,$this->memberships); 174 } 175 return False; 176 } 177 178 /** 179 * Returns the class-vars belonging direct to the wiki-page as an array 180 * 181 * @return array 182 */ 183 function as_array() 184 { 185 $arr = array(); 186 foreach($this->colNames as $name) 187 { 188 $arr[$name] = $this->$name; 189 } 190 return $arr; 191 } 192 193 /** 194 * Check if the page, which name, lang was set in the constructor, exists. 195 * 196 * @return boolean true if page exists in database, false otherwise 197 */ 198 function exists() 199 { 200 $this->db->select($this->PgTbl,'wiki_lang',array( 201 'wiki_name' => $this->name, 202 'wiki_lang' => $this->use_langs, 203 $this->acl_filter(), 204 ),__LINE__,__FILE__); 205 206 return $this->db->next_record() ? ($this->db->f(0) ? $this->db->f(0) : 'default') : False; 207 } 208 209 /** 210 * Read in a page contents, name and lang was set in the constructor 211 * 212 * @return array/boolean contents of the page or False. 213 */ 214 function read() 215 { 216 $where = array( 217 'wiki_name' => $this->name, 218 'wiki_lang' => !empty($this->lang) ? $this->lang : $this->use_langs, 219 $this->acl_filter(), 220 ); 221 if($this->version != -1) 222 { 223 $where['wiki_version'] = $this->version; 224 } 225 else 226 { 227 $where[] = 'wiki_supercede=wiki_time'; // gives the up-to-date version only 228 } 229 $this->db->select($this->PgTbl,"*,$this->lang_priority_sql",$where,__LINE__,__FILE__,false,'ORDER BY lang_priority'); 230 231 if (!$this->db->next_record()) 232 { 233 return False; 234 } 235 foreach($this->colNames as $dbname => $name) 236 { 237 $this->$name = $this->db->f($dbname); 238 } 239 $this->exists = 1; 240 $this->mutable = $this->acl_check(); 241 242 return $this->text; 243 } 244 245 /** 246 * Write the a page's contents to the db and sets the supercede-time of the prev. version 247 * 248 * The caller is responsible for performing locking. 249 */ 250 function write() 251 { 252 $this->time = $this->supercede = time(); 253 foreach($this->colNames as $dbname => $name) 254 { 255 $arr[$dbname] = $this->$name; 256 } 257 if (is_null($arr['wiki_comment'])) $arr['wiki_comment'] = ''; // can not be null 258 259 if (empty($this->text)) unset($arr['wiki_body']); // deleted / empty pages are written as SQL NULL 260 261 $this->db->insert($this->PgTbl,$arr,false,__LINE__,__FILE__); 262 263 if($this->version > 1) // set supercede-time of prev. version 264 { 265 $this->db->update($this->PgTbl,array( 266 'wiki_supercede' => $this->supercede 267 ),array( 268 'wiki_id' => $this->wiki_id, 269 'wiki_name' => $this->name, 270 'wiki_lang' => $this->lang, 271 'wiki_version' => $this->version-1 272 ),__LINE__,__FILE__); 273 } 274 } 275 276 /** 277 * Renames a page to a new name and/or lang 278 * 279 * The caller is responsible for performing locking. 280 * @param string/boolean $new_name to rename to or false if only a new language, default false 281 * @param string/boolean $new_lang to rename to or false if only a new name, default false 282 * @return int affected rows, 1=success, 0=not found 283 */ 284 function rename($new_name=False,$new_lang=False) 285 { 286 if ($new_name === False && $new_lang === False || !$this->acl_check()) 287 { 288 if ($this->debug) echo "soWikiPage::rename('$new_name','$new_lang') returning False this=<pre>".print_r($this->as_array(),True)."</pre>"; 289 return False; // nothing to do or no permission 290 } 291 $new = array( 292 'wiki_id' => $this->wiki_id, 293 'wiki_name' => $new_name === False ? $this->name : $new_name, 294 'wiki_lang' => $new_lang === False ? $this->lang : $new_lang, 295 ); 296 // delete (evtl.) existing target 297 $this->db->delete($this->PgTbl,$new,__LINE__,__FILE__); 298 299 $this->db->update($this->PgTbl,$new,array( 300 'wiki_id' => $this->wiki_id, 301 'wiki_name' => $this->name, 302 'wiki_lang' => $this->lang, 303 ),__LINE__,__FILE__); 304 305 if ($this->debug) echo "<p>soWikiPage::rename('$new_name','$new_lang') old='$this->name:$this->lang', sql='$sql', sql2='$sql2'</p>"; 306 307 if ($new_name !== False) $this->name = $new_name; 308 if ($new_lang !== False) $this->lang = $new_lang; 309 310 return $this->db->affected_rows(); 311 } 312 313 /** 314 * Returns colNames array, which translates column-names to internal names 315 * 316 * @return array with column-names as keys 317 */ 318 function column2names() 319 { 320 return $this->colNames; 321 } 322 } 323 324 /** 325 * Wiki's storage-object was former called pageStore in WikiTikiTavi 326 * @class sowiki 327 * @author RalfBecker-AT-outdoor-training.de 328 * @license GPL 329 */ 330 class sowiki // DB-Layer 331 { 332 var $db; /* @var $db db */ 333 var $LkTbl = 'egw_wiki_links'; 334 var $PgTbl = 'egw_wiki_pages'; 335 var $RtTbl = 'egw_wiki_rate'; 336 var $IwTbl = 'egw_wiki_interwiki'; 337 var $SwTbl = 'egw_wiki_sisterwiki'; 338 var $RemTbl= 'egw_wiki_remote_pages'; 339 var $ExpireLen,$Admin; 340 var $RatePeriod,$RateView,$RateSearch,$RateEdit; 341 var $wiki_id = 0; 342 var $colNames=false; // array converting column-names to internal names, set on the first call to sowiki::page 343 var $debug = 0; 344 345 /** 346 * Constructor of the PageStrore class sowiki 347 * 348 * @param int $wikid_id which wiki to use, default 0 349 */ 350 function sowiki($wiki_id=0) 351 { 352 $this->wiki_id = (int) $wiki_id; 353 $this->user_lang = $GLOBALS['egw_info']['user']['preferences']['common']['lang']; 354 355 $this->db = clone($GLOBALS['egw']->db); 356 $this->db->set_app('wiki'); 357 358 global $ExpireLen,$Admin; // this should come from the app-config later 359 global $RatePeriod, $RateView, $RateSearch, $RateEdit; 360 $this->ExpireLen = $ExpireLen; 361 $this->Admin = $Admin; 362 $this->RatePeriod = $RatePeriod; 363 $this->RateView = $RateView; 364 $this->RateSearch = $RateSearch; 365 $this->RateEdit = $RateEdit; 366 } 367 368 /** 369 * Create a page object / instanciate the soWikiPage class. 370 * @param string $name name of the page 371 * @param string/boolean $lang language or false for the users default language-order 372 * @return object soWikiPage class of the page 373 */ 374 function &page($name = '',$lang=False) 375 { 376 if ($this->debug) echo "<p>sowiki::page(".print_r($name,True).",'$lang')</p>"; 377 378 if (is_array($name)) 379 { 380 $lang = $lang ? $lang : @$name['lang']; 381 $name = @$name['name'] ? $name['name'] : @$name['title']; 382 } 383 $page =& new soWikiPage($this->db,$this->PgTbl,$name,$lang,$this->wiki_id,$this->debug); 384 385 if (!$this->colNames) $this->colNames = $page->column2names(); 386 387 return $page; 388 } 389 390 391 /** 392 * Returns the SQL to retrive the length of the body-column 393 * 394 * MaxDB cant calculate the length of the content of a LONG column, we set it to 1, 395 * we could retrive the complete column and use strlen on it, I dont do it as the length is only for sorting 396 * via a macro and that macro retrives all pages(!) - never used that macro ;-) 397 * 398 * @param string $table table-name of join alias incl. '.', or '' (default) 399 * @return string the SQL 400 */ 401 function length_sql($table) 402 { 403 if ($this->db->Type == 'maxdb' || $this->db->Type == 'sapdb') 404 { 405 return '1'; 406 } 407 return 'LENGTH('.$table.'wiki_body)'; 408 } 409 410 /** 411 * Find $text in the database, searches title and body. 412 * 413 * @param string $text pattern to search 414 * @param string/boolean $search_in comma-separated string with columns to search (name,title,body) or false to search all three for "%text%" (!) 415 * @return array of wiki-pages (array with column-name / value pairs) 416 */ 417 function find($text,$search_in=False) 418 { 419 $sql="SELECT t1.wiki_name,t1.wiki_lang,t1.wiki_version,MAX(t2.wiki_version) as wiki_max,t1.wiki_title,t1.wiki_body". 420 " FROM $this->PgTbl AS t1,$this->PgTbl AS t2". 421 " WHERE t1.wiki_name=t2.wiki_name AND t1.wiki_lang=t2.wiki_lang AND t1.wiki_id=$this->wiki_id AND t2.wiki_id=$this->wiki_id". 422 " GROUP BY t1.wiki_name,t1.wiki_lang,t1.wiki_version,t1.wiki_title,t1.wiki_body". 423 " HAVING t1.wiki_version=MAX(t2.wiki_version) AND ("; 424 425 // fix for case-insensitiv search on pgsql for lowercase searchwords 426 $op_text = $this->db->type == 'pgsql' && !preg_match('/[A-Z]/') ? 'ILIKE' : 'LIKE'; 427 $op_text .= ' '.$this->db->quote($search_in ? $text : "%$text%"); 428 429 $search_in = $search_in ? explode(',',$search_in) : array('wiki_name','wiki_title','wiki_body'); 430 431 if ($this->db->Type == 'sapdb' || $this->db->Type == 'maxdb') 432 { 433 $search_in = array_intersect($search_in,array('wiki_name','wiki_title')); 434 } 435 foreach($search_in as $n => $name) 436 { 437 $sql .= ($n ? ' OR ' : '') . "t1.$name $op_text"; 438 } 439 $sql .= ')'; 440 441 $this->db->query($sql,__LINE__,__FILE__); 442 443 return $this->_return_pages("find('$text','".implode(',',$search_in)."'"); 444 } 445 446 /** 447 * Retrieve a page's edit history. 448 * 449 * @param string/array $page name of the page or array with values for keys 'name' and 'lang' 450 * @param string/boolean $lang language to use or false if given via array in $name, default false 451 * @return an array of the different versions 452 */ 453 function history($page,$lang=False) 454 { 455 $name = $this->db->db_addslashes(is_array($page) ? $page['name'] : $page); 456 $lang = $this->db->db_addslashes(is_array($page) && !$lang ? $page['lang'] : $lang); 457 458 $this->db->select($this->PgTbl,'wiki_time,wiki_hostname,wiki_version,wiki_username,wiki_comment',array( 459 'wiki_name' => is_array($page) ? $page['name'] : $page, 460 'wiki_lang' => is_array($page) && !$lang ? $page['lang'] : $lang, 461 'wiki_id' => $this->wiki_id, 462 ),__LINE__,__FILE__,False,'ORDER BY wiki_version DESC'); 463 464 return $this->_return_pages('history('.print_r($page,True).",'$lang')"); 465 } 466 467 /** 468 * Look up an interwiki prefix 469 * 470 * @param string $name name-prefix of an interwiki 471 * @return string/boolean the url of False 472 */ 473 function interwiki($name) 474 { 475 $this->db->select($this->IwTbl,'interwiki_url',array( 476 'wiki_id' => $this->wiki_id, 477 'interwiki_prefix' => $name, 478 ),__LINE__,__FILE__); 479 480 return $this->db->next_record() ? $this->db->f('url') : False; 481 } 482 483 /** 484 * Clear all the links cached for a particular page. 485 * 486 * @param string/array $page page-name or array with values for wiki_id, name and lang keys 487 */ 488 function clear_link($page) 489 { 490 if ($this->debug) echo "<p>sowiki::clear_link(".print_r($page,true)."</p>\n"; 491 492 $this->db->delete($this->LkTbl,array( 493 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 494 'wiki_name' => is_array($page) ? $page['name'] : $page, 495 'wiki_lang' => $page['lang'], 496 ),__LINE__,__FILE__); 497 } 498 499 /** 500 * Clear all the interwiki definitions for a particular page. 501 * 502 * @param string/array $page page-name or array with values for wiki_id, name and lang keys 503 */ 504 function clear_interwiki($page) 505 { 506 if ($this->debug) echo "<p>sowiki::clear_interwiki(".print_r($page,true)."</p>\n"; 507 508 $this->db->delete($this->IwTbl,array( 509 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 510 'wiki_name' => is_array($page) ? $page['name'] : $page, 511 'wiki_lang' => $page['lang'], 512 ),__LINE__,__FILE__); 513 } 514 515 /** 516 * Clear all the sisterwiki definitions for a particular page. 517 * 518 * @param string/array $page page-name or array with values for wiki_id, name and lang keys 519 */ 520 function clear_sisterwiki($page) 521 { 522 if ($this->debug) echo "<p>sowiki::clear_sisterwiki(".print_r($page,true)."</p>\n"; 523 524 $this->db->delete($this->SwTbl,array( 525 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 526 'wiki_name' => is_array($page) ? $page['name'] : $page, 527 'wiki_lang' => $page['lang'], 528 ),__LINE__,__FILE__); 529 } 530 531 /** 532 * Add a link for a given page to the link table. 533 * 534 * @param string/array $page page-name or array with values for wiki_id, name and lang keys 535 * @param string $link the link to add 536 */ 537 function new_link($page, $link) 538 { 539 static $links = array(); 540 541 $where = array( 542 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 543 'wiki_name' => trim(is_array($page) ? $page['name'] : $page), 544 'wiki_lang' => $page['lang'], 545 'wiki_link' => trim($link), 546 ); 547 // $links need to be 2-dimensional as rename, can cause new_link to be called for different pages 548 $page_uid = strtolower($where['wiki_id'].':'.$where['page'].':'.$where['lang']); 549 $link = strtolower(trim($link)); 550 551 $data = array('wiki_count' => ++$links[$page_uid][$link]); 552 553 if ($this->debug) echo "<p>sowiki::new_link('$where[wiki_id]:$where[wiki_name]:$where[wiki_lang]','$link') = $data[wiki_count]</p>"; 554 555 if ($where['wiki_count'] == 1) 556 { 557 $this->db->insert($this->LkTbl,array_merge($data,$where),False,__LINE__,__FILE__); 558 } 559 else 560 { 561 $this->db->update($this->LkTbl,$data,$where,__LINE__,__FILE__); 562 } 563 } 564 565 /** 566 * Retrives all links on all pages and all languages 567 * 568 * @param string $link if none-empty, only these links are retrived 569 * @return array 2-dim. array with linking pages and languages, eg. $arr[$page][$lang] = $link 570 */ 571 function get_links($link='') 572 { 573 $where = array('wiki_id' => $this->wiki_id); 574 if ($link) 575 { 576 $where['wiki_link'] = $link; 577 } 578 $this->db->select($this->LkTbl,'wiki_name,wiki_lang,wiki_link',$where,__LINE__,__FILE__,false, 579 'ORDER BY wiki_name,wiki_lang'); 580 581 $result = array(); 582 while ($row = $this->db->row(True)) 583 { 584 $result[$row['wiki_name']][$row['wiki_lang']][] = $row['wiki_link']; 585 } 586 return $result; 587 } 588 589 /** 590 * Add an interwiki definition for a particular page. 591 * 592 * @param string/array $page page-name or array with values for name, lang and evtl. wiki_id (this->wiki_id is used if not) 593 * @param string $prefix Prefix of the new interwiki 594 * @param string $url URL of the new interwiki 595 */ 596 function new_interwiki($page, $prefix, $url) 597 { 598 $this->db->insert($this->IwTbl,array( 599 'wiki_name' => is_array($page) ? $page['name'] : $page, 600 'wiki_lang' => $page['lang'], 601 'interwiki_url' => str_replace('&','&',$url), 602 ),array( 603 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 604 'interwiki_prefix' => $prefix, 605 ),__LINE__,__FILE__); 606 } 607 608 /** 609 * Add an sisterwiki definition for a particular page. 610 * 611 * @param string/array $page page-name or array with values for name, lang and evtl. wiki_id (this->wiki_id is used if not) 612 * @param string $prefix Prefix of the new interwiki 613 * @param string $url URL of the new interwiki 614 */ 615 function new_sisterwiki($page, $prefix, $url) 616 { 617 $this->db->insert($this->SwTbl,array( 618 'wiki_name' => is_array($page) ? $page['name'] : $page, 619 'wiki_lang' => $page['lang'], 620 'interwiki_url' => str_replace('&','&',$url), 621 ),array( 622 'wiki_id' => is_array($page) && isset($page['wiki_id']) ? $page['wiki_id'] : $this->wiki_id, 623 'interwiki_prefix' => $prefix, 624 ),__LINE__,__FILE__); 625 } 626 627 /** 628 * Find all twins of a page at sisterwiki sites. 629 * 630 * @param string/array $page page-name or array with values for name 631 * @return array list of array(site,page) 632 */ 633 function twinpages($page) 634 { 635 $this->db->query("SELECT wiki_remote_site, wiki_remote_page FROM $this->RemTbl WHERE wiki_remote_page=". 636 $this->db->quote(is_array($page) ? $page['name'] : $page),__LINE__,__FILE__); 637 638 $list = array(); 639 while($this->db->next_record()) 640 { 641 $list[] = array( 642 'site' => $this->db->f('wiki_remote_site'), 643 'page' => $this->db->f('wiki_remote_page'), 644 ); 645 } 646 return $list; 647 } 648 649 /* 650 * Lock all wiki database tables. 651 */ 652 function lock() 653 { 654 $this->db->lock(array($this->PgTbl,$this->IwTbl,$this->SwTbl,$this->LkTbl),'write'); 655 } 656 657 /* 658 * Unlock all database tables. 659 */ 660 function unlock() 661 { 662 $this->db->unlock(); 663 } 664 665 /* 666 * Retrieve a list of all of the pages in the wiki. 667 * 668 * @return array of all pages 669 */ 670 function allpages() 671 { 672 $qid = $this->db->query("SELECT t1.wiki_time,t1.wiki_name,t1.wiki_lang,t1.wiki_hostname,t1.wiki_username,t1.wiki_title,".$this->length_sql('t1.'). 673 " AS wiki_length,t1.wiki_comment,t1.wiki_version,MAX(t2.wiki_version)" . 674 " FROM $this->PgTbl AS t1, $this->PgTbl AS t2" . 675 " WHERE t1.wiki_name = t2.wiki_name AND t1.wiki_lang=t2.wiki_lang AND t1.wiki_id=t2.wiki_id AND t1.wiki_id=".(int)$this->wiki_id. 676 " GROUP BY t1.wiki_name,t1.wiki_lang,t1.wiki_version,t1.wiki_time,t1.wiki_hostname,t1.wiki_username,t1.wiki_body,t1.wiki_comment,t1.wiki_title" . 677 " HAVING t1.wiki_version = MAX(t2.wiki_version)",__LINE__,__FILE__); 678 679 return $this->_return_pages('allpages()'); 680 } 681 682 /** 683 * Create array of page-arrays from the returned rows of a query 684 * 685 * @internal 686 * @param string $func calling function incl. parameters for debug-message 687 */ 688 function _return_pages($func) 689 { 690 if (!$this->colNames) 691 { 692 $page =& new soWikiPage($this->db,$this->PgTbl); 693 $this->colNames = $page->column2names(); 694 unset($page); 695 } 696 $list = array(); 697 while($this->db->next_record()) 698 { 699 $page = array(); 700 foreach($this->db->Record as $col => $val) 701 { 702 $name = isset($this->colNames[$col]) ? $this->colNames[$col] : ($name == 'wiki_length' ? 'length' : $col); 703 $page[$name] = $val; 704 } 705 $list[] = $page; 706 } 707 if ($this->debug) echo "<p>sowiki::$func<pre>".print_r($list,true)."</pre>\n"; 708 709 return $list; 710 } 711 712 /* 713 * Retrieve a list of the new pages in the wiki. 714 * 715 * @return array of pages 716 */ 717 function newpages() 718 { 719 $this->db->select($this->PgTbl,'wiki_time,wiki_name,wiki_lang,wiki_hostname,wiki_username,'.$this->length_sql().' AS wiki_length,wiki_comment,wiki_title', 720 array( 721 'wiki_id' => $this->wiki_id, 722 'wiki_version=1', 723 ),__LINE__,__FILE__); 724 725 return $this->_return_pages('newpages()'); 726 } 727 728 /* 729 * Retrieve a list of all empty (deleted) pages in the wiki. 730 * 731 * @return array of pages 732 */ 733 function emptypages() 734 { 735 $this->db->query("SELECT t1.wiki_time,t1.wiki_name,t1.wiki_lang,t1.wiki_hostname,t1.wiki_username,0,t1.wiki_comment,t1.wiki_version,MAX(t2.wiki_version),t1.wiki_title " . 736 " FROM $this->PgTbl AS t1,$this->PgTbl AS t2" . 737 " WHERE t1.wiki_name=t2.wiki_name AND t1.wiki_lang=t2.wiki_lang AND t1.wiki_id=t2.wiki_id AND t1.wiki_id=".(int)$this->wiki_id. 738 " GROUP BY t1.wiki_name,t1.wiki_lang,t1.wiki_version,t1.wiki_time,t1.wiki_hostname,t1.wiki_username,t1.wiki_comment". 739 " HAVING t1.wiki_version = MAX(t2.wiki_version) AND t1.wiki_body IS NULL",__LINE__,__FILE__); 740 741 return $this->_return_pages('emptypages()'); 742 } 743 744 /* 745 * Retrieve a list of information about a particular set of pages 746 * 747 * @param array $names array of page-names 748 * @return array of pages 749 */ 750 function givenpages($names) 751 { 752 $list = array(); 753 foreach($names as $page) 754 { 755 $this->db->select($this->PgTbl,'wiki_time,wiki_name,wiki_hostname,wiki_username,'.$this->length_sql().' AS wiki_length,wiki_comment,wiki_title',array( 756 'wiki_name' => $page, 757 'wiki_id' => $this->wiki_id, 758 ),__LINE__,__FILE__,False,'ORDER BY wiki_version DESC'); 759 760 $list = array_merge($list,$this->_return_pages('givenpages('.@print_r($names,true).')')); 761 } 762 return $list; 763 } 764 765 /** 766 * Expire old versions of pages. 767 */ 768 function maintain() 769 { 770 $this->db->delete($this->PgTbl,"(wiki_time!=wiki_supercede OR wiki_body IS NULL) AND ". 771 "wiki_supercede<".(time()-86400*$this->ExpireLen),__LINE__,__FILE__); 772 773 if($this->RatePeriod) 774 { 775 $this->db->delete($this->RtTbl,"wiki_rate_ip NOT LIKE '%.*' AND " . 776 intval(time()/86400)." > wiki_rate_time/86400",__LINE__,__FILE__); 777 } 778 } 779 780 /** 781 * Perform a lookup on an IP addresses edit-rate. 782 * 783 * @param string $type 'view',' search' or 'edit' 784 * @param string $remote_addr eg. $_SERVER['REMOTE_ADDR'] 785 */ 786 function rateCheck($type,$remote_addr) 787 { 788 if(!$this->RatePeriod) 789 { 790 return; 791 } 792 793 $this->db->lock($this->RtTbl,'WRITE'); 794 795 // Make sure this IP address hasn't been excluded. 796 797 $fields = explode(".", $remote_addr); 798 $this->db->select($this->RtTbl,'*',"wiki_rate_ip='$fields[0].*'". 799 " OR wiki_rate_ip='$fields[0].$fields[1].*'". 800 " OR wiki_rate_ip='$fields[0].$fields[1].$fields[2].*'",__LINE__,__FILE__); 801 802 if ($this->db->next_record()) 803 { 804 global $ErrorDeniedAccess; 805 die($ErrorDeniedAccess); 806 } 807 808 // Now check how many more actions we can perform. 809 810 $this->db->select($this->RtTbl,'wiki_rate_time,wiki_rate_viewLimit,wiki_rate_searchLimit,wiki_rate_editLimit',array( 811 'wiki_rate_ip' => $remote_addr 812 ),__LINE__,__FILE__); 813 814 if(!$this->db->next_record()) 815 { 816 $result = array(-1, $this->RateView, $this->RateSearch, $this->RateEdit); 817 } 818 else 819 { 820 $result = $this->db->Record; 821 822 $result[0] = time()-$result[0]; 823 if ($result[0] < 0) 824 { 825 $result[0] = $this->RatePeriod; 826 } 827 $result[1] = min($result[1] + $result[0] * $this->RateView / $this->RatePeriod,$this->RateView); 828 $result[2] = min($result[2] + $result[0] * $this->RateSearch / $this->RatePeriod,$this->RateSearch); 829 $result[3] = min($result[3] + $result[0] * $this->RateEdit / $this->RatePeriod,$this->RateEdit); 830 } 831 832 switch($type) 833 { 834 case 'view': $result[1]--; break; 835 case 'search': $result[2]--; break; 836 case 'edit': $result[3]--; break; 837 } 838 if($result[1] < 0 || $result[2] < 0 || $result[3] < 0) 839 { 840 global $ErrorRateExceeded; 841 die($ErrorRateExceeded); 842 } 843 844 // Record this action. 845 846 $this->db->insert($this->RtTbl,array( 847 'wiki_rate_viewLimit' => $result[1], 848 'wiki_rate_searchLimit' => $result[2], 849 'wiki_rate_editLimit' => $result[3], 850 'wiki_rate_time' => time(), 851 ),array( 852 'wiki_rate_ip' => $remote_addr 853 ),__LINE__,__FILE__); 854 855 $this->db->unlock(); 856 } 857 858 /** 859 * Return a list of blocked address ranges. 860 * 861 * @return array of blocked address-ranges 862 */ 863 function rateBlockList() 864 { 865 $list = array(); 866 867 if(!$this->RatePeriod) 868 { 869 return $list; 870 } 871 $this->db->select($this->RtTbl,'wiki_rate_ip',false,__LINE__,__FILE__); 872 873 while($this->db->next_record()) 874 { 875 if(preg_match('/^\\d+\\.(\\d+\\.(\\d+\\.)?)?\\*$/',$this->db->f('wiki_rate_ip'))) 876 { 877 $list[] = $this->db->f('wiki_rate_ip'); 878 } 879 } 880 return $list; 881 } 882 883 /** 884 * Block an address range. 885 * 886 * @param string $address ip-addr. or addr-range 887 */ 888 function rateBlockAdd($address) 889 { 890 if(preg_match('/^\\d+\\.(\\d+\\.(\\d+\\.)?)?\\*$/', $address)) 891 { 892 $this->db->select($this->RtTbl,'*',array( 893 'wiki_rate_ip' => $address 894 ),__LINE__,__FILE__); 895 896 if(!$this->db->next_record()) 897 { 898 $this->db->insert($this->RtTbl,array( 899 'wiki_rate_ip' => $address, 900 'wiki_rate_time'=> time(), 901 ),__LINE__,__FILE__); 902 } 903 } 904 } 905 906 /** 907 * Remove an address-range block. 908 * 909 * @param string $address ip-addr. or addr-range 910 */ 911 function rateBlockRemove($address) 912 { 913 $this->db->delete($this->RtTbl,array('wiki_rate_ip' => $address),__LINE__,__FILE__); 914 } 915 } 916 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |