| [ Index ] |
PHP Cross Reference of MyBB 1.6.5 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * MyBB 1.6 4 * Copyright 2010 MyBB Group, All Rights Reserved 5 * 6 * Website: http://mybb.com 7 * License: http://mybb.com/about/license 8 * 9 * $Id: akismet.php 5297 2010-12-28 22:01:14Z Tomm $ 10 */ 11 12 // Disallow direct access to this file for security reasons 13 if(!defined("IN_MYBB")) 14 { 15 die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined."); 16 } 17 18 // Neat trick for caching our custom template(s) 19 // Basically, when we include this from class_plugins.php we can do stuff in init.php, which is before we cache our templates 20 // So we won't need an extra call to cache it. 21 22 if(my_strpos($_SERVER['PHP_SELF'], 'showthread.php')) 23 { 24 global $templatelist; 25 if(isset($templatelist)) 26 { 27 $templatelist .= ','; 28 } 29 $templatelist .= 'akismet_postbit_spam'; 30 } 31 32 $plugins->add_hook("datahandler_post_insert_thread", "akismet_verify"); 33 $plugins->add_hook("datahandler_post_insert_thread_post", "akismet_verify"); 34 $plugins->add_hook("datahandler_post_insert_post", "akismet_verify"); 35 $plugins->add_hook("datahandler_post_validate_post", "akismet_fake_draft"); 36 $plugins->add_hook("datahandler_post_validate_thread", "akismet_fake_draft"); 37 $plugins->add_hook("newreply_do_newreply_end", "akismet_redirect_thread"); 38 $plugins->add_hook("newthread_do_newthread_end", "akismet_redirect_forum"); 39 $plugins->add_hook("moderation_start", "akismet_moderation_start"); 40 $plugins->add_hook("postbit", "akismet_postbit"); 41 42 $plugins->add_hook("admin_forum_menu", "akismet_admin_nav"); 43 $plugins->add_hook("admin_forum_permissions", "akismet_admin_permissions"); 44 $plugins->add_hook("admin_load", "akismet_admin"); 45 $plugins->add_hook("admin_forum_action_handler", "akismet_action_handler"); 46 $plugins->add_hook("admin_config_plugins_activate_commit", "akismet_key"); 47 48 function akismet_info() 49 { 50 global $lang; 51 52 $lang->load("forum_akismet", false, true); 53 54 return array( 55 "name" => $lang->akismet, 56 "description" => $lang->akismet_desc, 57 "website" => "http://mybb.com", 58 "author" => "MyBB Group", 59 "authorsite" => "http://mybb.com", 60 "version" => "1.2.1", 61 "guid" => "e57a80dbe7ff85083596a1a3b7da3ce7", 62 "compatibility" => "16*", 63 ); 64 } 65 66 /** 67 * ADDITIONAL PLUGIN INSTALL/UNINSTALL ROUTINES 68 * 69 * _install(): 70 * Called whenever a plugin is installed by clicking the "Install" button in the plugin manager. 71 * If no install routine exists, the install button is not shown and it assumed any work will be 72 * performed in the _activate() routine. 73 * 74 * function hello_install() 75 * { 76 * } 77 * 78 * _is_installed(): 79 * Called on the plugin management page to establish if a plugin is already installed or not. 80 * This should return TRUE if the plugin is installed (by checking tables, fields etc) or FALSE 81 * if the plugin is not installed. 82 * 83 * function hello_is_installed() 84 * { 85 * global $db; 86 * if($db->table_exists("hello_world")) 87 * { 88 * return true; 89 * } 90 * return false; 91 * } 92 * 93 * _uninstall(): 94 * Called whenever a plugin is to be uninstalled. This should remove ALL traces of the plugin 95 * from the installation (tables etc). If it does not exist, uninstall button is not shown. 96 * 97 * function hello_uninstall() 98 * { 99 * } 100 * 101 * _activate(): 102 * Called whenever a plugin is activated via the Admin CP. This should essentially make a plugin 103 * "visible" by adding templates/template changes, language changes etc. 104 * 105 * function hello_activate() 106 * { 107 * } 108 * 109 * _deactivate(): 110 * Called whenever a plugin is deactivated. This should essentially "hide" the plugin from view 111 * by removing templates/template changes etc. It should not, however, remove any information 112 * such as tables, fields etc - that should be handled by an _uninstall routine. When a plugin is 113 * uninstalled, this routine will also be called before _uninstall() if the plugin is active. 114 * 115 * function hello_deactivate() 116 * { 117 * } 118 */ 119 120 function akismet_install() 121 { 122 global $db, $mybb, $lang; 123 124 if($db->field_exists('akismetstopped', "users")) 125 { 126 $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP akismetstopped"); 127 } 128 129 // DELETE ALL SETTINGS TO AVOID DUPLICATES 130 $db->write_query("DELETE FROM ".TABLE_PREFIX."settings WHERE name IN( 131 'akismetswitch', 132 'akismetnumtillban', 133 'akismetfidsignore', 134 'akismetuidsignore', 135 'akismetuserstoignore' 136 )"); 137 $db->delete_query("settinggroups", "name = 'akismet'"); 138 $db->delete_query("datacache", "title = 'akismet_update_check'"); 139 140 $query = $db->simple_select("settinggroups", "COUNT(*) as rows"); 141 $rows = $db->fetch_field($query, "rows"); 142 143 $insertarray = array( 144 'name' => 'akismet', 145 'title' => 'Akismet', 146 'description' => 'Options on how to configure and personalize Akismet', 147 'disporder' => $rows+1, 148 'isdefault' => 0 149 ); 150 $group['gid'] = $db->insert_query("settinggroups", $insertarray); 151 $mybb->akismet_insert_gid = $group['gid']; 152 153 $insertarray = array( 154 'name' => 'akismetswitch', 155 'title' => 'Akismet Main Switch', 156 'description' => 'Turns on or off Akismet.', 157 'optionscode' => 'onoff', 158 'value' => 1, 159 'disporder' => 0, 160 'gid' => $group['gid'] 161 ); 162 $db->insert_query("settings", $insertarray); 163 164 $insertarray = array( 165 'name' => 'akismetapikey', 166 'title' => 'API Key to use for Akismet', 167 'description' => $db->escape_string('The API Key used to connect to Akismet. Please check here for more details: <a href="http://wordpress.com/api-keys/" target="_blank">http://wordpress.com/api-keys/</a>'), 168 'optionscode' => 'text', 169 'value' => '', 170 'disporder' => 1, 171 'gid' => $group['gid'] 172 ); 173 $db->insert_query("settings", $insertarray); 174 175 $insertarray = array( 176 'name' => 'akismetnumtillban', 177 'title' => 'Spam messages until ban', 178 'description' => 'The number of spam messages detected by Akismet until the user gets banned (set to 0 to disable).', 179 'optionscode' => 'text', 180 'value' => '3', 181 'disporder' => 2, 182 'gid' => $group['gid'] 183 ); 184 $db->insert_query("settings", $insertarray); 185 186 $insertarray = array( 187 'name' => 'akismetfidsignore', 188 'title' => 'Forums to Ignore', 189 'description' => 'Forums, separated by a comma, to ignore. Use the forum id, <strong>not the name</strong>.', 190 'optionscode' => 'text', 191 'value' => '', 192 'disporder' => 3, 193 'gid' => $group['gid'] 194 ); 195 $db->insert_query("settings", $insertarray); 196 197 $insertarray = array( 198 'name' => 'akismetuidsignore', 199 'title' => 'Usergroups to Ignore', 200 'description' => 'Usergroups, separated by a comma, to ignore. Use the usergroup id, <strong>not the name</strong>.', 201 'optionscode' => 'text', 202 'value' => '6,4,3', 203 'disporder' => 4, 204 'gid' => $group['gid'] 205 ); 206 $db->insert_query("settings", $insertarray); 207 208 $insertarray = array( 209 'name' => 'akismetuserstoignore', 210 'title' => 'Users to Ignore', 211 'description' => 'Users, separated by a comma, to ignore. Use the user id, <strong>not the name</strong>.', 212 'optionscode' => 'text', 213 'value' => '', 214 'disporder' => 6, 215 'gid' => $group['gid'] 216 ); 217 $db->insert_query("settings", $insertarray); 218 219 $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD akismetstopped int NOT NULL default 0"); 220 221 rebuild_settings(); 222 } 223 224 function akismet_is_installed() 225 { 226 global $db; 227 228 if($db->field_exists('akismetstopped', "users")) 229 { 230 return true; 231 } 232 233 return false; 234 } 235 236 function akismet_activate() 237 { 238 global $db, $mybb; 239 240 include MYBB_ROOT."/inc/adminfunctions_templates.php"; 241 242 find_replace_templatesets("postbit", "#".preg_quote('{$post[\'button_spam\']}')."#i", '', 0); 243 find_replace_templatesets("postbit_classic", "#".preg_quote('{$post[\'button_spam\']}')."#i", '', 0); 244 245 $db->delete_query("templates", "title = 'akismet_postbit_spam'"); 246 247 find_replace_templatesets("postbit", "#".preg_quote('{$post[\'button_edit\']}')."#i", '{$post[\'button_spam\']}{$post[\'button_edit\']}'); 248 find_replace_templatesets("postbit_classic", "#".preg_quote('{$post[\'button_edit\']}')."#i", '{$post[\'button_spam\']}{$post[\'button_edit\']}'); 249 250 $insert_array = array( 251 'title' => 'akismet_postbit_spam', 252 'template' => $db->escape_string('<a href="{$mybb->settings[\'bburl\']}/moderation.php?action=mark_as_spam&pid={$post[\'pid\']}&fid={$post[\'fid\']}"><img src="{$theme[\'imglangdir\']}/postbit_spam.gif" alt="{$lang->spam}" /></a>'), 253 'sid' => '-1', 254 'version' => '', 255 'dateline' => TIME_NOW 256 ); 257 258 $db->insert_query("templates", $insert_array); 259 260 change_admin_permission('forum', 'akismet'); 261 } 262 263 function akismet_deactivate() 264 { 265 global $db, $mybb; 266 267 include MYBB_ROOT."/inc/adminfunctions_templates.php"; 268 269 find_replace_templatesets("postbit", "#".preg_quote('{$post[\'button_spam\']}')."#i", '', 0); 270 find_replace_templatesets("postbit_classic", "#".preg_quote('{$post[\'button_spam\']}')."#i", '', 0); 271 272 $db->delete_query("templates", "title = 'akismet_postbit_spam'"); 273 274 change_admin_permission('forum', 'akismet', -1); 275 } 276 277 function akismet_uninstall() 278 { 279 global $db; 280 281 if($db->field_exists('akismetstopped', "users")) 282 { 283 $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP akismetstopped"); 284 } 285 286 // DELETE ALL SETTINGS TO AVOID DUPLICATES 287 $db->write_query("DELETE FROM ".TABLE_PREFIX."settings WHERE name IN( 288 'akismetswitch', 289 'akismetapikey', 290 'akismetnumtillban', 291 'akismetfidsignore', 292 'akismetuidsignore', 293 'akismetuserstoignore' 294 )"); 295 $db->delete_query("settinggroups", "name = 'akismet'"); 296 $db->delete_query("datacache", "title = 'akismet_update_check'"); 297 rebuild_settings(); 298 } 299 300 function akismet_key() 301 { 302 global $installed, $mybb; 303 304 if($installed == false && $mybb->input['plugin'] == "akismet") 305 { 306 global $message; 307 308 flash_message($message, 'success'); 309 admin_redirect("index.php?module=config-settings&action=change&gid=".intval($mybb->akismet_insert_gid)."#row_setting_akismetapikey"); 310 } 311 } 312 313 314 function akismet_show_confirm_page() 315 { 316 global $mybb, $lang, $theme, $pid, $fid, $db, $headerinclude, $header, $footer; 317 318 $pid = intval($pid); 319 $fid = intval($fid); 320 321 $query = $db->simple_select("posts", "subject", "pid='{$pid}'", 1); 322 $post = $db->fetch_array($query); 323 324 if(!$post) 325 { 326 error("Invalid Post ID."); 327 } 328 329 output_page("<html> 330 <head> 331 <title>{$mybb->settings['bbname']} - {$lang->mark_as_spam}</title> 332 {$headerinclude} 333 </head> 334 <body> 335 {$header} 336 <form action=\"moderation.php\" method=\"post\"> 337 <input type=\"hidden\" name=\"my_post_key\" value=\"{$mybb->post_code}\" /> 338 <table border=\"0\" cellspacing=\"{$theme['borderwidth']}\" cellpadding=\"{$theme['tablespace']}\" class=\"tborder\"> 339 <tr> 340 <td class=\"thead\" colspan=\"2\"><strong>{$post['subject']} - {$lang->mark_as_spam}</strong></td> 341 </tr> 342 <tr> 343 <td class=\"trow1\" colspan=\"2\" align=\"center\">{$lang->confirm_mark_as_spam}</td> 344 </tr> 345 {$loginbox} 346 </table> 347 <br /> 348 <div align=\"center\"><input type=\"submit\" class=\"button\" name=\"submit\" value=\"{$lang->mark_as_spam}\" /></div> 349 <input type=\"hidden\" name=\"action\" value=\"mark_as_spam\" /> 350 <input type=\"hidden\" name=\"pid\" value=\"{$pid}\" /> 351 <input type=\"hidden\" name=\"fid\" value=\"{$fid}\" /> 352 </form> 353 {$footer} 354 </body> 355 </html>"); 356 exit; 357 } 358 359 function akismet_moderation_start() 360 { 361 global $mybb, $db, $akismet, $lang, $cache, $fid, $pid; 362 363 if(!$mybb->settings['akismetswitch'] || $mybb->input['action'] != 'mark_as_spam') 364 { 365 return; 366 } 367 368 $lang->load("akismet", false, true); 369 370 if(!$mybb->input['pid']) 371 { 372 error("No Post ID specified."); 373 } 374 375 $pid = intval($mybb->input['pid']); 376 377 if(!$mybb->input['fid']) 378 { 379 error("No Forum ID specified."); 380 } 381 382 $fid = intval($mybb->input['fid']); 383 384 if(!is_moderator($fid)) 385 { 386 error("No Permissions to do this action."); 387 } 388 389 $query = $db->query(" 390 SELECT p.uid, p.username, u.email, u.website, u.akismetstopped, p.message, p.ipaddress, p.tid, p.replyto, p.fid, f.usepostcounts 391 FROM ".TABLE_PREFIX."posts p 392 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 393 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 394 WHERE p.pid = '{$pid}' 395 "); 396 $post = $db->fetch_array($query); 397 398 if(!$post) 399 { 400 error("Invalid Post ID."); 401 } 402 403 if(!$mybb->input['my_post_key'] || $mybb->request_method != "post") 404 { 405 akismet_show_confirm_page(); 406 } 407 408 verify_post_check($mybb->input['my_post_key']); 409 410 $akismet_array = array( 411 'type' => 'post', 412 'username' => $post['username'], 413 'email' => $post['email'], 414 'website' => $post['website'], 415 'message' => $post['message'], 416 'user_ip' => $post['ipaddress'] 417 ); 418 419 if($post['replyto'] == 0) 420 { 421 $db->update_query("threads", array('visible' => '-4'), "tid = '{$post['tid']}'"); 422 $db->update_query("posts", array('visible' => '-4'), "tid = '{$post['tid']}'"); 423 $snippit = "thread"; 424 } 425 else 426 { 427 $db->update_query("posts", array('visible' => '-4'), "pid = '{$pid}'"); 428 $snippit = "post"; 429 } 430 431 if(!$akismet) 432 { 433 $akismet = new Akismet($mybb->settings['bburl'], $mybb->settings['akismetapikey'], $akismet_array); 434 } 435 436 $akismet->submit_spam(); 437 438 $numakismetthread = $numakismetpost = 0; 439 440 if($snippit == "thread") 441 { 442 $query = $db->query(" 443 SELECT p.uid, u.usergroup 444 FROM ".TABLE_PREFIX."posts p 445 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 446 WHERE p.tid = '{$post['tid']}' 447 "); 448 while($post2 = $db->fetch_array($query)) 449 { 450 ++$numakismetpost; 451 452 if($post['usepostcounts'] != 0) 453 { 454 $db->write_query("UPDATE ".TABLE_PREFIX."users SET postnum=postnum-1 WHERE uid = '{$post2['uid']}'"); 455 } 456 457 if($mybb->settings['akismetuidsignore']) 458 { 459 $akismet_uids_ignore = explode(',', $mybb->settings['akismetuidsignore']); 460 if(in_array($post2['usergroup'], $akismet_uids_ignore) || is_super_admin($post2['uid'])) 461 { 462 continue; 463 } 464 } 465 466 if(is_super_admin($post2['uid'])) 467 { 468 continue; 469 } 470 471 $db->write_query("UPDATE ".TABLE_PREFIX."users SET akismetstopped=akismetstopped+1 WHERE uid = '{$post2['uid']}'"); 472 $query1 = $db->simple_select("users", "akismetstopped", "uid = '{$post2['uid']}'"); 473 $akismetstopped = $db->fetch_field($query1, 'akismetstopped'); 474 475 // Check if the person should be banned 476 if($mybb->settings['akismetnumtillban'] > 0 && $akismetstopped >= $mybb->settings['akismetnumtillban']) 477 { 478 $banned_user = array( 479 "uid" => $post2['uid'], 480 "admin" => 0, 481 "gid" => 7, 482 "oldgroup" => $post2['usergroup'], 483 "dateline" => TIME_NOW, 484 "bantime" => 'perm', 485 "lifted" => 'perm', 486 "reason" => "Automatically banned by the Akismet system for spamming.", 487 "oldadditionalgroups" => '' 488 ); 489 $db->insert_query("banned", $banned_user); 490 491 $db->update_query("users", array('usergroup' => 7), "uid = '{$post2['uid']}'"); 492 493 $cache->update_moderators(); 494 } 495 } 496 497 ++$numakismetthread; 498 } 499 else 500 { 501 $db->write_query("UPDATE ".TABLE_PREFIX."users SET akismetstopped=akismetstopped+1 WHERE uid = '{$post['uid']}'"); 502 $query = $db->simple_select("users", "akismetstopped, usergroup", "uid = '{$post['uid']}'"); 503 $akismetstopped = $db->fetch_field($query, 'akismetstopped'); 504 $usergroup = $db->fetch_field($query, 'usergroup'); 505 506 if($mybb->settings['akismetuidsignore']) 507 { 508 $akismet_uids_ignore = explode(',', $mybb->settings['akismetuidsignore']); 509 if(in_array($usergroup, $akismet_uids_ignore)) 510 { 511 continue; 512 } 513 } 514 515 if(is_super_admin($post['uid'])) 516 { 517 continue; 518 } 519 520 // Check if the person should be banned 521 if($mybb->settings['akismetnumtillban'] > 0 && $akismetstopped >= $mybb->settings['akismetnumtillban']) 522 { 523 $banned_user = array( 524 "uid" => $post['uid'], 525 "admin" => 0, 526 "gid" => 7, 527 "oldgroup" => $usergroup, 528 "dateline" => TIME_NOW, 529 "bantime" => 'perm', 530 "lifted" => 'perm', 531 "reason" => "Automatically banned by the Akismet system for spamming.", 532 "oldadditionalgroups" => '' 533 ); 534 $db->insert_query("banned", $banned_user); 535 536 $db->update_query("users", array('usergroup' => 7), "uid = '{$post['uid']}'"); 537 538 $cache->update_moderators(); 539 } 540 541 ++$numakismetpost; 542 543 if($post['usepostcounts'] != 0) 544 { 545 $db->write_query("UPDATE ".TABLE_PREFIX."users SET postnum=postnum-1 WHERE uid = '{$post['uid']}'"); 546 } 547 } 548 549 update_thread_counters($post['tid'], array('replies' => '-'.$numakismetpost)); 550 update_forum_counters($post['fid'], array('threads' => '-'.$numakismetthread, 'posts' => '-'.$numakismetpost)); 551 552 if($snippit == "thread") 553 { 554 redirect("./forumdisplay.php?fid={$post['fid']}", $lang->thread_spam_success); 555 } 556 else 557 { 558 redirect("./showthread.php?tid={$post['tid']}", $lang->post_spam_success); 559 } 560 } 561 562 function akismet_postbit(&$post) 563 { 564 global $templates, $mybb, $theme, $lang; 565 566 if(!$mybb->settings['akismetswitch'] || !is_moderator($post['fid'])) 567 { 568 return; 569 } 570 571 if($mybb->settings['akismetuidsignore']) 572 { 573 $akismet_uids_ignore = explode(',', $mybb->settings['akismetuidsignore']); 574 if(in_array($usergroup, $akismet_uids_ignore)) 575 { 576 return; 577 } 578 } 579 580 if(is_super_admin($post['uid'])) 581 { 582 return; 583 } 584 585 $lang->load("akismet", false, true); 586 587 eval("\$post['button_spam'] = \"".$templates->get("akismet_postbit_spam")."\";"); 588 } 589 590 function akismet_verify(&$post) 591 { 592 global $mybb, $isspam, $akismet; 593 594 if($isspam == true && $mybb->settings['akismetswitch'] == 1) 595 { 596 if(isset($post->thread_insert_data)) 597 { 598 $post->thread_insert_data['visible'] = '-4'; 599 } 600 601 $post->post_insert_data['visible'] = '-4'; 602 } 603 } 604 605 function akismet_fake_draft(&$post) 606 { 607 global $mybb, $isspam, $akismet, $cache; 608 609 $exclude_array = explode(',', $mybb->settings['akismetuserstoignore']); 610 611 if(!$mybb->settings['akismetswitch'] || in_array($mybb->user['uid'], $exclude_array) || is_super_admin($mybb->user['uid'])) 612 { 613 return; 614 } 615 616 if($mybb->settings['akismetfidsignore']) 617 { 618 $akismet_fids_ignore = explode(',', $mybb->settings['akismetfidsignore']); 619 if(in_array($post->data['fid'], $akismet_fids_ignore)) 620 { 621 return; 622 } 623 } 624 625 if($mybb->settings['akismetuidsignore']) 626 { 627 $akismet_uids_ignore = explode(',', $mybb->settings['akismetuidsignore']); 628 if(in_array($mybb->user['usergroup'], $akismet_uids_ignore)) 629 { 630 return; 631 } 632 } 633 634 $akismet_array = array( 635 'type' => 'post', 636 'username' => $post->data['username'], 637 'email' => $mybb->user['email'], 638 'website' => $mybb->user['website'], 639 'message' => $post->data['message'], 640 'user_ip' => $mybb->user['ipaddress'] 641 ); 642 643 if(!$akismet) 644 { 645 $akismet = new Akismet($mybb->settings['bburl'], $mybb->settings['akismetapikey'], $akismet_array); 646 } 647 648 if($akismet->check()) 649 { 650 global $db; 651 652 $isspam = true; 653 654 // Update our spam count attempts 655 ++$mybb->user['akismetstopped']; 656 $db->update_query("users", array('akismetstopped' => $mybb->user['akismetstopped']), "uid = '{$mybb->user['uid']}'"); 657 658 // Check if the person should be banned 659 if($mybb->settings['akismetnumtillban'] > 0 && $mybb->user['akismetstopped'] >= $mybb->settings['akismetnumtillban']) 660 { 661 $banned_user = array( 662 "uid" => $mybb->user['uid'], 663 "admin" => 0, 664 "gid" => 7, 665 "oldgroup" => $mybb->user['usergroup'], 666 "dateline" => TIME_NOW, 667 "bantime" => 'perm', 668 "lifted" => 'perm', 669 "reason" => "Automatically banned by the Akismet system for spamming.", 670 "oldadditionalgroups" => '' 671 ); 672 $db->insert_query("banned", $banned_user); 673 674 $db->update_query("users", array('usergroup' => 7), "uid = '{$mybb->user['uid']}'"); 675 676 $cache->update_moderators(); 677 678 // We better do this..otherwise they have dodgy permissions 679 $mybb->user['banoldgroup'] = $mybb->user['usergroup']; 680 $mybb->user['usergroup'] = 7; 681 682 global $mybbgroups; 683 684 $mybbgroups = $mybb->user['usergroup']; 685 if($mybb->user['additionalgroups']) 686 { 687 $mybbgroups .= ','.$mybb->user['additionalgroups']; 688 } 689 } 690 691 // Fake visibility 692 // Essentially because you can't modify the $visible variable we need to trick it 693 // into thinking its saving a draft so it won't modify the users lastpost and postcount 694 // In akismet_verify, its set back to -4 so we can still uniquely verify that this is a spam message 695 // before it's inserted into the database. 696 $post->data['savedraft'] = 1; 697 } 698 } 699 700 function akismet_redirect_thread() 701 { 702 global $isspam, $url, $lang, $thread, $mybb; 703 704 if($isspam && $mybb->settings['akismetswitch'] == 1) 705 { 706 $lang->load("akismet", false, true); 707 708 $url = get_thread_link($thread['tid']); 709 $url2 = get_forum_link($thread['fid']); 710 711 error("<div align=\"center\">".$lang->redirect_newreply."<br /><br />".$lang->sprintf($lang->redirect_return_forum, $url, $url2)."</div>", $lang->akismet_error); 712 } 713 } 714 715 function akismet_redirect_forum() 716 { 717 global $isspam, $url, $lang, $fid, $mybb; 718 719 if($isspam && $mybb->settings['akismetswitch'] == 1) 720 { 721 $lang->load("akismet", false, true); 722 723 $url = get_forum_link($fid); 724 725 error("<div align=\"center\">".$lang->redirect_newthread."<br /><br />".$lang->sprintf($lang->redirect_return_forum, $url)."</div>", $lang->akismet_error); 726 } 727 } 728 729 function akismet_action_handler(&$action) 730 { 731 $action['akismet'] = array('active' => 'akismet', 'file' => ''); 732 } 733 734 function akismet_admin_nav(&$sub_menu) 735 { 736 global $mybb, $lang; 737 738 if($mybb->settings['akismetswitch'] == 1) 739 { 740 $lang->load("forum_akismet", false, true); 741 742 end($sub_menu); 743 $key = (key($sub_menu))+10; 744 745 if(!$key) 746 { 747 $key = '50'; 748 } 749 750 $sub_menu[$key] = array('id' => 'akismet', 'title' => $lang->akismet, 'link' => "index.php?module=forum-akismet"); 751 } 752 } 753 754 function akismet_admin_permissions(&$admin_permissions) 755 { 756 global $db, $mybb; 757 758 if($mybb->settings['akismetswitch'] == 1) 759 { 760 global $lang; 761 762 $lang->load("forum_akismet", false, true); 763 764 $admin_permissions['akismet'] = $lang->can_manage_akismet; 765 } 766 } 767 768 function akismet_admin() 769 { 770 global $mybb, $db, $page, $lang; 771 772 if($page->active_action != "akismet") 773 { 774 return; 775 } 776 777 $page->add_breadcrumb_item($lang->akismet); 778 779 if($mybb->input['delete_all'] && $mybb->request_method == "post") 780 { 781 // User clicked no 782 if($mybb->input['no']) 783 { 784 admin_redirect("index.php?module=forum-akismet"); 785 } 786 787 if($mybb->request_method == "post") 788 { 789 // Delete the template 790 $db->delete_query("posts", "visible = '-4'"); 791 792 // Log admin action 793 log_admin_action(); 794 795 flash_message($lang->success_deleted_spam, 'success'); 796 admin_redirect("index.php?module=forum-akismet"); 797 } 798 else 799 { 800 $page->output_confirm_action("index.php?module=forum-akismet&delete_all=1", $lang->confirm_spam_deletion); 801 } 802 } 803 804 if($mybb->input['unmark'] && $mybb->request_method == "post") 805 { 806 $unmark = $mybb->input['akismet']; 807 808 if(empty($unmark)) 809 { 810 flash_message($lang->error_unmark, 'error'); 811 admin_redirect("index.php?module=forum-akismet"); 812 } 813 814 $posts_in = ''; 815 $comma = ''; 816 foreach($unmark as $key => $val) 817 { 818 $posts_in .= $comma.intval($key); 819 $comma = ','; 820 } 821 822 $query = $db->simple_select("posts", "pid, tid", "pid IN ({$posts_in}) AND replyto = '0'"); 823 while($post = $db->fetch_array($query)) 824 { 825 $threadp[] = $post['tid']; 826 } 827 828 if(!is_array($threadp)) 829 { 830 $threadp = array(); 831 } 832 833 $thread_list = implode(',', $threadp); 834 835 $query = $db->query(" 836 SELECT p.tid, f.usepostcounts, p.uid, p.fid, p.dateline, p.replyto, t.lastpost, t.lastposter, t.lastposteruid, t.subject 837 FROM ".TABLE_PREFIX."posts p 838 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 839 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 840 WHERE p.pid IN ({$posts_in}) AND p.visible = '-4' 841 "); 842 while($post = $db->fetch_array($query)) 843 { 844 // Fetch the last post for this forum 845 $query2 = $db->query(" 846 SELECT tid, lastpost, lastposter, lastposteruid, subject 847 FROM ".TABLE_PREFIX."threads 848 WHERE fid='{$post['fid']}' AND visible='1' AND closed NOT LIKE 'moved|%' 849 ORDER BY lastpost DESC 850 LIMIT 0, 1 851 "); 852 $lastpost = $db->fetch_array($query2); 853 854 if($post['lastpost'] > $lastpost['lastpost']) 855 { 856 $lastpost['lastpost'] = $post['lastpost']; 857 $lastpost['lastposter'] = $post['lastposter']; 858 $lastpost['lastposteruid'] = $post['lastposteruid']; 859 $lastpost['subject'] = $post['subject']; 860 $lastpost['tid'] = $post['tid']; 861 } 862 863 $update_count = array( 864 "lastpost" => intval($lastpost['lastpost']), 865 "lastposter" => $db->escape_string($lastpost['lastposter']), 866 "lastposteruid" => intval($lastpost['lastposteruid']), 867 "lastposttid" => intval($lastpost['tid']), 868 "lastpostsubject" => $db->escape_string($lastpost['subject']) 869 ); 870 871 $db->update_query("forums", $update_count, "fid='{$post['fid']}'"); 872 873 $query2 = $db->query(" 874 SELECT u.uid, u.username, p.username AS postusername, p.dateline 875 FROM ".TABLE_PREFIX."posts p 876 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 877 WHERE p.tid='{$post['tid']}' AND p.visible='1' OR p.pid = '{$post['pid']}' 878 ORDER BY p.dateline DESC 879 LIMIT 1" 880 ); 881 $lastpost = $db->fetch_array($query2); 882 883 $query2 = $db->query(" 884 SELECT u.uid, u.username, p.username AS postusername, p.dateline 885 FROM ".TABLE_PREFIX."posts p 886 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 887 WHERE p.tid='{$post['tid']}' 888 ORDER BY p.dateline ASC 889 LIMIT 0,1 890 "); 891 $firstpost = $db->fetch_array($query2); 892 893 if(!$firstpost['username']) 894 { 895 $firstpost['username'] = $firstpost['postusername']; 896 } 897 if(!$lastpost['username']) 898 { 899 $lastpost['username'] = $lastpost['postusername']; 900 } 901 902 if(!$lastpost['dateline']) 903 { 904 $lastpost['username'] = $firstpost['username']; 905 $lastpost['uid'] = $firstpost['uid']; 906 $lastpost['dateline'] = $firstpost['dateline']; 907 } 908 909 $lastpost['username'] = $db->escape_string($lastpost['username']); 910 $firstpost['username'] = $db->escape_string($firstpost['username']); 911 912 $query2 = $db->simple_select("users", "akismetstopped", "uid='{$post['uid']}'"); 913 $akismetstopped = $db->fetch_field($query2, "akismetstopped")-1; 914 915 if($akismetstopped < 0) 916 { 917 $akismetstopped = 0; 918 } 919 $db->update_query("users", array('akismetstopped' => $akismetstopped), "uid='{$post['uid']}'"); 920 921 $update_array = array( 922 'username' => $firstpost['username'], 923 'uid' => intval($firstpost['uid']), 924 'lastpost' => intval($lastpost['dateline']), 925 'lastposter' => $lastpost['username'], 926 'lastposteruid' => intval($lastpost['uid']), 927 ); 928 $db->update_query("threads", $update_array, "tid='{$post['tid']}'"); 929 930 if($post['usepostcounts'] != 0) 931 { 932 $db->write_query("UPDATE ".TABLE_PREFIX."users SET postnum=postnum+1 WHERE uid = '{$post['uid']}'"); 933 } 934 935 $newthreads = $newreplies = 0; 936 937 if($post['replyto'] == 0) 938 { 939 ++$newthreads; 940 } 941 else 942 { 943 ++$newreplies; 944 } 945 946 update_thread_counters($post['tid'], array('replies' => '+'.$newreplies)); 947 update_forum_counters($post['fid'], array('threads' => '+'.$newthreads, 'posts' => '+1')); 948 } 949 950 $approve = array( 951 "visible" => 1, 952 ); 953 954 if($thread_list) 955 { 956 $db->update_query("threads", $approve, "tid IN ({$thread_list})"); 957 } 958 959 $db->update_query("posts", $approve, "pid IN ({$posts_in})"); 960 961 // Log admin action 962 log_admin_action(); 963 964 flash_message($lang->success_unmarked, 'success'); 965 admin_redirect("index.php?module=forum-akismet"); 966 } 967 968 if($mybb->input['delete'] && $mybb->request_method == "post") 969 { 970 $deletepost = $mybb->input['akismet']; 971 972 if(empty($deletepost)) 973 { 974 flash_message($lang->error_deletepost, 'error'); 975 admin_redirect("index.php?module=forum-akismet"); 976 } 977 978 $posts_in = ''; 979 $comma = ''; 980 foreach($deletepost as $key => $val) 981 { 982 $posts_in .= $comma.intval($key); 983 $comma = ','; 984 } 985 986 $query = $db->simple_select("posts", "pid, tid", "pid IN ({$posts_in}) AND replyto = '0'"); 987 while($post = $db->fetch_array($query)) 988 { 989 $threadp[$post['pid']] = $post['tid']; 990 } 991 992 if(!is_array($threadp)) 993 { 994 $threadp = array(); 995 } 996 997 require_once MYBB_ROOT."inc/functions_upload.php"; 998 999 foreach($deletepost as $pid => $val) 1000 { 1001 if(array_key_exists($pid, $threadp)) 1002 { 1003 $db->delete_query("posts", "pid IN ({$posts_in})"); 1004 $db->delete_query("attachments", "pid IN ({$posts_in})"); 1005 1006 // Get thread info 1007 $query = $db->simple_select("threads", "poll", "tid='".$threadp[$pid]."'"); 1008 $poll = $db->fetch_field($query, 'poll'); 1009 1010 // Delete threads, redirects, favorites, polls, and poll votes 1011 $db->delete_query("threads", "tid='".$threadp[$pid]."'"); 1012 $db->delete_query("threads", "closed='moved|".$threadp[$pid]."'"); 1013 $db->delete_query("threadsubscriptions", "tid='".$threadp[$pid]."'"); 1014 $db->delete_query("polls", "tid='".$threadp[$pid]."'"); 1015 $db->delete_query("pollvotes", "pid='{$poll}'"); 1016 } 1017 1018 // Remove attachments 1019 remove_attachments($pid); 1020 1021 // Delete the post 1022 $db->delete_query("posts", "pid='{$pid}'"); 1023 } 1024 1025 // Log admin action 1026 log_admin_action(); 1027 1028 flash_message($lang->success_spam_deleted, 'success'); 1029 admin_redirect("index.php?module=forum-akismet"); 1030 } 1031 1032 if(!$mybb->input['action']) 1033 { 1034 require MYBB_ROOT."inc/class_parser.php"; 1035 $parser = new postParser; 1036 1037 $page->output_header($lang->akismet); 1038 1039 $form = new Form("index.php?module=forum-akismet", "post"); 1040 1041 $table = new Table; 1042 $table->construct_header($form->generate_check_box("checkall", 1, '', array('class' => 'checkall')), array('width' => '5%')); 1043 $table->construct_header("Title / Username / Post", array('class' => 'align_center')); 1044 1045 $mybb->input['page'] = intval($mybb->input['page']); 1046 1047 if($mybb->input['page'] > 0) 1048 { 1049 $start = $mybb->input['page'] * 20; 1050 } 1051 else 1052 { 1053 $start = 0; 1054 } 1055 1056 $query = $db->simple_select("posts", "COUNT(pid) as spam", "visible = '-4'"); 1057 $total_rows = $db->fetch_field($query, 'spam'); 1058 1059 if($start > $total_rows) 1060 { 1061 $start = $total_rows - 20; 1062 } 1063 1064 if($start < 0) 1065 { 1066 $start = 0; 1067 } 1068 1069 $query = $db->simple_select("posts", "*", "visible = '-4'", array('limit_start' => $start, 'limit' => '20', 'order_by' => 'dateline', 'order_dir' => 'desc')); 1070 while($post = $db->fetch_array($query)) 1071 { 1072 if($post['uid'] != 0) 1073 { 1074 $username = "<a href=\"../".str_replace("{uid}", $post['uid'], PROFILE_URL)."\" target=\"_blank\">".format_name($post['username'], $post['usergroup'], $post['displaygroup'])."</a>"; 1075 } 1076 else 1077 { 1078 $username = $post['username']; 1079 } 1080 1081 $table->construct_cell($form->generate_check_box("akismet[{$post['pid']}]", 1, '')); 1082 $table->construct_cell("<span style=\"float: right;\">{$lang->username}: {$username}</span> <span style=\"float: left;\">{$lang->title}: {$post['subject']} <strong>(".my_date($mybb->settings['dateformat'], $post['dateline']).", ".my_date($mybb->settings['timeformat'], $post['dateline']).")</strong></span>"); 1083 $table->construct_row(); 1084 1085 $parser_options = array( 1086 "allow_html" => 0, 1087 "allow_mycode" => 0, 1088 "allow_smilies" => 0, 1089 "allow_imgcode" => 0, 1090 "me_username" => $post['username'], 1091 "filter_badwords" => 1 1092 ); 1093 $post['message'] = $parser->parse_message($post['message'], $parser_options); 1094 1095 $table->construct_cell($post['message'], array("colspan" => 2)); 1096 $table->construct_row(); 1097 } 1098 1099 $num_rows = $table->num_rows(); 1100 1101 if($num_rows == 0) 1102 { 1103 $table->construct_cell($lang->no_spam_found, array("class" => "align_center", "colspan" => 2)); 1104 $table->construct_row(); 1105 } 1106 1107 $table->output($lang->detected_spam_messages); 1108 1109 echo "<br />".draw_admin_pagination($mybb->input['page'], 20, $total_rows, "index.php?module=forum-akismet&page={page}"); 1110 1111 $buttons[] = $form->generate_submit_button($lang->unmark_selected, array('name' => 'unmark')); 1112 $buttons[] = $form->generate_submit_button($lang->deleted_selected, array('name' => 'delete')); 1113 1114 if($num_rows > 0) 1115 { 1116 $buttons[] = $form->generate_submit_button($lang->delete_all, array('name' => 'delete_all', 'onclick' => "return confirm('{$lang->confirm_spam_deletion}');")); 1117 } 1118 1119 $form->output_submit_wrapper($buttons); 1120 1121 $form->end(); 1122 1123 $page->output_footer(); 1124 } 1125 1126 exit; 1127 } 1128 1129 /** 1130 * This class is Copyright 2009 Ryan Gordon (Tikitiki) 1131 * Built to communicate with the akismet server 1132 */ 1133 1134 class Akismet { 1135 1136 /** 1137 * The array of required server keys when building a query string 1138 * 1139 * @var array 1140 */ 1141 var $required = array( 1142 'HTTP_REFERRER', 1143 'HTTP_ACCEPT_CHARSET', 1144 'SERVERNAME', 1145 'SERVER_ADDR', 1146 'REMOTE_ADDR', 1147 'HTTP_USER_AGENT' 1148 ); 1149 1150 /** 1151 * The array of a post to validate against Akismet. 1152 * 1153 * @var array 1154 */ 1155 var $post = array(); 1156 1157 /** 1158 * The port to use to connect to the Akismet servers 1159 * 1160 * @var integer 1161 */ 1162 var $port = 80; 1163 1164 /** 1165 * The address to use to connect to the Akismet servers 1166 * 1167 * @var string 1168 */ 1169 var $host = "rest.akismet.com"; 1170 1171 /** 1172 * The version of Akismet being used 1173 * 1174 * @var integer 1175 */ 1176 var $version = "1.1"; 1177 1178 /** 1179 * The API key used to validate your use of Akismet 1180 * 1181 * @var string 1182 */ 1183 var $key = false; 1184 1185 /** 1186 * The main page of your forum 1187 * 1188 * @var string 1189 */ 1190 var $site = false; 1191 1192 /** 1193 * The object of the Akismet connection 1194 * 1195 * @var object 1196 */ 1197 var $connection; 1198 1199 /** 1200 * Errors (uh oh) 1201 * 1202 * @var array 1203 */ 1204 var $errors = array(); 1205 1206 /** 1207 * Initilize the Akismet class 1208 * 1209 * @param string The board url. 1210 * @param int The API Key used to validate your use of Akismet. 1211 * @param array Array of the post that is going to be validated by Akismet. 1212 */ 1213 function Akismet($url, $api_key, $post) 1214 { 1215 // Set option stuff 1216 $this->url = $url; 1217 $this->api_key = $api_key; 1218 1219 $this->post = $post; 1220 1221 $this->format_post(); 1222 1223 if(!isset($this->post['user_ip'])) 1224 { 1225 if($_SERVER['REMOTE_ADDR'] != getenv('SERVER_ADDR')) 1226 { 1227 $this->post['user_ip'] = $_SERVER['REMOTE_ADDR']; 1228 } 1229 else 1230 { 1231 $this->post['user_ip'] = getenv('HTTP_X_FORWARDED_FOR'); 1232 } 1233 } 1234 1235 if(!isset($this->post['permalink'])) 1236 { 1237 $this->post['permalink'] = $_SERVER['HTTP_REFERER']; 1238 } 1239 1240 if(!isset($this->post['user_agent'])) 1241 { 1242 $this->post['user_agent'] = $_SERVER['HTTP_USER_AGENT']; 1243 } 1244 1245 if(!isset($this->post['referrer'])) 1246 { 1247 $this->post['referrer'] = $_SERVER['HTTP_REFERER']; 1248 } 1249 1250 $this->post['blog'] = $url; 1251 1252 // Check if the API key is valid 1253 if(!$this->validate_api_key()) 1254 { 1255 $this->set_error("invalid_key"); 1256 } 1257 } 1258 1259 /** 1260 * Checks a post against the Akismet server 1261 * 1262 * @return boolean True if the comment passed spam validation. 1263 */ 1264 function check() 1265 { 1266 if($this->fetch_response($this->build_query_string(), 'comment-check') == "true") 1267 { 1268 // We have spam! 1269 return true; 1270 } 1271 1272 // Good! The check failed; We're all good to go! 1273 return false; 1274 } 1275 1276 /** 1277 * Submits a spam post to the Akismet server 1278 * 1279 */ 1280 function submit_spam() 1281 { 1282 $this->fetch_response($this->build_query_string(), 'submit-spam'); 1283 } 1284 1285 /** 1286 * Submits a ham post to the Akismet server 1287 * 1288 */ 1289 function submit_ham() 1290 { 1291 $this->fetch_response($this->build_query_string(), 'submit-ham'); 1292 } 1293 1294 /** 1295 * Validate a API Key against the Akismet server 1296 * 1297 * @return boolean True if the API Key passed. 1298 */ 1299 function validate_api_key() 1300 { 1301 if($this->fetch_response("key=".$this->api_key."&blog=".urlencode($this->url), 'verify-key') == "valid") 1302 { 1303 return true; 1304 } 1305 1306 return false; 1307 } 1308 1309 /** 1310 * Formats the comment array to the Akismet API Standards 1311 * 1312 */ 1313 function format_post() 1314 { 1315 $format = array( 1316 'type' => 'comment_type', 1317 'username' => 'comment_author', 1318 'email' => 'comment_author_email', 1319 'website' => 'comment_author_url', 1320 'message' => 'comment_content', 1321 ); 1322 1323 // Basically we're assigning $long to the comment array if $short in the comment array, is not null 1324 foreach($format as $short => $long) 1325 { 1326 if(isset($this->post[$short])) 1327 { 1328 $this->post[$long] = $this->post[$short]; 1329 unset($this->post[$short]); 1330 } 1331 } 1332 } 1333 1334 /** 1335 * Builds a query string to work with Akismet 1336 * 1337 * @return string The built query string 1338 */ 1339 function build_query_string() 1340 { 1341 foreach($_SERVER as $key => $value) 1342 { 1343 if(in_array($key, $this->required)) 1344 { 1345 if($key == 'REMOTE_ADDR') 1346 { 1347 $this->post[$key] = $this->post['user_ip']; 1348 } 1349 else 1350 { 1351 $this->post[$key] = $value; 1352 } 1353 } 1354 } 1355 1356 1357 $query_string = ''; 1358 foreach($this->post as $key => $data) 1359 { 1360 $query_string .= $key.'='.urlencode(stripslashes($data)).'&'; 1361 } 1362 1363 return $query_string; 1364 } 1365 1366 /** 1367 * Connects to the Akismet server 1368 * 1369 * @return boolean True on success. 1370 */ 1371 function connect() 1372 { 1373 $this->connection = @fsockopen($this->host, 80); 1374 if(!$this->connection) 1375 { 1376 $this->set_error("server_not_found"); 1377 return false; 1378 } 1379 1380 return true; 1381 } 1382 1383 /** 1384 * Sends a request to the Akismet server 1385 * 1386 * @param string The request uri. 1387 * @param string The path to what is being checked (e.x. 'comment-spam'). 1388 * @return mixed The response on success, false otherwise. 1389 */ 1390 function fetch_response($request, $path) 1391 { 1392 $this->connect(); 1393 1394 if($this->connection == true && !$this->errors['server_not_found']) 1395 { 1396 if(!empty($this->api_key)) 1397 { 1398 $api_key = $this->api_key."."; 1399 } 1400 else 1401 { 1402 $api_key = ""; 1403 } 1404 1405 $http_request = "POST /{$this->version}/{$path} HTTP/1.1\r\n"; 1406 $http_request .= "Host: {$api_key}{$this->host}\r\n"; 1407 $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n"; 1408 $http_request .= "Content-Length: ".strlen($request)."\r\n"; 1409 $http_request .= "User-Agent: MyBB/1.4 | Akismet/1.1\r\n"; 1410 $http_request .= "Connection: close\r\n"; 1411 $http_request .= "\r\n"; 1412 $http_request .= $request; 1413 1414 @fwrite($this->connection, $http_request); 1415 1416 $http_response = ""; 1417 while(feof($this->connection) === false) 1418 { 1419 $http_response .= @fgets($this->connection, 1160); 1420 } 1421 1422 $http_response = explode("\r\n\r\n", $http_response, 2); 1423 return $http_response[1]; 1424 } 1425 else 1426 { 1427 $this->set_error("response_failed"); 1428 return false; 1429 } 1430 1431 $this->disconnect(); 1432 } 1433 1434 /** 1435 * Disconnects from the Akismet server 1436 * 1437 */ 1438 function disconnect() 1439 { 1440 @fclose($this->connection); 1441 } 1442 1443 /** 1444 * Append an error onto the error array 1445 * 1446 * @param string The error message. 1447 * @param int The error code of the error. 1448 * @return boolean Always true. 1449 */ 1450 function set_error($error_code) 1451 { 1452 switch($error_code) 1453 { 1454 case "server_not_found": 1455 $message = "Could not connect to Akismet server."; 1456 break; 1457 case "response_failed": 1458 $message = "There was a problem retrieving the response."; 1459 break; 1460 case "invalid_key": 1461 $message = "Your Akismet API key does not appear to be valid."; 1462 break; 1463 default: 1464 $message = "Unkown error."; 1465 break; 1466 } 1467 $this->errors[$error_code] = $message; 1468 1469 return true; 1470 } 1471 1472 /** 1473 * Check if a specified error exists with the error array 1474 * 1475 * @param int The error code 1476 * @return boolean True if error exists. 1477 */ 1478 function error_exists($error_code) 1479 { 1480 if(isset($this->errors[$error_code])) 1481 { 1482 return true; 1483 } 1484 1485 return false; 1486 } 1487 1488 /** 1489 * Checks if there are any errors stored in the error array 1490 * 1491 * @return boolean True if there errors. 1492 */ 1493 function errors_exist() 1494 { 1495 if(count($this->errors) > 0) 1496 { 1497 return true; 1498 } 1499 1500 return false; 1501 } 1502 } 1503 1504 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sun Dec 11 14:16:27 2011 | Cross-referenced by PHPXref 0.7.1 |