PageRenderTime 65ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/inc/class.MyBBIntegrator.php

https://bitbucket.org/Captain_Lightning/arflux
PHP | 3406 lines | 2107 code | 462 blank | 837 comment | 425 complexity | 0b93b9726a5e3f87e6110875d1acfc3c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * MyBBIntegrator - The integration class for MyBB and your website
  4. *
  5. * The MyBBIntegrator is a useful collection of variables and functions for easy MyBB integration
  6. * into the own website
  7. *
  8. * @author: David Olah (aka PHPDave - http://phpdave.com)
  9. * @version 1.3.1
  10. * @date July 2010
  11. * @copyright Copyright (c) 2009, David Olah
  12. *
  13. *
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation, either version 3 of the License, or
  18. * (at your option) any later version.
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. */
  26. class MyBBIntegrator
  27. {
  28. /**
  29. * Cache Handler of MyBB
  30. *
  31. * @var object
  32. */
  33. var $cache;
  34. /**
  35. * Config Data of MyBB
  36. *
  37. * @var array
  38. */
  39. var $config;
  40. /**
  41. * Database Handler of MyBB
  42. *
  43. * @var object
  44. */
  45. var $db;
  46. /**
  47. * MyBB Super Variable containing a whole lot of information
  48. *
  49. * @var object
  50. */
  51. var $mybb;
  52. /**
  53. * MyBB's Post Parser
  54. *
  55. * @var object
  56. */
  57. var $parser;
  58. /**
  59. * Shows a message for errors occuring in this class.
  60. * Afterwards it stops the script
  61. *
  62. * @param string $message The error message
  63. */
  64. function _errorAndDie($message)
  65. {
  66. echo '<div style="width:92%; margin:4px auto; border:1px #DDD solid; background:#F1F1F1; padding:5px; color:#C00; font-weight:bold;">An error occured during script run.<br />'.$message.'</div>';
  67. die;
  68. }
  69. /**
  70. * Let's see if the correct password is given for a forum!
  71. * Possible Todo: Pass passowrds in an array for defining passwords for parent categories (so far this only works when parent foums have same pass)
  72. *
  73. * @param integer $forum_id ID of Forum
  74. * @param string $password Wow, what might this be??
  75. * @return boolean
  76. */
  77. function checkForumPassword($forum_id, $password = '', $pid = 0)
  78. {
  79. global $forum_cache;
  80. if(!is_array($forum_cache))
  81. {
  82. $forum_cache = cache_forums();
  83. if(!$forum_cache)
  84. {
  85. return false;
  86. }
  87. }
  88. // Loop through each of parent forums to ensure we have a password for them too
  89. $parents = explode(',', $forum_cache[$fid]['parentlist']);
  90. rsort($parents);
  91. if(!empty($parents))
  92. {
  93. foreach($parents as $parent_id)
  94. {
  95. if($parent_id == $forum_id || $parent_id == $pid)
  96. {
  97. continue;
  98. }
  99. if($forum_cache[$parent_id]['password'] != "")
  100. {
  101. if (!$this->checkForumPassword($parent_id, $password))
  102. {
  103. return false;
  104. }
  105. }
  106. }
  107. }
  108. $forum_password = $forum_cache[$forum_id]['password'];
  109. // A password is required
  110. if ($forum_password)
  111. {
  112. if (empty($password))
  113. {
  114. if (!$this->mybb->cookies['forumpass'][$forum_id] || ($this->mybb->cookies['forumpass'][$forum_id] && md5($this->mybb->user['uid'].$forum_password) != $this->mybb->cookies['forumpass'][$forum_id]))
  115. {
  116. return false;
  117. }
  118. else
  119. {
  120. return true;
  121. }
  122. }
  123. else
  124. {
  125. if ($forum_password == $password)
  126. {
  127. $this->setCookie('forumpass['.$forum_id.']', md5($this->mybb->user['uid'].$password), NULL, true);
  128. return true;
  129. }
  130. else
  131. {
  132. return false;
  133. }
  134. }
  135. }
  136. else
  137. {
  138. return true;
  139. }
  140. }
  141. /**
  142. * Enables you to close one or more threads
  143. * One thread: $thread_id is int
  144. * More threads: $thread_id is array with ints
  145. *
  146. * @param integer|array $thread_id See above
  147. * @param integer $forum_id This can be filled for a nice moderator log!
  148. * @return boolean
  149. */
  150. function closeThread($thread_id, $forum_id = 0)
  151. {
  152. if (!is_moderator($fid, "canopenclosethreads"))
  153. {
  154. return false;
  155. }
  156. $this->lang->load('moderation');
  157. $this->MyBBIntegratorClassObject('moderation', 'Moderation', MYBB_ROOT.'/inc/class_moderation.php');
  158. $this->moderation->close_threads($thread_id);
  159. $modlogdata['fid'] = $forum_id;
  160. $this->logModeratorAction($modlogdata, $this->lang->mod_process);
  161. return true;
  162. }
  163. /**
  164. * Insert a new Category into Database
  165. *
  166. * @param array $data Array with keys according to database layout, which holds the data of the forum
  167. * @param array $permissions Array with Permission entries (structure: array( 'canview' => array( 'usergroupid' => 1 ) )) (an example)
  168. * @param array $default_permissions Array which defines, if default permissions shall be used (structure: array( usergroupid => 0 / 1 )
  169. * Can be left empty, then this function will take care of it
  170. * @return $data with more values, like fid and parentlist
  171. */
  172. function createCategory($data, $permissions = array(), $default_permissions = array())
  173. {
  174. require_once MYBB_ADMIN_DIR.'inc/functions.php';
  175. if (!isset($data['name']))
  176. {
  177. $this->_errorAndDie('A new forum needs to have a name and a type');
  178. }
  179. $data['type'] = 'c';
  180. // Let's leave the parentlist creation to the script and let's not trust the dev :)
  181. if ($data['parentlist'] != '')
  182. {
  183. $data['parentlist'] = '';
  184. }
  185. // If there is no defined Parent ID, parent ID will be set to 0
  186. if (!isset($data['pid']) || $data['pid'] < 0)
  187. {
  188. $data['pid'] = 0;
  189. }
  190. else
  191. {
  192. $data['pid'] = intval($data['pid']);
  193. }
  194. if (!empty($permissions))
  195. {
  196. if (
  197. (!isset($permissions['canview']) || empty($permissions['canview'])) ||
  198. (!isset($permissions['canpostthreads']) || empty($permissions['canpostthreads'])) ||
  199. (!isset($permissions['canpostreplys']) || empty($permissions['canpostreplys'])) ||
  200. (!isset($permissions['canpostpolls']) || empty($permissions['canpostpolls'])) ||
  201. (!isset($permissions['canpostattachments']) || empty($permissions['canpostattachments']))
  202. )
  203. {
  204. $this->_errorAndDie('The $permissions Parameter does not have the correct format. It requires following keys: <i>canview, canpostthreads, canpostreplys, canpostpolls and canpostattachments</i>');
  205. }
  206. /**
  207. * If no default permissions are given, we will initiate them, default: yes
  208. * Since there is the possibility of additional usergroups, we will get the usergroups from the permissions array!
  209. * The structure of the inherit array is: keys = groupid
  210. * If the value of an inherit array item is 1, this means that the default_permissions shall be used
  211. */
  212. if (empty($default_permissions))
  213. {
  214. foreach ($permissions['canview'] as $gid)
  215. {
  216. $default_permissions[$gid] = 1;
  217. }
  218. }
  219. }
  220. $data['fid'] = $this->db->insert_query("forums", $data);
  221. $data['parentlist'] = make_parent_list($data['fid']);
  222. $this->db->update_query("forums", array("parentlist" => $data['parentlist']), 'fid=\''.$data['fid'].'\'');
  223. $this->cache->update_forums();
  224. if (!empty($permissions))
  225. {
  226. $inherit = $default_permissions;
  227. /**
  228. * $permissions['canview'][1] = 1 OR $permissions['canview'][1] = 0
  229. * --> $permissions[$name][$gid] = yes / no
  230. */
  231. $canview = $permissions['canview'];
  232. $canpostthreads = $permissions['canpostthreads'];
  233. $canpostpolls = $permissions['canpostpolls'];
  234. $canpostattachments = $permissions['canpostattachments'];
  235. $canpostreplies = $permissions['canpostreplys'];
  236. save_quick_perms($data['fid']);
  237. }
  238. return $data;
  239. }
  240. /**
  241. * Insert a new Forum into Database
  242. *
  243. * @param array $data Array with keys according to database layout, which holds the data of the forum
  244. * @param array $permissions Array with Permission entries (structure: array( 'canview' => array( 'usergroupid' => 1 ) )) (an example)
  245. * @param array $default_permissions Array which defines, if default permissions shall be used (structure: array( usergroupid => 0 / 1 )
  246. * Can be left empty, then this function will take care of it
  247. * @return $data with more values, like fid and parentlist
  248. */
  249. function createForum($data, $permissions = array(), $default_permissions = array())
  250. {
  251. require_once MYBB_ADMIN_DIR.'inc/functions.php';
  252. if (!isset($data['name']))
  253. {
  254. $this->_errorAndDie('A new forum needs to have a name and a type');
  255. }
  256. $data['type'] = 'f';
  257. // Let's leave the parentlist creation to the script and let's not trust the dev :)
  258. if ($data['parentlist'] != '')
  259. {
  260. $data['parentlist'] = '';
  261. }
  262. // If there is no defined Parent ID, parent ID will be set to 0
  263. if (!isset($data['pid']) || $data['pid'] < 0)
  264. {
  265. $data['pid'] = 0;
  266. }
  267. else
  268. {
  269. $data['pid'] = intval($data['pid']);
  270. }
  271. if (!empty($permissions))
  272. {
  273. if (
  274. (!isset($permissions['canview']) || empty($permissions['canview'])) ||
  275. (!isset($permissions['canpostthreads']) || empty($permissions['canpostthreads'])) ||
  276. (!isset($permissions['canpostreplys']) || empty($permissions['canpostreplys'])) ||
  277. (!isset($permissions['canpostpolls']) || empty($permissions['canpostpolls'])) ||
  278. (!isset($permissions['canpostattachments']) || empty($permissions['canpostattachments']))
  279. )
  280. {
  281. $this->_errorAndDie('The $permissions Parameter does not have the correct format. It requires following keys: <i>canview, canpostthreads, canpostreplys, canpostpolls and canpostattachments</i>');
  282. }
  283. /**
  284. * If no default permissions are given, we will initiate them, default: yes
  285. * Since there is the possibility of additional usergroups, we will get the usergroups from the permissions array!
  286. * The structure of the inherit array is: keys = groupid
  287. * If the value of an inherit array item is 1, this means that the default_permissions shall be used
  288. */
  289. if (empty($default_permissions))
  290. {
  291. foreach ($permissions['canview'] as $gid)
  292. {
  293. $default_permissions[$gid] = 1;
  294. }
  295. }
  296. }
  297. $data['fid'] = $this->db->insert_query("forums", $data);
  298. $data['parentlist'] = make_parent_list($data['fid']);
  299. $this->db->update_query("forums", array("parentlist" => $data['parentlist']), 'fid=\''.$data['fid'].'\'');
  300. $this->cache->update_forums();
  301. if (!empty($permissions))
  302. {
  303. $inherit = $default_permissions;
  304. /**
  305. * $permissions['canview'][1] = 1 OR $permissions['canview'][1] = 0
  306. * --> $permissions[$name][$gid] = yes / no
  307. */
  308. $canview = $permissions['canview'];
  309. $canpostthreads = $permissions['canpostthreads'];
  310. $canpostpolls = $permissions['canpostpolls'];
  311. $canpostattachments = $permissions['canpostattachments'];
  312. $canpostreplies = $permissions['canpostreplys'];
  313. save_quick_perms($data['fid']);
  314. }
  315. return $data;
  316. }
  317. /**
  318. * Create a new poll and assign it to a thread
  319. * Taken frm polls.php
  320. *
  321. * @param integer $thread_id ID of Thread where the poll should be assigned to
  322. * @param array $data The Data
  323. */
  324. function createPoll($thread_id, $data)
  325. {
  326. // Required keys in data array: options, question
  327. if (!isset($data['options']) || !isset($data['question']))
  328. {
  329. $this->_errorAndDie('One or more required array keys in parameter <i>$data</i> missing. Required keys are: <i>options</i>, <i>question</i>');
  330. }
  331. $this->lang->load('polls');
  332. $this->plugins->run_hooks("polls_do_newpoll_start");
  333. $query = $this->db->simple_select("threads", "*", "tid='".(int) $thread_id."'");
  334. $thread = $this->db->fetch_array($query);
  335. $fid = $thread['fid'];
  336. $forumpermissions = forum_permissions($fid);
  337. if (!$thread['tid'])
  338. {
  339. return $this->lang->error_invalidthread;
  340. }
  341. // No permission if: Not thread author; not moderator; no forum perms to view, post threads, post polls
  342. if (($thread['uid'] != $this->mybb->user['uid'] && !is_moderator($fid)) || ($forumpermissions['canview'] == 0 || $forumpermissions['canpostthreads'] == 0 || $forumpermissions['canpostpolls'] == 0))
  343. {
  344. return false;
  345. }
  346. if ($thread['poll'])
  347. {
  348. return $this->lang->error_pollalready;
  349. }
  350. $polloptions = count($data['options']);
  351. if($this->mybb->settings['maxpolloptions'] && $polloptions > $this->mybb->settings['maxpolloptions'])
  352. {
  353. $polloptions = $this->mybb->settings['maxpolloptions'];
  354. }
  355. if (!isset($data['postoptions']))
  356. {
  357. $data['postoptions'] = array('multiple', 'public');
  358. }
  359. $postoptions = $data['postoptions'];
  360. if ($postoptions['multiple'] != '1')
  361. {
  362. $postoptions['multiple'] = 0;
  363. }
  364. if ($postoptions['public'] != '1')
  365. {
  366. $postoptions['public'] = 0;
  367. }
  368. if ($polloptions < 2)
  369. {
  370. $polloptions = "2";
  371. }
  372. $optioncount = "0";
  373. $options = $data['options'];
  374. for($i = 0; $i < $polloptions; ++$i)
  375. {
  376. if (trim($options[$i]) != "")
  377. {
  378. $optioncount++;
  379. }
  380. if (my_strlen($options[$i]) > $this->mybb->settings['polloptionlimit'] && $this->mybb->settings['polloptionlimit'] != 0)
  381. {
  382. $lengtherror = 1;
  383. break;
  384. }
  385. }
  386. if ($lengtherror)
  387. {
  388. return $this->lang->error_polloptiontoolong;
  389. }
  390. if (empty($data['question']) || $optioncount < 2)
  391. {
  392. return $this->lang->error_noquestionoptions;
  393. }
  394. $optionslist = '';
  395. $voteslist = '';
  396. for($i = 0; $i < $optioncount; ++$i)
  397. {
  398. if(trim($options[$i]) != '')
  399. {
  400. if($i > 0)
  401. {
  402. $optionslist .= '||~|~||';
  403. $voteslist .= '||~|~||';
  404. }
  405. $optionslist .= $options[$i];
  406. $voteslist .= '0';
  407. }
  408. }
  409. if (!isset($data['timeout']))
  410. {
  411. $data['timeout'] = 0;
  412. }
  413. if($data['timeout'] > 0)
  414. {
  415. $timeout = intval($data['timeout']);
  416. }
  417. else
  418. {
  419. $timeout = 0;
  420. }
  421. $newpoll = array(
  422. "tid" => $thread['tid'],
  423. "question" => $this->db->escape_string($data['question']),
  424. "dateline" => TIME_NOW,
  425. "options" => $this->db->escape_string($optionslist),
  426. "votes" => $this->db->escape_string($voteslist),
  427. "numoptions" => intval($optioncount),
  428. "numvotes" => 0,
  429. "timeout" => $timeout,
  430. "closed" => 0,
  431. "multiple" => $postoptions['multiple'],
  432. "public" => $postoptions['public']
  433. );
  434. $this->plugins->run_hooks("polls_do_newpoll_process");
  435. $pid = $this->db->insert_query("polls", $newpoll);
  436. $this->db->update_query("threads", array('poll' => $pid), "tid='".$thread['tid']."'");
  437. $this->plugins->run_hooks("polls_do_newpoll_end");
  438. return true;
  439. }
  440. /**
  441. * Insert a new post into Database
  442. *
  443. * @param array $data Post Data
  444. * @return array|string When true it will return an array with postID and status of being visible - false = error array or inline string
  445. */
  446. function createPost($data, $inline_errors = true)
  447. {
  448. require_once MYBB_ROOT.'inc/functions_post.php';
  449. require_once MYBB_ROOT.'/inc/datahandlers/post.php';
  450. $posthandler = new PostDataHandler('insert');
  451. $this->plugins->run_hooks('newreply_do_newreply_start');
  452. $posthandler->set_data($data);
  453. if (!$posthandler->validate_post())
  454. {
  455. $errors = $posthandler->get_friendly_errors();
  456. return ($inline_errors === true) ? inline_error($errors) : $errors;
  457. }
  458. $this->plugins->run_hooks('newreply_do_newreply_end');
  459. return $posthandler->insert_post();
  460. }
  461. /**
  462. * Inserts a thread into the database
  463. *
  464. * @param array $data Thread data
  465. * @param boolean $inline_errors Defines if we want a formatted error string or an array
  466. * @return array|string
  467. * @return array|string When true it will return an array with threadID, postID and status of being visible - false = error array or inline string
  468. */
  469. function createThread($data, $inline_errors = true)
  470. {
  471. require_once MYBB_ROOT.'inc/functions_post.php';
  472. require_once MYBB_ROOT.'/inc/datahandlers/post.php';
  473. $posthandler = new PostDataHandler('insert');
  474. $posthandler->action = 'thread';
  475. $posthandler->set_data($data);
  476. if (!$posthandler->validate_thread())
  477. {
  478. $errors = $posthandler->get_friendly_errors();
  479. return ($inline_errors === true) ? inline_error($errors) : $errors;
  480. }
  481. return $posthandler->insert_thread();
  482. }
  483. /**
  484. * Insert a new user into Database
  485. *
  486. * @param array $data User data
  487. * @param boolean $inline_errors Defines if we want a formatted error string or an array
  488. * @return array|string When true it will return an array with some user data - false = error array or inline string
  489. */
  490. function createUser($data, $inline_errors = true)
  491. {
  492. require_once MYBB_ROOT.'inc/functions_user.php';
  493. require_once MYBB_ROOT.'/inc/datahandlers/user.php';
  494. $userhandler = new UserDataHandler('insert');
  495. $this->plugins->run_hooks('admin_user_users_add');
  496. $userhandler->set_data($data);
  497. if (!$userhandler->validate_user())
  498. {
  499. $errors = $userhandler->get_friendly_errors();
  500. return ($inline_errors === true) ? inline_error($errors) : $errors;
  501. }
  502. $this->plugins->run_hooks('admin_user_users_add_commit');
  503. return $userhandler->insert_user();
  504. }
  505. /**
  506. * Escapes a value for DB usage
  507. *
  508. * @param mixed $value Any value to use with the database
  509. * @return string
  510. */
  511. function dbEscape($value)
  512. {
  513. return $this->db->escape_string($value);
  514. }
  515. /**
  516. * Remove a poll
  517. * Taken from moderation.php
  518. *
  519. * @param integer $poll_id ID of Poll to be deleted
  520. * @return boolean|string
  521. */
  522. function deletePoll($poll_id)
  523. {
  524. $this->lang->load('moderation');
  525. $this->MyBBIntegratorClassObject('moderation', 'Moderation', MYBB_ROOT.'/inc/class_moderation.php');
  526. $query = $this->db->simple_select("polls", "*", "pid='$poll_id'");
  527. $poll = $this->db->fetch_array($query);
  528. if(!$poll['pid'])
  529. {
  530. return $this->lang->error_invalidpoll;
  531. }
  532. $thread = $this->getThread($poll['tid']);
  533. if(!is_moderator($thread['fid'], "candeleteposts"))
  534. {
  535. if($permissions['candeletethreads'] != 1 || $this->mybb->user['uid'] != $thread['uid'])
  536. {
  537. return false;
  538. }
  539. }
  540. $modlogdata = array();
  541. $modlogdata['tid'] = $poll['tid'];
  542. $this->plugins->run_hooks("moderation_do_deletepoll");
  543. $this->lang->poll_deleted = $this->lang->sprintf($this->lang->poll_deleted, $thread['subject']);
  544. $this->logModeratorAction($modlogdata, $this->lang->poll_deleted);
  545. $this->moderation->delete_poll($poll['pid']);
  546. return true;
  547. }
  548. /**
  549. * Delete the poll of a thread
  550. * Taken from moderation.php
  551. *
  552. * @param integer $thread_id Thread-ID where the poll is located
  553. * @return boolean|string
  554. */
  555. function deletePollOfThread($thread_id)
  556. {
  557. $this->lang->load('polls');
  558. $this->lang->load('moderation');
  559. $this->MyBBIntegratorClassObject('moderation', 'Moderation', MYBB_ROOT.'/inc/class_moderation.php');
  560. $thread = $this->getThread($thread_id);
  561. $permissions = forum_permissions($thread['fid']);
  562. if (!is_moderator($thread['fid'], "candeleteposts"))
  563. {
  564. if($permissions['candeletethreads'] != 1 || $this->mybb->user['uid'] != $thread['uid'])
  565. {
  566. return false;
  567. }
  568. }
  569. $query = $this->db->simple_select("polls", "*", "tid='$thread_id'");
  570. $poll = $this->db->fetch_array($query);
  571. if(!$poll['pid'])
  572. {
  573. return $this->lang->error_invalidpoll;
  574. }
  575. $modlogdata = array();
  576. $modlogdata['tid'] = $poll['tid'];
  577. $this->plugins->run_hooks("moderation_do_deletepoll");
  578. $this->lang->poll_deleted = $this->lang->sprintf($this->lang->poll_deleted, $thread['subject']);
  579. $this->logModeratorAction($modlogdata, $this->lang->poll_deleted);
  580. $this->moderation->delete_poll($poll['pid']);
  581. return true;
  582. }
  583. /**
  584. * Flag private messages as deleted
  585. *
  586. * @param integer|array $pm_id ID(s) of Private Messages (many IDs require an array)
  587. */
  588. function deletePrivateMessage($pm_id)
  589. {
  590. require_once MYBB_ROOT.'inc/functions_user.php';
  591. $this->plugins->run_hooks('private_delete_start');
  592. $data = array(
  593. 'folder' => 4,
  594. 'deletetime' => TIME_NOW
  595. );
  596. if (is_array($pm_id))
  597. {
  598. $this->db->update_query('privatemessages', $data, 'pmid IN ('.implode(',', array_map('intval', $pm_id)).')');
  599. }
  600. else
  601. {
  602. $this->db->update_query('privatemessages', $data, 'pmid = '.intval($pm_id));
  603. }
  604. update_pm_count();
  605. $this->plugins->run_hooks('private_delete_end');
  606. }
  607. /**
  608. * Flag all private messages of a user as deleted
  609. * It is also possible to flag pms as deleted of multiple users, when paramater is an array with IDs
  610. *
  611. * @param integer|array $pm_id ID(s) of User IDs (many IDs require an array)
  612. */
  613. function deletePrivateMessagesOfUser($user_id)
  614. {
  615. require_once MYBB_ROOT.'inc/functions_user.php';
  616. $this->plugins->run_hooks('private_delete_start');
  617. $data = array(
  618. 'folder' => 4,
  619. 'deletetime' => TIME_NOW
  620. );
  621. if (is_array($user_id))
  622. {
  623. $this->db->update_query('privatemessages', $data, 'uid IN ('.implode(',', array_map('intval', $user_id)).')');
  624. }
  625. else
  626. {
  627. $this->db->update_query('privatemessages', $data, 'uid = '.intval($user_id));
  628. }
  629. update_pm_count();
  630. $this->plugins->run_hooks('private_delete_end');
  631. }
  632. /**
  633. * Generates a Captcha
  634. *
  635. * @return array
  636. */
  637. function generateCaptcha()
  638. {
  639. $randomstr = random_str(5);
  640. $imagehash = md5(random_str(12));
  641. $imagearray = array(
  642. "imagehash" => $imagehash,
  643. "imagestring" => $randomstr,
  644. "dateline" => TIME_NOW
  645. );
  646. $this->db->insert_query("captcha", $imagearray);
  647. return array_merge($imagearray, array(
  648. 'captcha' => '<img src="'.$this->mybb->settings['bburl'].'/captcha.php?imagehash='.$imagehash.'" />'
  649. ));
  650. }
  651. /**
  652. * Generates a posthash
  653. *
  654. * @param integer $user_id User-ID
  655. * @return string MD5
  656. */
  657. function generatePosthash($user_id = 0)
  658. {
  659. mt_srand((double) microtime() * 1000000);
  660. if ($user_id == 0)
  661. {
  662. return md5($this->mybb->user['uid'].mt_rand());
  663. }
  664. else
  665. {
  666. return md5($user_id.mt_rand());
  667. }
  668. }
  669. /**
  670. * Get the Hottest Threads within a defined timespan
  671. *
  672. * @param integer $timespan The timespan you want to use for fetching the hottest topics (in seconds)
  673. * @param string $post_sort_order Sort Order to the posts you are fetching (ordered by the dateline)
  674. * @param string $postamount_sort_order Sort order of the threads (ordered by the amount of posts)
  675. * @return array
  676. */
  677. function getBusyThreadsWithinTimespan($timespan = 86400, $post_sort_order = 'DESC', $postamount_sort_order = 'DESC')
  678. {
  679. $threads = array();
  680. // Make sure the parameters have correct values
  681. $post_sort_order = ($post_sort_order == 'DESC') ? 'DESC' : 'ASC';
  682. $postamount_sort_order = ($postamount_sort_order == 'DESC') ? 'DESC' : 'ASC';
  683. $query = $this->db->query('
  684. SELECT p.`pid`, p.`message`, p.`uid` as postuid, p.`username` as postusername, p.`dateline`,
  685. t.`tid`, t.`fid`, t.`subject`, t.`uid` as threaduid, t.`username` as threadusername, t.`lastpost`, t.`lastposter`, t.`lastposteruid`, t.`views`, t.`replies`
  686. FROM '.TABLE_PREFIX.'posts p
  687. INNER JOIN '.TABLE_PREFIX.'threads t ON t.`tid` = p.`tid`
  688. WHERE p.`dateline` >= '.(TIME_NOW - $timespan).'
  689. ORDER BY p.`dateline` '.$post_sort_order.'
  690. ');
  691. while ($post = $this->db->fetch_array($query))
  692. {
  693. /**
  694. * The return array we are building is being filled with the thread itself, but also with the posts
  695. * We will later increase the Postamount, so we can sort it
  696. */
  697. if (!isset($threads[$post['tid']]))
  698. {
  699. $threads[$post['tid']] = array(
  700. 'tid' => $post['tid'],
  701. 'fid' => $post['fid'],
  702. 'subject' => $post['subject'],
  703. 'uid' => $post['threaduid'],
  704. 'username' => $post['threadusername'],
  705. 'lastpost' => $post['lastpost'],
  706. 'lastposter' => $post['lastposter'],
  707. 'lastposteruid' => $post['lastposteruid'],
  708. 'views' => $post['views'],
  709. 'replies' => $post['replies'],
  710. 'postamount' => 1,
  711. 'posts' => array()
  712. );
  713. // The first run of one thread also brings a post, so we assign this post
  714. $threads[$post['tid']]['posts'][] = array(
  715. 'pid' => $post['pid'],
  716. 'message' => $post['message'],
  717. 'uid' => $post['postuid'],
  718. 'username' => $post['postusername'],
  719. 'dateline' => $post['dateline']
  720. );
  721. }
  722. else
  723. {
  724. // The thread array key exists already, so we increment the postamount and save another post
  725. $threads[$post['tid']]['postamount']++;
  726. $threads[$post['tid']]['posts'][] = array(
  727. 'pid' => $post['pid'],
  728. 'message' => $post['message'],
  729. 'uid' => $post['postuid'],
  730. 'username' => $post['postusername'],
  731. 'dateline' => $post['dateline']
  732. );
  733. }
  734. }
  735. // Sort function for ascending posts
  736. function arraySortByPostamountASC($item1, $item2)
  737. {
  738. if ($item1['postamount'] == $item2['postamount'])
  739. {
  740. return 0;
  741. }
  742. if ($item1['postamount'] > $item2['postamount'])
  743. {
  744. return 1;
  745. }
  746. else
  747. {
  748. return -1;
  749. }
  750. }
  751. // Sort function for descending posts
  752. function arraySortByPostamountDESC($item1, $item2)
  753. {
  754. if ($item1['postamount'] == $item2['postamount'])
  755. {
  756. return 0;
  757. }
  758. if ($item1['postamount'] > $item2['postamount'])
  759. {
  760. return -1;
  761. }
  762. else
  763. {
  764. return 1;
  765. }
  766. }
  767. // Let's sort the threads now
  768. usort($threads, 'arraySortByPostamount'.$postamount_sort_order);
  769. return $threads;
  770. }
  771. /**
  772. * Returns data of a specified forum
  773. * Refers to: inc/functions.php
  774. *
  775. * @param integer $forum_id ID of forum to fetch data from
  776. * @param integer $active_override If set to 1, will override the active forum status
  777. * @return array|boolean If unsuccessful, it returns false - Otherwise the Database row
  778. */
  779. function getForum($forum_id, $active_override = 0)
  780. {
  781. $forum = get_forum($forum_id, $active_override);
  782. // Do we have permission?
  783. $forumpermissions = forum_permissions($forum['fid']);
  784. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  785. {
  786. // error_no_permission();
  787. return false;
  788. }
  789. else
  790. {
  791. return $forum;
  792. }
  793. }
  794. /**
  795. * Return members of the board with administrative function
  796. * Taken from /showteam.php
  797. *
  798. * @return array
  799. */
  800. function getForumStaff()
  801. {
  802. $this->lang->load('showteam');
  803. $usergroups = array();
  804. $moderators = array();
  805. $users = array();
  806. // Fetch the list of groups which are to be shown on the page
  807. $query = $this->db->simple_select("usergroups", "gid, title, usertitle", "showforumteam=1", array('order_by' => 'disporder'));
  808. while($usergroup = $this->db->fetch_array($query))
  809. {
  810. $usergroups[$usergroup['gid']] = $usergroup;
  811. }
  812. if (empty($usergroups))
  813. {
  814. return $this->lang->error_noteamstoshow;
  815. }
  816. // Fetch specific forum moderator details
  817. if ($usergroups[6]['gid'])
  818. {
  819. $query = $this->db->query("
  820. SELECT m.*, f.name
  821. FROM ".TABLE_PREFIX."moderators m
  822. LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=m.uid)
  823. LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=m.fid)
  824. WHERE f.active = 1
  825. ORDER BY u.username
  826. ");
  827. while($moderator = $this->db->fetch_array($query))
  828. {
  829. $moderators[$moderator['uid']][] = $moderator;
  830. }
  831. }
  832. // Now query the users of those specific groups
  833. $groups_in = implode(",", array_keys($usergroups));
  834. $users_in = implode(",", array_keys($moderators));
  835. if (!$groups_in)
  836. {
  837. $groups_in = 0;
  838. }
  839. if (!$users_in)
  840. {
  841. $users_in = 0;
  842. }
  843. $forum_permissions = forum_permissions();
  844. $query = $this->db->simple_select("users", "uid, username, displaygroup, usergroup, ignorelist, hideemail, receivepms", "displaygroup IN ($groups_in) OR (displaygroup='0' AND usergroup IN ($groups_in)) OR uid IN ($users_in)", array('order_by' => 'username'));
  845. while ($user = $this->db->fetch_array($query))
  846. {
  847. // If this user is a moderator
  848. if (isset($moderators[$user['uid']]))
  849. {
  850. foreach ($moderators[$user['uid']] as $forum)
  851. {
  852. if ($forum_permissions[$forum['fid']]['canview'] == 1)
  853. {
  854. $forum_url = get_forum_link($forum['fid']);
  855. }
  856. }
  857. $usergroups[6]['user_list'][$user['uid']] = $user;
  858. }
  859. if ($user['displaygroup'] == '6' || $user['usergroup'] == '6')
  860. {
  861. $usergroups[6]['user_list'][$user['uid']] = $user;
  862. }
  863. // Are they also in another group which is being shown on the list?
  864. if ($user['displaygroup'] != 0)
  865. {
  866. $group = $user['displaygroup'];
  867. }
  868. else
  869. {
  870. $group = $user['usergroup'];
  871. }
  872. if ($usergroups[$group] && $group != 6)
  873. {
  874. $usergroups[$group]['user_list'][$user['uid']] = $user;
  875. }
  876. }
  877. return $usergroups;
  878. }
  879. /**
  880. * Return the latest threads of one forum, where a post has been posted
  881. *
  882. * @param integer $forum_id Forum ID to fetch threads from
  883. * @param integer $limit Amount of threads to get
  884. * @param boolean $excluse_invisible Shall we also get invisible threads?
  885. * @return array
  886. */
  887. function getLatestActiveThreads($forum_id = 0, $limit = 7, $exclude_invisible = true)
  888. {
  889. if ($forum_id == 0)
  890. {
  891. $this->_errorAndDie('Specified forum ID cannot be 0!');
  892. }
  893. else
  894. {
  895. // Do we have permission?
  896. $forumpermissions = forum_permissions($forum_id);
  897. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  898. {
  899. // error_no_permission();
  900. return false;
  901. }
  902. }
  903. // This will be the array, where we can save the threads
  904. $threads = array();
  905. // We want to get a list of threads, starting with the newest one
  906. $query_params = array(
  907. 'order_by' => 'lastpost',
  908. 'order_dir' => 'DESC',
  909. 'limit' => intval($limit)
  910. );
  911. /**
  912. * If defined forum id is 0, we do not fetch threads from only one forum,
  913. * but we fetch the latest threads of all forums
  914. * Therefore we add the forum_id in the where condition
  915. * We only fetch visible threads, if there is anything we want to hide ;)
  916. * However we can also define that we want the invisible threads as well
  917. */
  918. $fetch_invisible_threads = ($exclude_invisible == true) ? '1' : '0';
  919. $condition = ($forum_id != 0) ? ' `visible` = '.$fetch_invisible_threads.' AND `fid` = '.intval($forum_id) : '';
  920. // Run the Query
  921. $query = $this->db->simple_select('threads', '*', $condition, $query_params);
  922. // Now let's iterate through the fetched threads to create the return array
  923. while ($thread = $this->db->fetch_array($query))
  924. {
  925. $threads[] = $thread;
  926. }
  927. return $threads;
  928. }
  929. /**
  930. * Return newly created threads, regardless of replies
  931. *
  932. * @param integer|array $forum_id Forum ID / Forum IDs to fetch threads from
  933. * @param string $fields Name of fields if you want to fetch specific fields
  934. * @param integer $limit Amount of threads to get
  935. * @param boolean $excluse_invisible Shall we also get invisible threads?
  936. * @param boolean $join_forums Shall we also get the information from the forums where the threads are located in?
  937. * @param boolean $join_first_post Shall we get the first post of this thread as well?
  938. * @return array
  939. */
  940. function getLatestThreads($forum_id = 0, $fields = '*', $limit = 7, $exclude_invisible = true, $join_forums = true, $join_first_post = true)
  941. {
  942. if ($forum_id != 0)
  943. {
  944. // If we have multiple values, we have to check permission for each forum!
  945. if (is_array($forum_id))
  946. {
  947. foreach ($forum_id as $single_forum_id)
  948. {
  949. $forum_permissions = forum_permissions($single_forum_id);
  950. if ($forum_permissions['canview'] != 1 || $forum_permissions['canviewthreads'] != 1)
  951. {
  952. // error_no_permission();
  953. return false;
  954. }
  955. }
  956. }
  957. else
  958. {
  959. // Do we have permission?
  960. $forumpermissions = forum_permissions($forum_id);
  961. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  962. {
  963. // error_no_permission();
  964. return false;
  965. }
  966. }
  967. }
  968. // This is what we will be returning
  969. $threads = array();
  970. // Do we want to get invisible threads as well?
  971. $fetch_invisible_threads = ($exclude_invisible == true) ? '1' : '0';
  972. $condition = 't.`visible` = '.$fetch_invisible_threads;
  973. // Are we fetching threads from multiple forums?
  974. if (is_array($forum_id) || is_object($forum_id))
  975. {
  976. $condition .= ' AND t.`fid` IN ('.implode(', ', $forum_id).')';
  977. }
  978. // Or are we just fetching threads from one forum?
  979. else
  980. {
  981. $condition .= ($forum_id == 0) ? '' : ' AND t.`fid` = '.$forum_id;
  982. }
  983. // Do we want to get information of the forum where the thread is located in?
  984. $forum_join = ($join_forums == true) ? 'INNER JOIN '.TABLE_PREFIX.'forums f ON f.`fid` = t.`fid`' : '';
  985. // Do we want to get the first post from the thread?
  986. $first_post_join = ($join_first_post == true) ? 'INNER JOIN '.TABLE_PREFIX.'posts p ON p.`pid` = t.`firstpost`' : '';
  987. // Run the Query
  988. $query = $this->db->query('
  989. SELECT '.$fields.'
  990. FROM '.TABLE_PREFIX.'threads t
  991. '.$forum_join.'
  992. '.$first_post_join.'
  993. WHERE '.$condition.'
  994. ORDER BY t.`dateline` DESC
  995. LIMIT '.intval($limit).'
  996. ');
  997. // Iterate through the results and assign it to our returning array
  998. while ($thread = $this->db->fetch_array($query))
  999. {
  1000. $threads[] = $thread;
  1001. }
  1002. return $threads;
  1003. }
  1004. /**
  1005. * Return recently posted posts
  1006. *
  1007. * @param integer|array Either a single Thread ID or an array containing thread IDs
  1008. * @param string Fields, which shall be fetched from the posts table
  1009. * @param integer How many posts shall be fetched?
  1010. * @param boolean Shall we also return invisible ones?
  1011. * @return array
  1012. */
  1013. function getLatestPosts($thread_id = 0, $fields = '*', $limit = 7, $exclude_invisible = true)
  1014. {
  1015. // Posts will be stored in this array
  1016. $posts = array();
  1017. // Posts will be returned in descending order, starting with the newest
  1018. $query_params = array(
  1019. 'order_by' => 'dateline',
  1020. 'order_dir' => 'DESC',
  1021. 'limit' => intval($limit)
  1022. );
  1023. // We want to fetch posts from multiple threads
  1024. if (is_array($thread_id) || is_object($thread_id))
  1025. {
  1026. // Multiple threads = IN (...) Operator
  1027. $condition = '`fid` IN ('.implode(', ', $thread_id).')';
  1028. }
  1029. else
  1030. {
  1031. // Single thread = normal WHERE X = Y - if set 0 we fetch posts from all threads
  1032. $condition = ($thread_id == 0) ? '1 = 1' : '`fid` = '.intval($thread_id);
  1033. }
  1034. /**
  1035. * If defined forum id is 0, we do not fetch threads from only one forum,
  1036. * but we fetch the latest threads of all forums
  1037. * Therefore we add the forum_id in the where condition
  1038. * We only fetch visible threads, if there is anything we want to hide ;)
  1039. * However we can also define that we want the invisible threads as well
  1040. */
  1041. $fetch_invisible_threads = ($exclude_invisible == true) ? '1' : '0';
  1042. $condition .= ' AND `visible` = '.$fetch_invisible_threads;
  1043. // Run the Query
  1044. $query = $this->db->simple_select('posts', $fields, $condition, $query_params);
  1045. // Now let's iterate through the fetched posts to create the return array
  1046. while ($post = $this->db->fetch_array($query))
  1047. {
  1048. $posts[] = $post;
  1049. }
  1050. return $posts;
  1051. }
  1052. /**
  1053. * Retrieve member list
  1054. * Ideal to offer a multi-page member list
  1055. *
  1056. * @param array $data Contains data affecting the member query - List of Array keys below
  1057. * - orderby: What table column will the member list be sorted by?
  1058. * - orderdir: Ascending or Descending order direction
  1059. * - perpage: Amount of members to fetch (set 0 for all members)
  1060. * - letter: Beginning character of member name
  1061. * - username: Searching for a matching username
  1062. * - username_match: Set this to "begins" when username shall being with given token - otherwise it goes or "contains"
  1063. * - website: String contained in website
  1064. * - aim: Search for an AIM
  1065. * - icq: Search for an ICQ number
  1066. * - msn: Search for a MSN ID
  1067. * - yahoo: Search for a Yahoo ID
  1068. * - page: Which page of the list will we be retrieving
  1069. * @return array
  1070. */
  1071. function getMembers($data = array())
  1072. {
  1073. /**
  1074. * Make sure we have initial values in the data array
  1075. */
  1076. $data['orderby'] = (!isset($data['orderby'])) ? 'u.`username`' : $data['orderby'];
  1077. $data['orderdir'] = (!isset($data['orderdir'])) ? 'ASC' : strtoupper($data['orderdir']);
  1078. $data['orderdir'] = ($data['orderdir'] == 'ASC') ? 'ASC' : 'DESC';
  1079. $data['perpage'] = (!isset($data['perpage'])) ? (int) $this->mybb->settings['membersperpage'] : (int) $data['perpage'];
  1080. $data['letter'] = (!isset($data['letter'])) ? '' : $data['letter'];
  1081. $data['username'] = (!isset($data['username'])) ? '' : $data['username'];
  1082. $data['username_match'] = (!isset($data['username_match'])) ? 'begins' : $data['username_match'];
  1083. $data['website'] = (!isset($data['website'])) ? '' : $data['website'];
  1084. $data['aim'] = (!isset($data['aim'])) ? '' : $data['aim'];
  1085. $data['icq'] = (!isset($data['icq'])) ? '' : $data['icq'];
  1086. $data['msn'] = (!isset($data['msn'])) ? '' : $data['msn'];
  1087. $data['yahoo'] = (!isset($data['yahoo'])) ? '' : $data['yahoo'];
  1088. $data['page'] = (!isset($data['page'])) ? 1 : (int) $data['page'];
  1089. /**
  1090. * Let's build the DB query now!
  1091. */
  1092. $sql_where = 'WHERE 1 = 1';
  1093. // Username begins with a letter or number
  1094. if (strlen($data['letter']) == 1)
  1095. {
  1096. $data['letter'] = chr(ord($data['letter']));
  1097. // Letter is 0: Shall start with number
  1098. if ($data['letter'] == '0')
  1099. {
  1100. $sql_where .= " AND u.`username` NOT REGEXP('[a-zA-Z]')";
  1101. }
  1102. // letter is not 0, so it will be fetching names according to first char
  1103. else
  1104. {
  1105. $sql_where .= " AND u.`username` LIKE '".$this->db->escape_string($data['letter'])."%'";
  1106. }
  1107. }
  1108. // Search for matching username
  1109. if (strlen($data['username']) > 0)
  1110. {
  1111. $data['username'] = htmlspecialchars_uni($data['username']);
  1112. if ($data['username_match'] == 'begins')
  1113. {
  1114. $sql_where .= " AND u.`username` LIKE '".$this->db->escape_string_like($data['username'])."%'";
  1115. }
  1116. else
  1117. {
  1118. $sql_where .= " AND u.`username` LIKE '%".$this->db->escape_string_like($data['username'])."%'";
  1119. }
  1120. }
  1121. // Search for website
  1122. if (strlen($data['website']) > 0)
  1123. {
  1124. $data['website'] = trim(htmlspecialchars_uni($data['website']));
  1125. $sql_where .= " AND u.`website` LIKE '%".$this->db->escape_string_like($data['website'])."%'";
  1126. }
  1127. // Search for AIM
  1128. if (strlen($data['aim']) > 0)
  1129. {
  1130. $sql_where .= " AND u.`aim` LIKE '%".$this->db->escape_string_like($data['aim'])."%'";
  1131. }
  1132. // Search for ICQ
  1133. if (strlen($data['icq']) > 0)
  1134. {
  1135. $sql_where .= " AND u.`icq` LIKE '%".$this->db->escape_string_like($data['icq'])."%'";
  1136. }
  1137. // Search for MSN
  1138. if (strlen($data['msn']) > 0)
  1139. {
  1140. $sql_where .= " AND u.`msn` LIKE '%".$this->db->escape_string_like($data['msn'])."%'";
  1141. }
  1142. // Search for Yahoo
  1143. if (strlen($data['yahoo']) > 0)
  1144. {
  1145. $sql_where .= " AND u.`yahoo` LIKE '%".$this->db->escape_string_like($data['yahoo'])."%'";
  1146. }
  1147. // Build the LIMIT-part of the query here
  1148. if ($data['perpage'] == 0)
  1149. {
  1150. $limit_string = '';
  1151. }
  1152. else
  1153. {
  1154. if ($data['page'] > 0)
  1155. {
  1156. $limit_string = 'LIMIT '.(($data['page'] - 1) * $data['perpage']).', '.$data['perpage'];
  1157. }
  1158. else
  1159. {
  1160. $limit_string = 'LIMIT '.$data['perpage'];
  1161. }
  1162. }
  1163. $sql .= '
  1164. SELECT u.*, f.*
  1165. FROM '.TABLE_PREFIX.'users u
  1166. LEFT JOIN '.TABLE_PREFIX.'userfields f ON f.`ufid` = u.`uid`
  1167. '.$sql_where.'
  1168. ORDER BY '.$data['orderby'].' '.$data['orderdir'].'
  1169. '.$limit_string.'
  1170. ';
  1171. $query = $this->db->query($sql);
  1172. $arr = array();
  1173. while ($member = $this->db->fetch_array($query))
  1174. {
  1175. $arr[] = $member;
  1176. }
  1177. return $arr;
  1178. }
  1179. /**
  1180. * Read some info about a poll
  1181. *
  1182. * @param integer $poll_id ID of Poll to fetch infos from
  1183. * @return array
  1184. */
  1185. function getPoll($poll_id)
  1186. {
  1187. if ($poll_id == 0)
  1188. {
  1189. $this->_errorAndDie('Specified poll ID cannot be 0!');
  1190. }
  1191. $query = $this->db->query('
  1192. SELECT *
  1193. FROM '.TABLE_PREFIX.'polls
  1194. WHERE `pid` = '.(int) $poll_id.'
  1195. LIMIT 1
  1196. ');
  1197. $poll = $this->db->fetch_array($query);
  1198. $separator = '||~|~||';
  1199. $poll['optionsarray'] = explode($separator, $poll['options']);
  1200. $poll['votesarray'] = explode($separator, $poll['votes']);
  1201. /**
  1202. * At this point we are doing another query, so it is easier
  1203. * Little Todo: Include an INNER JOIN in the initial Poll-fetching query to save one query
  1204. * YOu have to make sure that columns of "thread" won't override columns of "poll"
  1205. * Therefore the solution right now at hand will be sufficient, until people start to moan :)
  1206. */
  1207. $poll['thread'] = $this->getThread($poll['tid']);
  1208. $poll['whovoted'] = $this->getWhoVoted($poll_id);
  1209. return $poll;
  1210. }
  1211. /**
  1212. * Returns post data of specified post
  1213. * Refers to: inc/functions.php & inc/class_parser.php
  1214. *
  1215. * @param integer $post_id Post ID to fetch data from
  1216. * @param boolean $parsed Shall the Post message be parsed?
  1217. * @param array $parse_options Array of yes/no options - allow_html,filter_badwords,allow_mycode,allow_smilies,nl2br,me_username
  1218. * @param array $override_forum_parse_options Whether parse options should be defined by forum or by the script.
  1219. If they are being overridden, the array will contain the options
  1220. * @return array|boolean: If unsuccessful, it returns false - Otherwise the Database row
  1221. */
  1222. function getPost($post_id, $parsed = false, $override_forum_parse_options = array())
  1223. {
  1224. if ($post_id == 0)
  1225. {
  1226. $this->_errorAndDie('Specified post ID cannot be 0!');
  1227. }
  1228. // Get the Post data
  1229. $post = get_post($post_id);
  1230. // Post not found? --> False
  1231. if (empty($post))
  1232. {
  1233. return false;
  1234. }
  1235. // Do we have permission?
  1236. $forumpermissions = forum_permissions($post['fid']);
  1237. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  1238. {
  1239. // error_no_permission();
  1240. return false;
  1241. }
  1242. // If the post shall not be parsed, we can already return it at this point
  1243. if ($parsed == false || empty($post))
  1244. {
  1245. return $post;
  1246. }
  1247. // So we want to parse the message
  1248. /**
  1249. * We don't want to override the parse options defined by the forum,
  1250. * so we have first to get these options defined for the forum
  1251. */
  1252. if (count($override_forum_parse_options) == 0)
  1253. {
  1254. // Get the Forum data according to the forum id stored with the post
  1255. $forum = $this->getForum($post['fid']);
  1256. // Set up the parser options.
  1257. $parser_options = array(
  1258. "allow_html" => $forum['allowhtml'],
  1259. "allow_mycode" => $forum['allowmycode'],
  1260. "allow_smilies" => $forum['allowsmilies'],
  1261. "allow_imgcode" => $forum['allowimgcode'],
  1262. "filter_badwords" => 1
  1263. );
  1264. }
  1265. else
  1266. {
  1267. // Self-defined options given in the function parameter
  1268. $parser_options = array(
  1269. 'allow_html' => (isset($override_forum_parse_options['allow_html']) && $override_forum_parse_options['allow_html'] == 1) ? 1 : 0,
  1270. 'allow_mycode' => (isset($override_forum_parse_options['allow_mycode']) && $override_forum_parse_options['allow_mycode'] == 1) ? 1 : 0,
  1271. 'allow_smilies' => (isset($override_forum_parse_options['allow_smilies']) && $override_forum_parse_options['allow_smilies'] == 1) ? 1 : 0,
  1272. 'allow_imgcode' => (isset($override_forum_parse_options['allow_imgcode']) && $override_forum_parse_options['allow_imgcode'] == 1) ? 1 : 0,
  1273. 'filter_badwords' => (isset($override_forum_parse_options['filter_badwords']) && $override_forum_parse_options['filter_badwords'] == 1) ? 1 : 0,
  1274. );
  1275. }
  1276. // Overwrite the message with the parsed message
  1277. $post['message'] = $this->parser->parse_message($post['message'], $parser_options);
  1278. return $post;
  1279. }
  1280. /**
  1281. * Get posts which match the given criteria
  1282. *
  1283. * @param array $params Parameters for the query
  1284. * @return array
  1285. */
  1286. function getPosts($params = array('fields' => '*', 'order_by' => 'dateline', 'order_dir' => 'DESC', 'limit_start' => 0, 'limit' => 0, 'where' => ''))
  1287. {
  1288. // We will store the posts in here
  1289. $posts = array();
  1290. // No matter what parameters will be given, the query starts with the following
  1291. $sql = 'SELECT '.$params['fields'].'
  1292. FROM '.TABLE_PREFIX.'posts';
  1293. // Get all posts or just (hopefully) posts which match certain criteria?
  1294. $sql .= ($params['where'] != '') ? ' WHERE '.$params['where'] : '';
  1295. // Are the posts going to be ordered by a field?
  1296. if ($params['order_by'] != '')
  1297. {
  1298. $sql .= ' ORDER BY '.$params['order_by'];
  1299. if ($params['order_dir'] != '')
  1300. {
  1301. $sql .= ' '.$params['order_dir'];
  1302. }
  1303. else
  1304. {
  1305. $sql .= ' ASC';
  1306. }
  1307. }
  1308. // Get all posts or (hopefully) just a few?
  1309. if ($params['limit'] != 0)
  1310. {
  1311. $sql .= ' LIMIT ';
  1312. if (isset($params['limit_start']))
  1313. {
  1314. $sql .= $params['limit_start'].', '.$params['limit'];
  1315. }
  1316. else
  1317. {
  1318. $sql .= $params['limit'];
  1319. }
  1320. }
  1321. // Run the query
  1322. $query = $this->db->query($sql);
  1323. // Store the returned data in the array we return
  1324. while ($post = $this->db->fetch_array($query))
  1325. {
  1326. $posts[] = $post;
  1327. }
  1328. return $posts;
  1329. }
  1330. /**
  1331. * Get the Posts of a particular thread
  1332. *
  1333. * @param integer $thread_id
  1334. * @param string $fields If you want to fetch certain fields, define them as a string here (separated by comma)
  1335. * @param array $options Options for the query [ array('limit_start', 'limit', 'orderby', 'order_dir') ]
  1336. * @return array
  1337. */
  1338. function getPostsOfThread($thread_id, $fields = '*', $options = array())
  1339. {
  1340. // This is what we will be returning
  1341. $arr = array();
  1342. $query_thread = $this->db->query('SELECT `fid` FROM '.TABLE_PREFIX.'threads WHERE `tid` = '.intval($thread_id).' LIMIT 1');
  1343. $thread_forumid = $this->db->fetch_field($query_thread, 'fid');
  1344. // Do we have permission?
  1345. $forumpermissions = forum_permissions($thread_forumid);
  1346. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  1347. {
  1348. // error_no_permission();
  1349. return false;
  1350. }
  1351. // Let's request the posts from the database
  1352. $query = $this->db->simple_select('posts', $fields, '`tid` = '.intval($thread_id), $options);
  1353. // All we need to do now is to assign them to our returning array
  1354. while ($post = $this->db->fetch_array($query))
  1355. {
  1356. $arr[] = $post;
  1357. }
  1358. return $arr;
  1359. }
  1360. /**
  1361. * Read the messages from database of a user
  1362. *
  1363. * @param integer $user_id ID of user
  1364. * @param array $params Array with options for SQL Query (orderby, sort)
  1365. * @param boolean $translate_folders If the folders should be turned into readable format Å• la "inbox"
  1366. * @return array
  1367. */
  1368. function getPrivateMessagesOfUser($user_id, $params = array('orderby' => 'pm.dateline', 'sort' => 'DESC'), $translate_folders = true)
  1369. {
  1370. /**
  1371. * This is what we will be returning
  1372. * Structure of the array to return:
  1373. * array(
  1374. * 'Inbox' => array( ... Messages ... )
  1375. * )
  1376. *
  1377. * 'Inbox' is the translated folder of folder #1
  1378. */
  1379. $arr = array();
  1380. // If we want to translate the folder names, we need to include the file which contains the translation function
  1381. if ($translate_folders == true)
  1382. {
  1383. include_once MYBB_ROOT.'inc/functions_user.php';
  1384. }
  1385. // Run the Query for Private Messages
  1386. $query = $this->db->query('
  1387. SELECT pm.*, fu.username AS fromusername, tu.username as tousername
  1388. FROM '.TABLE_PREFIX.'privatemessages pm
  1389. LEFT JOIN '.TABLE_PREFIX.'users fu ON (fu.uid=pm.fromid)
  1390. LEFT JOIN '.TABLE_PREFIX.'users tu ON (tu.uid=pm.toid)
  1391. WHERE pm.uid = '.intval($user_id).'
  1392. ORDER BY '.$params['orderby'].' '.$params['sort'].'
  1393. ');
  1394. // Do we have messages?
  1395. if ($this->db->num_rows($query) > 0)
  1396. {
  1397. // Uhh, let's iterate the messages!
  1398. while ($message = $this->db->fetch_array($query))
  1399. {
  1400. // If we translate the folder names, our array index will be the translated folder name
  1401. if ($translate_folders == true)
  1402. {
  1403. $arr[get_pm_folder_name($message['folder'])][] = $message;
  1404. }
  1405. // If we don't want translated folder names, our array index will be the folder number
  1406. else
  1407. {
  1408. $arr[$message['folder']][] = $message;
  1409. }
  1410. }
  1411. }
  1412. return $arr;
  1413. }
  1414. /**
  1415. * Returns data of a specified thread
  1416. * Refers to: inc/functions.php
  1417. *
  1418. * @param integer $thread_id ID of the thread to fetch data from
  1419. * @return array|boolean If unsuccessful, it returns false - Otherwise the Database row
  1420. */
  1421. function getThread($thread_id)
  1422. {
  1423. $thread = get_thread($thread_id);
  1424. // Do we have permission?
  1425. $forumpermissions = forum_permissions($thread['fid']);
  1426. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  1427. {
  1428. // error_no_permission();
  1429. return false;
  1430. }
  1431. else
  1432. {
  1433. return $thread;
  1434. }
  1435. }
  1436. /**
  1437. * Get Threads of one or more forums
  1438. *
  1439. * @param integer $forum_id IDs of Forums to fetch threads from
  1440. * @param string $fields If you want to fetch certain fields, define a string with them
  1441. * @param string $where Additional WHERE constellation if needed
  1442. * @pararm array $query_params Parameters for the Query to run in the database
  1443. (order_by, order_dir, limit_start, limit [limit will only be acknowledged if both limit vars are defined])
  1444. * @param boolean $excluse_invisible Shall we get invisible threads too?
  1445. * @param boolean $join_forums Do we also want to get the forum information of where the threads are located?
  1446. * @param boolean $join_first_post Shall we get the first post of the thread? (= initial post)
  1447. * @return array
  1448. */
  1449. function getThreads($forum_id, $fields = '*', $where = '', $query_params = array('order_by' => 't.`subject`', 'order_dir' => 'ASC'), $exclude_invisible = true, $join_forums = false, $join_first_post = false)
  1450. {
  1451. // Do we have permission?
  1452. if (!is_array($forum_id))
  1453. {
  1454. $forumpermissions = forum_permissions($forum_id);
  1455. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  1456. {
  1457. // error_no_permission();
  1458. return false;
  1459. }
  1460. }
  1461. else
  1462. {
  1463. // Check for every single forum
  1464. foreach ($forum_id as $forum_id_single)
  1465. {
  1466. $forumpermissions = forum_permissions($forum_id_single);
  1467. if ($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1)
  1468. {
  1469. // error_no_permission();
  1470. return false;
  1471. }
  1472. }
  1473. }
  1474. // This is what we will be returning
  1475. $threads = array();
  1476. // Do we want to get invisible threads as well?
  1477. $fetch_invisible_threads = ($exclude_invisible == true) ? '1' : '0';
  1478. $condition = 't.`visible` = '.$fetch_invisible_threads;
  1479. // Are we fetching threads from multiple forums?
  1480. if (is_array($forum_id))
  1481. {
  1482. $condition .= ' AND t.`fid` IN ('.implode(', ', $forum_id).')';
  1483. }
  1484. // Or are we just fetching threads from one forum?
  1485. else
  1486. {
  1487. $condition .= ($forum_id == 0) ? '' : ' AND t.`fid` = '.$forum_id;
  1488. }
  1489. // An additional WHERE clause has been added
  1490. if ($where != '')
  1491. {
  1492. $condition .= ' AND '.$where;
  1493. }
  1494. // Do we want to get information of the forum where the thread is located in?
  1495. $forum_join = ($join_forums == true) ? 'INNER JOIN '.TABLE_PREFIX.'forums f ON f.`fid` = t.`fid`' : '';
  1496. // Do we want to get the first post from the thread?
  1497. $first_post_join = ($join_first_post == true) ? 'INNER JOIN '.TABLE_PREFIX.'posts p ON p.`pid` = t.`firstpost`' : '';
  1498. // Is a Limit defined?
  1499. $limit = (isset($query_params['limit_start']) && isset($query_params['limit'])) ? 'LIMIT '.intval($query_params['limit_start']).', '.intval($query_params['limit']) : '';
  1500. // Run the Query
  1501. $query = $this->db->query('
  1502. SELECT '.$fields.'
  1503. FROM '.TABLE_PREFIX.'threads t
  1504. '.$forum_join.'
  1505. '.$first_post_join.'
  1506. WHERE '.$condition.'
  1507. ORDER BY '.$query_params['order_by'].' '.$query_params['order_dir'].'
  1508. '.$limit.'
  1509. ');
  1510. // Iterate through the results and assign it to our returning array
  1511. while ($thread = $this->db->fetch_array($query))
  1512. {
  1513. $threads[] = $thread;
  1514. }
  1515. return $threads;
  1516. }
  1517. /**
  1518. * Return array with unread threads of a forum
  1519. *
  1520. * @param integer $forum_id
  1521. * @return array
  1522. */
  1523. function getUnreadThreadsOfForum($forum_id)
  1524. {
  1525. $threads = $this->getThreads($forum_id);
  1526. $tids = array();
  1527. // Thread array keys shall be thread IDs
  1528. foreach ($threads as $key => $thread)
  1529. {
  1530. $tids[] = $thread['tid'];
  1531. $threads[$thread['tid']] = $thread;
  1532. unset($threads[$key]);
  1533. }
  1534. $tids = implode(',', $tids);
  1535. $query = $this->db->simple_select("threadsread", "*", "uid='{$this->mybb->user['uid']}' AND tid IN ({$tids})");
  1536. while ($readthread = $this->db->fetch_array($query))
  1537. {
  1538. // Dateline of checking forum is past of last activity - so we delete the entry in array
  1539. if ($readthread['dateline'] > $threads[$readthread['tid']]['lastpost'])
  1540. {
  1541. unset($threads[$readthread['tid']]);
  1542. }
  1543. }
  1544. return $threads;
  1545. }
  1546. /**
  1547. * Returns data of a user
  1548. * Refers to: inc/functions.php
  1549. *
  1550. * @param integer $user_id ID of User to fetch data from (0 = own user)
  1551. * @return array
  1552. */
  1553. function getUser($user_id = 0)
  1554. {
  1555. // If given user id is 0, we use the own User ID
  1556. if ($user_id == 0)
  1557. {
  1558. return get_user($this->mybb->user['uid']);
  1559. }
  1560. // Otherwise we fetch info from given User ID
  1561. else
  1562. {
  1563. return get_user($user_id);
  1564. }
  1565. }
  1566. /**
  1567. * Fetch the users being online
  1568. * Refers to: index.php
  1569. *
  1570. * @param boolean $colored_usernames Define if we want to return formatted usernames (color)
  1571. * @return array
  1572. */
  1573. function getWhoIsOnline($colored_usernames = true)
  1574. {
  1575. // This is what we are going to return
  1576. $arr = array(
  1577. 'bots' => array(),
  1578. 'count_anonymous' => 0,
  1579. 'count_bots' => 0,
  1580. 'count_guests' => 0,
  1581. 'count_members' => 0,
  1582. 'members' => array()
  1583. );
  1584. // We only fetch the Who's Online list if the setting tells us that we can
  1585. if($this->mybb->settings['showwol'] != 0 && $this->mybb->usergroup['canviewonline'] != 0)
  1586. {
  1587. // Get the online users.
  1588. $timesearch = TIME_NOW - $this->mybb->settings['wolcutoff'];
  1589. $comma = '';
  1590. $query = $this->db->query("
  1591. SELECT s.sid, s.ip, s.uid, s.time, s.location, s.location1, u.username, u.invisible, u.usergroup, u.displaygroup
  1592. FROM ".TABLE_PREFIX."sessions s
  1593. LEFT JOIN ".TABLE_PREFIX."users u ON (s.uid=u.uid)
  1594. WHERE s.time>'$timesearch'
  1595. ORDER BY u.username ASC, s.time DESC
  1596. ");
  1597. // Iterated users will be stored here to prevent double iterating one user
  1598. $doneusers = array();
  1599. // Fetch spiders
  1600. $spiders = $this->cache->read("spiders");
  1601. // Loop through all users.
  1602. while($user = $this->db->fetch_array($query))
  1603. {
  1604. // Create a key to test if this user is a search bot.
  1605. $botkey = my_strtolower(str_replace("bot=", '', $user['sid']));
  1606. // Decide what type of user we are dealing with.
  1607. if($user['uid'] > 0)
  1608. {
  1609. // The user is registered.
  1610. if($doneusers[$user['uid']] < $user['time'] || !$doneusers[$user['uid']])
  1611. {
  1612. // If the user is logged in anonymously, update the count for that.
  1613. if($user['invisible'] == 1)
  1614. {
  1615. ++$arr['count_anonymous'];
  1616. }
  1617. if($user['invisible'] != 1 || $this->mybb->usergroup['canviewwolinvis'] == 1 || $user['uid'] == $this->mybb->user['uid'])
  1618. {
  1619. // Maybe we don't want colored usernames
  1620. if ($colored_usernames == true)
  1621. {
  1622. // Properly format the username and assign the template.
  1623. $user['username'] = format_name($user['username'], $user['usergroup'], $user['displaygroup']);
  1624. }
  1625. $user['profilelink'] = build_profile_link($user['username'], $user['uid']);
  1626. }
  1627. // This user has been handled.
  1628. $doneusers[$user['uid']] = $user['time'];
  1629. // Add the user to the members, since he is registered and logged in
  1630. $arr['members'][]= $user;
  1631. // Increase member counter
  1632. ++$arr['count_members'];
  1633. }
  1634. }
  1635. // The user is a search bot.
  1636. elseif(my_strpos($user['sid'], "bot=") !== false && $spiders[$botkey])
  1637. {
  1638. ++$arr['count_bots'];
  1639. $arr['bots'][] = $spiders[$botkey];
  1640. }
  1641. // The user is a guest
  1642. else
  1643. {
  1644. ++$arr['count_guests'];
  1645. }
  1646. }
  1647. }
  1648. return $arr;
  1649. }
  1650. /**
  1651. * Return members which have posted in a thread
  1652. *
  1653. * @param integer $thread_id ID of Thread
  1654. * @return array|false
  1655. */
  1656. function getWhoPosted($thread_id, $sort_by_posts = true)
  1657. {
  1658. $thread = $this->getThread($thread_id); // No need to check for permissions, the function already does it
  1659. $forum = $this->getForum($thread['fid']); // No need to check for permissions, the function already does it
  1660. if (!$this->checkForumPassword($forum['fid']))
  1661. {
  1662. return false;
  1663. }
  1664. if($sort_by_posts === true)
  1665. {
  1666. $sort_sql = ' ORDER BY posts DESC';
  1667. }
  1668. else
  1669. {
  1670. $sort_sql = ' ORDER BY p.username ASC';
  1671. }
  1672. $query = $this->db->query('
  1673. SELECT COUNT(p.pid) AS posts, p.username AS postusername, u.uid, u.username, u.usergroup, u.displaygroup
  1674. FROM '.TABLE_PREFIX.'posts p
  1675. LEFT JOIN '.TABLE_PREFIX.'users u ON (u.uid=p.uid)
  1676. WHERE tid='.intval($thread_id).' AND p.visible = 1
  1677. GROUP BY u.uid
  1678. '.$sortsql.'
  1679. ');
  1680. $i = 0;
  1681. $arr = array();
  1682. $arr['total_posts'] = 0;
  1683. while ($poster = $this->db->fetch_array($query))
  1684. {
  1685. if($poster['username'] == '')
  1686. {
  1687. $poster['username'] = $poster['postusername'];
  1688. }
  1689. $poster_name = format_name($poster['username'], $poster['usergroup'], $poster['displaygroup']);
  1690. $arr[$i]['username']= $poster['username'];
  1691. $arr[$i]['profile_link'] = build_profile_link($poster_name, $poster['uid'], '_blank', $onclick);
  1692. $arr[$i]['posts'] = $poster['posts'];
  1693. ++$i;
  1694. $arr['total_posts'] += $poster['posts'];
  1695. }
  1696. return $arr;
  1697. }
  1698. /**
  1699. * Returns users which have voted in a poll
  1700. *
  1701. * @param integer $poll_id ID of Poll
  1702. * @return array
  1703. */
  1704. function getWhoVoted($poll_id)
  1705. {
  1706. if ($poll_id == 0)
  1707. {
  1708. $this->_errorAndDie('Specified post ID cannot be 0!');
  1709. }
  1710. $query = $this->db->query('
  1711. SELECT pv.`vid`, pv.`uid`, pv.`voteoption`, pv.`dateline`,
  1712. u.`username`, u.`usergroup`, u.`displaygroup`
  1713. FROM '.TABLE_PREFIX.'pollvotes pv
  1714. LEFT JOIN '.TABLE_PREFIX.'users u ON u.`uid` = pv.`uid`
  1715. WHERE pv.`pid` = '.(int) $poll_id.'
  1716. ');
  1717. $arr = array();
  1718. $i = 0;
  1719. while ($voter = $this->db->fetch_array($query))
  1720. {
  1721. $voter_name = format_name($voter['username'], $voter['usergroup'], $voter['displaygroup']);
  1722. $arr[$i] = array(
  1723. 'vid' => $voter['vid'],
  1724. 'username' => $voter['username'],
  1725. 'profile_link' => build_profile_link($voter_name, $voter['uid'], '_blank', $onclick),
  1726. 'voteoption' => $voter['voteoption'],
  1727. 'dateline' => $voter['dateline']
  1728. );
  1729. ++$i;
  1730. }
  1731. return $arr;
  1732. }
  1733. /**
  1734. * Increases the Amount of Views of a thread
  1735. *
  1736. * @param integer $thread_id ID of Thread
  1737. */
  1738. function incViews($thread_id)
  1739. {
  1740. // All we do here is to run the increment query
  1741. $this->db->query('
  1742. UPDATE '.TABLE_PREFIX.'threads
  1743. SET `views` = `views` + 1
  1744. WHERE `tid` = '.intval($thread_id).'
  1745. ');
  1746. }
  1747. /**
  1748. * Is the user logged in?
  1749. *
  1750. * @return boolean
  1751. */
  1752. function isLoggedIn()
  1753. {
  1754. // If the user is logged in, he has an UID
  1755. return ($this->mybb->user['uid'] != 0) ? true : false;
  1756. }
  1757. /**
  1758. * Is the user a moderator?
  1759. * This function checks if the user has certain rights to perform an action in a forum
  1760. * Refers to: inc/functions.php
  1761. *
  1762. * @param integer $forum_id ID of the forum to check permissions for
  1763. * @param string $action Action which shall be checked for
  1764. * @param integer $user_id ID of User
  1765. */
  1766. function isModerator($forum_id = 0, $action = '', $user_id = 0)
  1767. {
  1768. // If we aren't logged in, we cannot possibly a moderator
  1769. if ($this->isLoggedIn())
  1770. {
  1771. return false;
  1772. }
  1773. // If given user_id is 0 we tak the user_id of the current user --> Check if own user is mod
  1774. return is_moderator($forum_id, $action, ($user_id == 0) ? $this->mybb->user['uid'] : $user_id);
  1775. }
  1776. /**
  1777. * Returns if a user has super admin permission
  1778. * Refers to: inc/functions.php
  1779. *
  1780. * @param integer $user_id User-ID
  1781. * @return boolean
  1782. */
  1783. function isSuperAdmin($user_id = 0)
  1784. {
  1785. // If specified user_id is 0, we want to know if current user is Super Admin
  1786. return is_super_admin(($user_id == 0) ? $this->mybb->user['uid'] : $user_id);
  1787. }
  1788. /**
  1789. * Login procedure for a user + password
  1790. * Possible ToDo: Return error messages / array / whatever
  1791. *
  1792. * @param string $username Username
  1793. * @param string $password Password of User
  1794. * @return boolean
  1795. */
  1796. function login($username, $password, $captcha_hash = '', $captcha_string = '')
  1797. {
  1798. $this->lang->load('member');
  1799. /**
  1800. * If we are already logged in, we do not have to perform the login procedure
  1801. * However, we can make believe that the login did succeed
  1802. * It certainly did a while ago ;)
  1803. */
  1804. if ($this->isLoggedIn())
  1805. {
  1806. return true;
  1807. }
  1808. // by default, login is good!
  1809. $bad_login = false;
  1810. /**
  1811. * Let's see how many logins we have already tried
  1812. */
  1813. $logins = login_attempt_check(NON_FATAL);
  1814. // We need a few functions from the user function collection for the login procedur
  1815. require_once MYBB_ROOT.'inc/functions_user.php';
  1816. // If the username does not exist, login fails
  1817. if (!username_exists($username))
  1818. {
  1819. my_setcookie('loginattempts', $logins + 1);
  1820. return false;
  1821. }
  1822. /**
  1823. * Let's get a database version of the login attempts
  1824. * Previous login attempt call relied on cookies
  1825. */
  1826. $query = $this->db->simple_select("users", "loginattempts", "LOWER(username)='".$this->db->escape_string(my_strtolower($username))."'", array('limit' => 1));
  1827. $loginattempts = $this->db->fetch_field($query, "loginattempts");
  1828. // Let's call the handy MyBB validation function and see if we find a user
  1829. $user = validate_password_from_username($username, $password);
  1830. if (!$user['uid'])
  1831. {
  1832. my_setcookie('loginattempts', $logins + 1);
  1833. $this->db->write_query("UPDATE ".TABLE_PREFIX."users SET `loginattempts` = `loginattempts` + 1 WHERE LOWER(`username`) = '".$this->db->escape_string(my_strtolower($username))."'");
  1834. $bad_login = true;
  1835. }
  1836. /**
  1837. * Possible ToDo:
  1838. * If we have had more than 3 login attemps a captcha is shown in MyBB
  1839. * Maybe provide the same functionality in MyBBIntegrator ?
  1840. */
  1841. if ($loginattempts > 3 || intval($mybb->cookies['loginattempts']) > 3)
  1842. {
  1843. // Captcha input is given, let's validate the captcha and see if we can login
  1844. if (!empty($captcha_hash) && !empty($captcha_string))
  1845. {
  1846. if (!$this->validateCaptcha($captcha_hash, $captcha_string) || $bad_login === true)
  1847. {
  1848. return $this->generateCaptcha();
  1849. }
  1850. }
  1851. else
  1852. {
  1853. // Show captcha image for guests if enabled
  1854. if ($this->mybb->settings['captchaimage'] == 1 && function_exists("imagepng") && !$this->mybb->user['uid'])
  1855. {
  1856. return $this->generateCaptcha();
  1857. }
  1858. }
  1859. }
  1860. else
  1861. {
  1862. if ($bad_login === true)
  1863. {
  1864. return false;
  1865. }
  1866. }
  1867. // COPPA users always fail :D
  1868. if ($user['coppauser'])
  1869. {
  1870. return false;
  1871. }
  1872. // Reset both login attempts counter (cookie + database)
  1873. my_setcookie('loginattempts', 1);
  1874. $this->db->update_query("users", array("loginattempts" => 1), "uid='{$user['uid']}'");
  1875. // Delete old session entry
  1876. $this->db->delete_query("sessions", "ip='".$this->db->escape_string($this->mybb->session->ipaddress)."' AND sid != '".$this->mybb->session->sid."'");
  1877. // Create a new session and save it in the database
  1878. $newsession = array(
  1879. "uid" => $user['uid'],
  1880. );
  1881. $this->db->update_query("sessions", $newsession, "sid='".$this->mybb->session->sid."'");
  1882. // Temporarily set the cookie remember option for the login cookies
  1883. $this->mybb->user['remember'] = $user['remember'];
  1884. // Set essential login cookies
  1885. my_setcookie("mybbuser", $user['uid']."_".$user['loginkey'], null, true);
  1886. my_setcookie("sid", $this->mybb->session->sid, -1, true);
  1887. // If there are hooks defined for the end of the login procedure, call them
  1888. $this->plugins->run_hooks("member_do_login_end");
  1889. return true;
  1890. }
  1891. /**
  1892. * Logs an administrator action taking any arguments as log data.
  1893. * Taken from admin/inc/functions.php
  1894. *
  1895. * NEEDS MODULE AND ACTION AS PARAMS! DONT FORGET TO PUT THIS INTO DOCUMENTATION
  1896. */
  1897. function logAdminAction()
  1898. {
  1899. $data = func_get_args();
  1900. if(count($data) == 1 && is_array($data[0]))
  1901. {
  1902. $data = $data[0];
  1903. }
  1904. if(!is_array($data))
  1905. {
  1906. $data = array($data);
  1907. }
  1908. $log_entry = array(
  1909. "uid" => $this->mybb->user['uid'],
  1910. "ipaddress" => $this->db->escape_string(get_ip()),
  1911. "dateline" => TIME_NOW,
  1912. "module" => $this->db->escape_string($this->mybb->input['module']),
  1913. "action" => $this->db->escape_string($this->mybb->input['action']),
  1914. "data" => $this->db->escape_string(@serialize($data))
  1915. );
  1916. $this->db->insert_query("adminlog", $log_entry);
  1917. }
  1918. /**
  1919. * Log an action taken by a user with moderator rights
  1920. *
  1921. * @param array $data Data array with information necessary to pass onto the log
  1922. * @param string $action Name of the action
  1923. */
  1924. function logModeratorAction($data, $action = '')
  1925. {
  1926. // If the fid or tid is not set, set it at 0 so MySQL doesn't choke on it.
  1927. if($data['fid'] == '')
  1928. {
  1929. $fid = 0;
  1930. }
  1931. else
  1932. {
  1933. $fid = $data['fid'];
  1934. unset($data['fid']);
  1935. }
  1936. if($data['tid'] == '')
  1937. {
  1938. $tid = 0;
  1939. }
  1940. else
  1941. {
  1942. $tid = $data['tid'];
  1943. unset($data['tid']);
  1944. }
  1945. // Any remaining extra data - we serialize and insert in to its own column
  1946. if(is_array($data))
  1947. {
  1948. $data = serialize($data);
  1949. }
  1950. $sql_array = array(
  1951. "uid" => $this->mybb->user['uid'],
  1952. "dateline" => TIME_NOW,
  1953. "fid" => $fid,
  1954. "tid" => $tid,
  1955. "action" => $this->db->escape_string($action),
  1956. "data" => $this->db->escape_string($data),
  1957. "ipaddress" => $this->db->escape_string($this->session->ipaddress)
  1958. );
  1959. $this->db->insert_query("moderatorlog", $sql_array);
  1960. }
  1961. /**
  1962. * Logout procedure
  1963. *
  1964. * @return boolean
  1965. */
  1966. function logout()
  1967. {
  1968. // If the user is not logged in at all, we make him believe that the logout procedure workedjust fine
  1969. if (!$this->isLoggedIn())
  1970. {
  1971. return true;
  1972. }
  1973. // Check session ID if we have one
  1974. if($this->mybb->input['sid'] && $this->mybb->input['sid'] != $this->mybb->session->sid)
  1975. {
  1976. return false;
  1977. }
  1978. // Otherwise, check logoutkey
  1979. else if (!$this->mybb->input['sid'] && $this->mybb->input['logoutkey'] != $this->mybb->user['logoutkey'])
  1980. {
  1981. return false;
  1982. }
  1983. // Clear essential login cookies
  1984. my_unsetcookie("mybbuser");
  1985. my_unsetcookie("sid");
  1986. // The logged in user data will be updated
  1987. if($this->mybb->user['uid'])
  1988. {
  1989. $time = TIME_NOW;
  1990. $lastvisit = array(
  1991. "lastactive" => $time-900,
  1992. "lastvisit" => $time,
  1993. );
  1994. $this->db->update_query("users", $lastvisit, "uid='".$this->mybb->user['uid']."'");
  1995. $this->db->delete_query("sessions", "sid='".$this->mybb->session->sid."'");
  1996. }
  1997. // If there are any hooks to run, we call them here
  1998. $this->plugins->run_hooks("member_logout_end");
  1999. return true;
  2000. }
  2001. /**
  2002. * Marks one or more forums read
  2003. *
  2004. * @param integer $forum_id If Forum ID is set to 0 all forums will be marked as read
  2005. * @param string $redirect_url If there should be a redirection afterwards, define the URL here
  2006. * @return boolean Only returns false if it fails, otherwise, if it does not redirect, it returns true
  2007. */
  2008. function markRead($id = 0, $redirect_url = '')
  2009. {
  2010. // "Mark-Read" functions are located in inc/functions_indicators.php
  2011. require_once MYBB_ROOT."/inc/functions_indicators.php";
  2012. // Make sure the ID is a number
  2013. $id = intval($id);
  2014. // If the given Forum ID is 0, it tells us that we shall mark all forums as read
  2015. if ($id == 0)
  2016. {
  2017. mark_all_forums_read();
  2018. // If we want to redirect to an url, we do so
  2019. if ($redirect_url != '')
  2020. {
  2021. redirect($redirect_url, $this->lang->redirect_markforumsread);
  2022. }
  2023. }
  2024. // If a specific ID has been defined, we certainly want to mark ONE forum as read
  2025. else
  2026. {
  2027. // Does the Forum exist?
  2028. $validforum = $this->getForum($id);
  2029. // If the forum is invalid, marking as read failed
  2030. if (!$validforum)
  2031. {
  2032. return false;
  2033. }
  2034. // If we want to redirect to an url, we do so
  2035. if ($redirect_url != '')
  2036. {
  2037. redirect($redirect_url, $this->lang->redirect_markforumsread);
  2038. }
  2039. }
  2040. return true;
  2041. }
  2042. /**
  2043. * Constructor
  2044. * If we include the global.php of MyBB in the constructor,
  2045. * weird error messages popup
  2046. * --> This sounds like a ToDo: Find out why?????? - My guess: Some evil eval() functions
  2047. *
  2048. * @param object $mybb Pass the Super MyBB Object as a reference so we can work with it
  2049. * @param object $db Pass the MyBB Database Handler as a reference so we can work with is
  2050. */
  2051. function MyBBIntegrator(&$mybb, &$db, &$cache, &$plugins, &$lang, &$config)
  2052. {
  2053. $this->mybb =& $mybb;
  2054. $this->db =& $db;
  2055. $this->cache = $cache;
  2056. $this->plugins =& $plugins;
  2057. $this->lang =& $lang;
  2058. $this->config =& $config;
  2059. define('MYBB_ADMIN_DIR', MYBB_ROOT.$this->config['admin_dir'].'/');
  2060. // Some Constants for non-magic-numbers
  2061. define('NON_FATAL', false);
  2062. require_once MYBB_ROOT.'inc/class_parser.php';
  2063. $this->parser = new postParser;
  2064. }
  2065. /**
  2066. * This function creates a class object if it is necessary
  2067. * This is needed, if we want to use classes, which are not included in the init routine of mybb (example: Moderation)
  2068. *
  2069. * @param string $object Name of the class object
  2070. * @param string $class_name Name of the Class
  2071. * @param string $include_path The Path where we can find the class
  2072. */
  2073. function MyBBIntegratorClassObject($object, $class_name, $include_path)
  2074. {
  2075. if (isset($this->{$object}))
  2076. {
  2077. return;
  2078. }
  2079. else
  2080. {
  2081. require_once $include_path;
  2082. $this->{$object} = new $class_name;
  2083. }
  2084. }
  2085. /**
  2086. * Enables you to close one or more threads
  2087. * One thread: $thread_id is int
  2088. * More threads: $thread_id is array with ints
  2089. *
  2090. * @param integer|array $thread_id See above
  2091. * @param integer $forum_id This can be filled for a nice moderator log!
  2092. * @return boolean
  2093. */
  2094. function openThread($thread_id, $forum_id = 0)
  2095. {
  2096. if (!is_moderator($fid, "canopenclosethreads"))
  2097. {
  2098. return false;
  2099. }
  2100. $this->lang->load('moderation');
  2101. $this->MyBBIntegratorClassObject('moderation', 'Moderation', MYBB_ROOT.'/inc/class_moderation.php');
  2102. $this->moderation->open_threads($thread_id);
  2103. $modlogdata['fid'] = $forum_id;
  2104. $this->logModeratorAction($modlogdata, $this->lang->mod_process);
  2105. return true;
  2106. }
  2107. /**
  2108. * Parses a string/message with the MyBB Parser Class
  2109. * Refers to: /inc/class_parser.php
  2110. *
  2111. * @param string $message The String which shall be parsed
  2112. * @param array $options Options the parser can accept: filter_badwords, allow_html, allow_mycode, me_username, allow_smilies, nl2br,
  2113. * @return string Parsed string
  2114. */
  2115. function parseString($message, $options = array())
  2116. {
  2117. // Set base URL for parsing smilies
  2118. $base_url= $this->mybb->settings['bburl'];
  2119. if($base_url!= "")
  2120. {
  2121. if(my_substr($base_url, my_strlen($base_url) -1) != "/")
  2122. {
  2123. $base_url= $base_url."/";
  2124. }
  2125. }
  2126. $message = $this->plugins->run_hooks("parse_message_start", $message);
  2127. // Get rid of cartridge returns for they are the workings of the devil
  2128. $message = str_replace("\r", "", $message);
  2129. // Filter bad words if requested.
  2130. if($options['filter_badwords'])
  2131. {
  2132. $message = $this->parser->parse_badwords($message);
  2133. }
  2134. if($options['allow_html'] != 1)
  2135. {
  2136. $message = $this->parser->parse_html($message);
  2137. }
  2138. else
  2139. {
  2140. while(preg_match("#<script(.*)>(.*)</script(.*)>#is", $message))
  2141. {
  2142. $message = preg_replace("#<script(.*)>(.*)</script(.*)>#is", "&lt;script$1&gt;$2&lt;/script$3&gt;", $message);
  2143. }
  2144. // Remove these completely
  2145. $message = preg_replace("#\s*<base[^>]*>\s*#is", "", $message);
  2146. $message = preg_replace("#\s*<meta[^>]*>\s*#is", "", $message);
  2147. $message = str_replace(array('<?php', '<!--', '-->', '?>', "<br />\n", "<br>\n"), array('&lt;?php', '&lt;!--', '--&gt;', '?&gt;', "\n", "\n"), $message);
  2148. }
  2149. // If MyCode needs to be replaced, first filter out [code] and [php] tags.
  2150. if($options['allow_mycode'])
  2151. {
  2152. // First we split up the contents of code and php tags to ensure they're not parsed.
  2153. preg_match_all("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", $message, $code_matches, PREG_SET_ORDER);
  2154. $message = preg_replace("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", "<mybb-code>\n", $message);
  2155. }
  2156. // Always fix bad Javascript in the message.
  2157. $message = $this->parser->fix_javascript($message);
  2158. // Replace "me" code and slaps if we have a username
  2159. if($options['me_username'])
  2160. {
  2161. $message = preg_replace('#(>|^|\r|\n)/me ([^\r\n<]*)#i', "\\1<span style=\"color: red;\">* {$options['me_username']} \\2</span>", $message);
  2162. $message = preg_replace('#(>|^|\r|\n)/slap ([^\r\n<]*)#i', "\\1<span style=\"color: red;\">* {$options['me_username']} {$this->lang->slaps} \\2 {$this->lang->with_trout}</span>", $message);
  2163. }
  2164. // If we can, parse smilies
  2165. if($options['allow_smilies'])
  2166. {
  2167. $message = $this->parser->parse_smilies($message, $options['allow_html']);
  2168. }
  2169. // Replace MyCode if requested.
  2170. if($options['allow_mycode'])
  2171. {
  2172. $message = $this->parser->parse_mycode($message, $options);
  2173. }
  2174. // Run plugin hooks
  2175. $message = $this->plugins->run_hooks("parse_message", $message);
  2176. if($options['allow_mycode'])
  2177. {
  2178. // Now that we're done, if we split up any code tags, parse them and glue it all back together
  2179. if(count($code_matches) > 0)
  2180. {
  2181. foreach($code_matches as $text)
  2182. {
  2183. // Fix up HTML inside the code tags so it is clean
  2184. if($options['allow_html'] != 0)
  2185. {
  2186. $text[2] = $this->parser->parse_html($text[2]);
  2187. }
  2188. if(my_strtolower($text[1]) == "code")
  2189. {
  2190. $code = $this->parser->mycode_parse_code($text[2]);
  2191. }
  2192. elseif(my_strtolower($text[1]) == "php")
  2193. {
  2194. $code = $this->parser->mycode_parse_php($text[2]);
  2195. }
  2196. $message = preg_replace("#\<mybb-code>\n?#", $code, $message, 1);
  2197. }
  2198. }
  2199. }
  2200. if($options['nl2br'] !== 0)
  2201. {
  2202. $message = nl2br($message);
  2203. // Fix up new lines and block level elements
  2204. $message = preg_replace("#(</?(?:html|head|body|div|p|form|table|thead|tbody|tfoot|tr|td|th|ul|ol|li|div|p|blockquote|cite|hr)[^>]*>)\s*<br />#i", "$1", $message);
  2205. $message = preg_replace("#(&nbsp;)+(</?(?:html|head|body|div|p|form|table|thead|tbody|tfoot|tr|td|th|ul|ol|li|div|p|blockquote|cite|hr)[^>]*>)#i", "$2", $message);
  2206. }
  2207. $message = my_wordwrap($message);
  2208. $message = $this->plugins->run_hooks("parse_message_end", $message);
  2209. return $message;
  2210. }
  2211. /**
  2212. * Register procedure
  2213. * Refers to: /member.php
  2214. *
  2215. * @param array $info Contains user information of the User to be registered
  2216. * @return array|string If registration fails, we return an array containing the error message,
  2217. * If registration is successful, we return the string, which notifies the user of what will be the next action
  2218. */
  2219. function register($info = array())
  2220. {
  2221. // Load the language phrases we need for the registration
  2222. $this->lang->load('member');
  2223. /**
  2224. * $info contains the given user information for the registration
  2225. * We need to make sure that every possible key is given, so we do not generate ugly E_NOIICE errors
  2226. */
  2227. $possible_info_keys = array(
  2228. 'username', 'password', 'password2', 'email', 'email2', 'referrer', 'timezone', 'language',
  2229. 'profile_fields', 'allownotices', 'hideemail', 'subscriptionmethod',
  2230. 'receivepms', 'pmnotice', 'emailpmnotify', 'invisible', 'dstcorrection'
  2231. );
  2232. // Iterate the possible info keys to create the array entry in $info if it does not exist
  2233. foreach ($possible_info_keys as $possible_info_key)
  2234. {
  2235. if (!isset($info[$possible_info_key]))
  2236. {
  2237. $info[$possible_info_key] = '';
  2238. }
  2239. }
  2240. // Run whatever hook specified at the beginning of the registration
  2241. $this->plugins->run_hooks('member_do_register_start');
  2242. // If register type is random password, we generate one
  2243. if($this->mybb->settings['regtype'] == "randompass")
  2244. {
  2245. $info['password'] = random_str();
  2246. $info['password2'] = $info['password'];
  2247. }
  2248. if($this->mybb->settings['regtype'] == "verify" || $this->mybb->settings['regtype'] == "admin" || $info['coppa'] == 1)
  2249. {
  2250. $usergroup = 5;
  2251. }
  2252. else
  2253. {
  2254. $usergroup = 2;
  2255. }
  2256. // Set up user handler.
  2257. require_once MYBB_ROOT."inc/datahandlers/user.php";
  2258. $userhandler = new UserDataHandler("insert");
  2259. // Set the data for the new user.
  2260. $user = array(
  2261. "username" => $info['username'],
  2262. "password" => $info['password'],
  2263. "password2" => $info['password2'],
  2264. "email" => $info['email'],
  2265. "email2" => $info['email2'],
  2266. "usergroup" => $usergroup,
  2267. "referrer" => $info['referrername'],
  2268. "timezone" => $info['timezone'],
  2269. "language" => $info['language'],
  2270. "profile_fields" => $info['profile_fields'],
  2271. "regip" => $this->mybb->session->ipaddress,
  2272. "longregip" => ip2long($this->mybb->session->ipaddress),
  2273. "coppa_user" => intval($this->mybb->cookies['coppauser']),
  2274. );
  2275. if(isset($info['regcheck1']) && isset($info['regcheck2']))
  2276. {
  2277. $user['regcheck1'] = $info['regcheck1'];
  2278. $user['regcheck2'] = $info['regcheck2'];
  2279. }
  2280. // Do we have a saved COPPA DOB?
  2281. if($this->mybb->cookies['coppadob'])
  2282. {
  2283. list($dob_day, $dob_month, $dob_year) = explode("-", $this->mybb->cookies['coppadob']);
  2284. $user['birthday'] = array(
  2285. "day" => $dob_day,
  2286. "month" => $dob_month,
  2287. "year" => $dob_year
  2288. );
  2289. }
  2290. // Generate the options array of the user
  2291. $user['options'] = array(
  2292. "allownotices" => $info['allownotices'],
  2293. "hideemail" => $info['hideemail'],
  2294. "subscriptionmethod" => $info['subscriptionmethod'],
  2295. "receivepms" => $info['receivepms'],
  2296. "pmnotice" => $info['pmnotice'],
  2297. "emailpmnotify" => $info['emailpmnotify'],
  2298. "invisible" => $info['invisible'],
  2299. "dstcorrection" => $info['dstcorrection']
  2300. );
  2301. // Assign data to the data handler
  2302. $userhandler->set_data($user);
  2303. // If the validation of the user failed, we return nice (friendly) errors
  2304. if(!$userhandler->validate_user())
  2305. {
  2306. $errors = $userhandler->get_friendly_errors();
  2307. return $errors;
  2308. }
  2309. // Create the User in the database
  2310. $user_info = $userhandler->insert_user();
  2311. // We need to set a cookie, if we don't want a random password (and it is no COPPA user), so he is instantly logged in
  2312. if($this->mybb->settings['regtype'] != "randompass" && !$this->mybb->cookies['coppauser'])
  2313. {
  2314. // Log them in
  2315. my_setcookie("mybbuser", $user_info['uid']."_".$user_info['loginkey'], null, true);
  2316. }
  2317. /**
  2318. * Coppa User
  2319. * Nothing special, just return that the coppa user will be redirected
  2320. */
  2321. if($this->mybb->cookies['coppauser'])
  2322. {
  2323. $this->lang->redirect_registered_coppa_activate = $this->lang->sprintf($this->lang->redirect_registered_coppa_activate, $this->mybb->settings['bbname'], $user_info['username']);
  2324. my_unsetcookie("coppauser");
  2325. my_unsetcookie("coppadob");
  2326. // Run whatever hook is defined at the end of a registration
  2327. $this->plugins->run_hooks("member_do_register_end");
  2328. return $this->lang->redirect_registered_coppa_activate;
  2329. }
  2330. /**
  2331. * Register Mode: Email Verification
  2332. * A mail is dispatched containing an activation link.
  2333. * The activation link is a reference to the newly created database entry
  2334. */
  2335. else if($this->mybb->settings['regtype'] == "verify")
  2336. {
  2337. // Generate and save the activation code in the database
  2338. $activationcode = random_str();
  2339. $now = TIME_NOW;
  2340. $activationarray = array(
  2341. "uid" => $user_info['uid'],
  2342. "dateline" => TIME_NOW,
  2343. "code" => $activationcode,
  2344. "type" => "r"
  2345. );
  2346. $this->db->insert_query("awaitingactivation", $activationarray);
  2347. // Generate and send the email
  2348. $emailsubject = $this->lang->sprintf($this->lang->emailsubject_activateaccount, $this->mybb->settings['bbname']);
  2349. $emailmessage = $this->lang->sprintf($this->lang->email_activateaccount, $user_info['username'], $this->mybb->settings['bbname'], $this->mybb->settings['bburl'], $user_info['uid'], $activationcode);
  2350. my_mail($user_info['email'], $emailsubject, $emailmessage);
  2351. // Build the message to return
  2352. $this->lang->redirect_registered_activation = $this->lang->sprintf($this->lang->redirect_registered_activation, $this->mybb->settings['bbname'], $user_info['username']);
  2353. // Run whatever hook is defined at the end of a registration
  2354. $this->plugins->run_hooks("member_do_register_end");
  2355. return $this->lang->redirect_registered_activation;
  2356. }
  2357. /**
  2358. * Register Mode: Send Random Password
  2359. * A mail is dispatched, containing the random password for the user
  2360. */
  2361. else if($this->mybb->settings['regtype'] == "randompass")
  2362. {
  2363. // Generate and send the email
  2364. $emailsubject = $this->lang->sprintf($this->lang->emailsubject_randompassword, $this->mybb->settings['bbname']);
  2365. $emailmessage = $this->lang->sprintf($this->lang->email_randompassword, $user['username'], $this->mybb->settings['bbname'], $user_info['username'], $user_info['password']);
  2366. my_mail($user_info['email'], $emailsubject, $emailmessage);
  2367. // Run whatever hook is defined at the end of a registration
  2368. $this->plugins->run_hooks("member_do_register_end");
  2369. return $this->lang->redirect_registered_passwordsent;
  2370. }
  2371. /**
  2372. * Register Mode: Admin Activation
  2373. * Return the message that the user will need to be authorized by an admin
  2374. */
  2375. else if($this->mybb->settings['regtype'] == "admin")
  2376. {
  2377. // Build the message to return
  2378. $this->lang->redirect_registered_admin_activate = $this->lang->sprintf($this->lang->redirect_registered_admin_activate, $this->mybb->settings['bbname'], $user_info['username']);
  2379. // Run whatever hook is defined at the end of a registration
  2380. $this->plugins->run_hooks("member_do_register_end");
  2381. return $this->lang->redirect_registered_admin_activate;
  2382. }
  2383. /**
  2384. * No activation required whatsoever,
  2385. * directly registered
  2386. */
  2387. else
  2388. {
  2389. // Build the message to return
  2390. $this->lang->redirect_registered = $this->lang->sprintf($this->lang->redirect_registered, $this->mybb->settings['bbname'], $user_info['username']);
  2391. // Run whatever hook is defined at the end of a registration
  2392. $this->plugins->run_hooks('member_do_register_end');
  2393. return $this->lang->redirect_registered;
  2394. }
  2395. }
  2396. /**
  2397. * Will remove a Forum/Category and everything related to it
  2398. * Taken from admin/modules/forum/management.php
  2399. *
  2400. * @param integer $forum_id ID of Forum/Category
  2401. * @return boolean
  2402. */
  2403. function removeForumOrCategory($forum_id)
  2404. {
  2405. $this->plugins->run_hooks("admin_forum_management_delete");
  2406. $query = $this->db->simple_select("forums", "*", "fid='{$forum_id}'");
  2407. $forum = $this->db->fetch_array($query);
  2408. // Does the forum not exist?
  2409. if (!$forum['fid'])
  2410. {
  2411. return false;
  2412. }
  2413. $fid = intval($forum_id);
  2414. $forum_info = $this->getForum($fid);
  2415. // Delete the forum
  2416. $this->db->delete_query("forums", "fid='$fid'");
  2417. switch ($this->db->type)
  2418. {
  2419. case "pgsql":
  2420. case "sqlite3":
  2421. case "sqlite2":
  2422. $query = $this->db->simple_select("forums", "*", "','|| parentlist|| ',' LIKE '%,$fid,%'");
  2423. break;
  2424. default:
  2425. $query = $this->db->simple_select("forums", "*", "CONCAT(',', parentlist, ',') LIKE '%,$fid,%'");
  2426. }
  2427. while ($forum = $this->db->fetch_array($query))
  2428. {
  2429. $fids[$forum['fid']] = $fid;
  2430. $delquery .= " OR fid='{$forum['fid']}'";
  2431. }
  2432. /**
  2433. * This slab of code pulls out the moderators for this forum,
  2434. * checks if they moderate any other forums, and if they don't
  2435. * it moves them back to the registered usergroup
  2436. */
  2437. $query = $this->db->simple_select("moderators", "*", "fid='$fid'");
  2438. while ($mod = $this->db->fetch_array($query))
  2439. {
  2440. $moderators[$mod['uid']] = $mod['uid'];
  2441. }
  2442. if (is_array($moderators))
  2443. {
  2444. $mod_list = implode(",", $moderators);
  2445. $query = $this->db->simple_select("moderators", "*", "fid != '$fid' AND uid IN ($mod_list)");
  2446. while ($mod = $this->db->fetch_array($query))
  2447. {
  2448. unset($moderators[$mod['uid']]);
  2449. }
  2450. }
  2451. if (is_array($moderators))
  2452. {
  2453. $mod_list = implode(",", $moderators);
  2454. if($mod_list)
  2455. {
  2456. $updatequery = array(
  2457. "usergroup" => "2"
  2458. );
  2459. $this->db->update_query("users", $updatequery, "uid IN ($mod_list) AND usergroup='6'");
  2460. }
  2461. }
  2462. switch($this->db->type)
  2463. {
  2464. case "pgsql":
  2465. case "sqlite3":
  2466. case "sqlite2":
  2467. $this->db->delete_query("forums", "','||parentlist||',' LIKE '%,$fid,%'");
  2468. break;
  2469. default:
  2470. $this->db->delete_query("forums", "CONCAT(',',parentlist,',') LIKE '%,$fid,%'");
  2471. }
  2472. $this->db->delete_query("threads", "fid='{$fid}' {$delquery}");
  2473. $this->db->delete_query("posts", "fid='{$fid}' {$delquery}");
  2474. $this->db->delete_query("moderators", "fid='{$fid}' {$delquery}");
  2475. $this->db->delete_query("forumsubscriptions", "fid='{$fid}' {$delquery}");
  2476. $this->cache->update_forums();
  2477. $this->cache->update_moderators();
  2478. $this->cache->update_forumpermissions();
  2479. // Log admin action - Need to add 2 params in input array so logging contains correct info
  2480. $this->mybb->input['module'] = 'forum/management';
  2481. $this->mybb->input['action'] = 'delete';
  2482. $this->logAdminAction($forum_info['fid'], $forum_info['name']);
  2483. $this->plugins->run_hooks("admin_forum_management_delete_commit");
  2484. return true;
  2485. }
  2486. /**
  2487. * Delete a post
  2488. *
  2489. * @param integer $post_id ID of Post
  2490. * @return ?
  2491. */
  2492. function removePost($post_id)
  2493. {
  2494. require_once MYBB_ROOT."inc/functions_post.php";
  2495. require_once MYBB_ROOT."inc/functions_upload.php";
  2496. $this->lang->load('editpost');
  2497. $post = $this->getPost($post_id);
  2498. $tid = $post['tid'];
  2499. $fid = $post['fid'];
  2500. $pid = $post['pid'];
  2501. $forumpermissions = forum_permissions($fid);
  2502. $this->plugins->run_hooks("editpost_deletepost");
  2503. $query = $this->db->simple_select("posts", "pid", "tid='{$tid}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "asc"));
  2504. $firstcheck = $this->db->fetch_array($query);
  2505. if ($firstcheck['pid'] == $pid)
  2506. {
  2507. $firstpost = 1;
  2508. }
  2509. else
  2510. {
  2511. $firstpost = 0;
  2512. }
  2513. $modlogdata['fid'] = $fid;
  2514. $modlogdata['tid'] = $tid;
  2515. if ($firstpost)
  2516. {
  2517. if ($forumpermissions['candeletethreads'] == 1 || is_moderator($fid, "candeleteposts"))
  2518. {
  2519. delete_thread($tid);
  2520. mark_reports($tid, "thread");
  2521. $this->logModeratorAction($modlogdata, $this->lang->thread_deleted);
  2522. return true;
  2523. }
  2524. else
  2525. {
  2526. return false;
  2527. }
  2528. }
  2529. else
  2530. {
  2531. if ($forumpermissions['candeleteposts'] == 1 || is_moderator($fid, "candeleteposts"))
  2532. {
  2533. // Select the first post before this
  2534. delete_post($pid, $tid);
  2535. mark_reports($pid, "post");
  2536. $this->logModeratorAction($modlogdata, $this->lang->post_deleted);
  2537. $query = $this->db->simple_select("posts", "pid", "tid='{$tid}' AND dateline <= '{$post['dateline']}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "desc"));
  2538. $next_post = $this->db->fetch_array($query);
  2539. return true;
  2540. }
  2541. else
  2542. {
  2543. return false;
  2544. }
  2545. }
  2546. }
  2547. /**
  2548. * Delete a user in the database
  2549. *
  2550. * @param integer $thread Thread ID
  2551. * @return boolean
  2552. */
  2553. function removeThread($thread)
  2554. {
  2555. $tid = intval($thread);
  2556. $this->lang->load('editpost');
  2557. $deleted = delete_thread($tid);
  2558. mark_reports($tid, "thread");
  2559. $modlogdata['tid'] = $tid;
  2560. $this->logModeratorAction($modlogdata, $this->lang->thread_deleted);
  2561. return $deleted;
  2562. }
  2563. /**
  2564. * Delete a user in the database
  2565. *
  2566. * @param integer|string $user User ID or username
  2567. * @return boolean
  2568. */
  2569. function removeUser($user)
  2570. {
  2571. // If no ID is given, we check if there is a user with the specified username
  2572. if (!is_numeric($user))
  2573. {
  2574. $query = $this->db->simple_select('users', 'uid', 'username=\''.$this->dbEscape($user).'\'');
  2575. $user_id = $this->db->fetch_field($query, 'uid', 0);
  2576. // User does not exist? --> False
  2577. if (empty($user_id))
  2578. {
  2579. return false;
  2580. }
  2581. $user_id = intval($user_id);
  2582. }
  2583. else
  2584. {
  2585. $user_id = intval($user);
  2586. }
  2587. $this->plugins->run_hooks('admin_user_users_delete');
  2588. // Delete the user
  2589. $this->db->update_query("posts", array('uid' => 0), "uid='{$user_id}'");
  2590. $this->db->delete_query("userfields", "ufid='{$user_id}'");
  2591. $this->db->delete_query("privatemessages", "uid='{$user_id}'");
  2592. $this->db->delete_query("events", "uid='{$user_id}'");
  2593. $this->db->delete_query("moderators", "uid='{$user_id}'");
  2594. $this->db->delete_query("forumsubscriptions", "uid='{$user_id}'");
  2595. $this->db->delete_query("threadsubscriptions", "uid='{$user_id}'");
  2596. $this->db->delete_query("sessions", "uid='{$user_id}'");
  2597. $this->db->delete_query("banned", "uid='{$user_id}'");
  2598. $this->db->delete_query("threadratings", "uid='{$user_id}'");
  2599. $this->db->delete_query("users", "uid='{$user_id}'");
  2600. $this->db->delete_query("joinrequests", "uid='{$user_id}'");
  2601. $this->db->delete_query("warnings", "uid='{$user_id}'");
  2602. // Update forum stats
  2603. update_stats(array('numusers' => '-1'));
  2604. $this->plugins->run_hooks('admin_user_users_delete_commit');
  2605. return true;
  2606. }
  2607. /**
  2608. * Send a private message from someone to someone
  2609. */
  2610. function sendPrivateMessage($data = array())
  2611. {
  2612. // Let's do default values and check if all required data keys are passed
  2613. $default_data = array(
  2614. 'fromid' => 0,
  2615. 'subject' => '',
  2616. 'message' => '',
  2617. 'icon' => 0,
  2618. 'to_username' => ''
  2619. );
  2620. // Set default values if they are missing!
  2621. foreach ($default_data as $default_data_key => $default_data_val)
  2622. {
  2623. if (!isset($data[$default_data_key]))
  2624. {
  2625. $data[$default_data_key] = $default_data_val;
  2626. }
  2627. }
  2628. $this->lang->load('private');
  2629. $this->plugins->run_hooks('private_send_do_send');
  2630. // Attempt to see if this PM is a duplicate or not
  2631. $time_cutoff = TIME_NOW - (5 * 60 * 60);
  2632. $query = $this->db->query("
  2633. SELECT pm.pmid
  2634. FROM ".TABLE_PREFIX."privatemessages pm
  2635. LEFT JOIN ".TABLE_PREFIX."users u ON(u.uid=pm.toid)
  2636. WHERE u.username='".$this->db->escape_string($data['to_uername'])."' AND pm.dateline > {$time_cutoff} AND pm.fromid='{".$data['fromid']."}' AND pm.subject='".$this->db->escape_string($data['subject'])."' AND pm.message='".$this->db->escape_string($data['message'])."' AND pm.folder!='3'
  2637. ");
  2638. $duplicate_check = $this->db->fetch_field($query, "pmid");
  2639. if ($duplicate_check)
  2640. {
  2641. return $this->lang->error_pm_already_submitted;
  2642. }
  2643. require_once MYBB_ROOT."inc/datahandlers/pm.php";
  2644. $pmhandler = new PMDataHandler();
  2645. // Split up any recipients we have
  2646. $data['to'] = explode(",", $data['to_username']);
  2647. $data['to'] = array_map("trim", $data['to']);
  2648. if (!empty($data['bcc']))
  2649. {
  2650. $data['bcc'] = explode(",", $data['bcc']);
  2651. $data['bcc'] = array_map("trim", $data['bcc']);
  2652. }
  2653. $data['options'] = array(
  2654. "signature" => (isset($data['options']['signature'])) ? $data['options']['signature'] : NULL,
  2655. "disablesmilies" => (isset($data['options']['disablesmilies'])) ? $data['options']['disablesmilies'] : NULL,
  2656. "savecopy" => (isset($data['options']['savecopy'])) ? $data['options']['savecopy'] : NULL,
  2657. "readreceipt" => (isset($data['options']['readreceipt'])) ? $data['options']['readreceipt'] : NULL
  2658. );
  2659. /* Unnecessary
  2660. if($data['saveasdraft'])
  2661. {
  2662. $data['saveasdraft'] = 1;
  2663. } */
  2664. $pmhandler->set_data($data);
  2665. // Now let the pm handler do all the hard work.
  2666. if(!$pmhandler->validate_pm())
  2667. {
  2668. $pm_errors = $pmhandler->get_friendly_errors();
  2669. return inline_error($pm_errors);
  2670. }
  2671. else
  2672. {
  2673. $pminfo = $pmhandler->insert_pm();
  2674. $this->plugins->run_hooks("private_do_send_end");
  2675. if (isset($pminfo['draftsaved']))
  2676. {
  2677. return $this->lang->redirect_pmsaved;
  2678. }
  2679. else
  2680. {
  2681. return $this->lang->redirect_pmsent;
  2682. }
  2683. }
  2684. }
  2685. /**
  2686. * Use built-in set-cookie function of MyBB
  2687. *
  2688. * @param string $name Cookie Name
  2689. * @param mixed $value Cookie Value
  2690. * @param integer $expires Timestamp of Expiry
  2691. * @param boolean Use cookie for HTTP only?
  2692. */
  2693. function setCookie($name, $value = '', $expires = NULL, $httponly = false)
  2694. {
  2695. my_setcookie($name, $value, $expires, $httponly);
  2696. }
  2697. /**
  2698. * Set a new password for a user
  2699. *
  2700. * @param integer User-ID
  2701. * @param string New Password
  2702. * @param boolean Return errors as MyBB array or nicely formated?
  2703. * @return boolean|array
  2704. */
  2705. function updatePasswordOfUser($user_id, $password, $inline_error = true)
  2706. {
  2707. include_once MYBB_ROOT.'inc/functions_user.php';
  2708. require_once MYBB_ROOT.'inc/datahandlers/user.php';
  2709. $userhandler = new UserDataHandler('update');
  2710. $data = array(
  2711. 'uid' => intval($user_id),
  2712. 'password' => $password
  2713. );
  2714. $userhandler->set_data($data);
  2715. if (!$userhandler->validate_user())
  2716. {
  2717. $errors = $userhandler->get_friendly_errors();
  2718. return ($inline_error === true) ? inline_error($errors) : $errors;
  2719. }
  2720. $userhandler->update_user();
  2721. return true;
  2722. }
  2723. /**
  2724. * Update content and information of a single post
  2725. *
  2726. * @param array $data Post-Data
  2727. * @param boolean|array|string $inline_errors Return arrays as array or string or return bool true when all good
  2728. */
  2729. function updatePost($data, $inline_errors)
  2730. {
  2731. require_once MYBB_ROOT.'inc/functions_post.php';
  2732. require_once MYBB_ROOT.'/inc/datahandlers/post.php';
  2733. $posthandler = new PostDataHandler('update');
  2734. $posthandler->action = 'post';
  2735. $this->plugins->run_hooks('editpost_do_editpost_start');
  2736. $posthandler->set_data($data);
  2737. if (!$posthandler->validate_post())
  2738. {
  2739. $errors = $posthandler->get_friendly_errors();
  2740. return ($inline_errors === true) ? inline_error($errors) : $errors;
  2741. }
  2742. $this->plugins->run_hooks('editpost_do_editpost_end');
  2743. return $posthandler->update_post();
  2744. }
  2745. /**
  2746. * Updates a thread in the database
  2747. *
  2748. * @param array $data Thread data
  2749. * @param boolean $inline_errors Defines if we want a formatted error string or an array
  2750. * @return array|string
  2751. * @return array|string When true it will return an array with threadID, postID and status of being visible - false = error array or inline string
  2752. */
  2753. function updateThread($data, $inline_errors = true)
  2754. {
  2755. if (!isset($data['tid']))
  2756. {
  2757. $this->_errorAndDie('Function <i>updateThread</i>: Must pass thread id in array parameter - Required array key is <i>tid</i>');
  2758. }
  2759. // Posthandler is used for a post, so let's fetch the thread-post
  2760. $thread = $this->getThread($data['tid']);
  2761. $data['pid'] = $thread['firstpost'];
  2762. require_once MYBB_ROOT.'inc/functions_post.php';
  2763. require_once MYBB_ROOT.'/inc/datahandlers/post.php';
  2764. $posthandler = new PostDataHandler('update');
  2765. $posthandler->action = 'post';
  2766. $posthandler->set_data($data);
  2767. if (!$posthandler->validate_post())
  2768. {
  2769. $errors = $posthandler->get_friendly_errors();
  2770. return ($inline_errors === true) ? inline_error($errors) : $errors;
  2771. }
  2772. return $posthandler->update_post();
  2773. }
  2774. /**
  2775. * Updates userdata
  2776. *
  2777. * @param array $userdata Data of the User (uid is required as index)
  2778. * @param boolean Return errors as MyBB array or nicely formated?
  2779. * @return boolean|array
  2780. */
  2781. function updateUser($userdata = array(), $inline_error = true)
  2782. {
  2783. // Userdata Array needs to contain the UserID
  2784. if (!isset($userdata['uid']))
  2785. {
  2786. $this->_errorAndDie('A UserID (Array-Key: <i>uid</i>) is required to update a user');
  2787. }
  2788. require_once MYBB_ROOT.'inc/functions_user.php';
  2789. require_once MYBB_ROOT.'inc/datahandlers/user.php';
  2790. $userhandler = new UserDataHandler('update');
  2791. $userhandler->set_data($userdata);
  2792. if (!$userhandler->validate_user())
  2793. {
  2794. $errors = $userhandler->get_friendly_errors();
  2795. return ($inline_error === true) ? inline_error($errors) : $errors;
  2796. }
  2797. $userhandler->update_user();
  2798. return true;
  2799. }
  2800. /**
  2801. * Checks if given captcha is correct
  2802. *
  2803. * @param string $hash Captcha-Hash
  2804. * @param string $string the Letters of the captcha
  2805. * @return boolean
  2806. */
  2807. function validateCaptcha($hash, $string)
  2808. {
  2809. $imagehash = $this->dbEscape($hash);
  2810. $imagestring = $this->dbEscape($string);
  2811. $query = $this->db->simple_select("captcha", "*", "imagehash='{$imagehash}' AND imagestring='{$imagestring}'");
  2812. $imgcheck = $this->db->fetch_array($query);
  2813. if($imgcheck['dateline'] > 0)
  2814. {
  2815. return true;
  2816. }
  2817. else
  2818. {
  2819. $this->db->delete_query("captcha", "imagehash='{$imagehash}'");
  2820. return false;
  2821. }
  2822. }
  2823. /**
  2824. * Perform a vote in a poll
  2825. *
  2826. * @param integer $poll_id ID of Poll
  2827. * @param integer $user_id ID of User
  2828. * @param integer|array Vote option (basically what you vote!) - if multiple, you can define more options in an array
  2829. */
  2830. function vote($poll_id, $user_id = 0, $option = NULL)
  2831. {
  2832. // Load the Language Phrases
  2833. $this->lang->load('polls');
  2834. // A bit sanitizing...
  2835. $poll_id = (int) $poll_id;
  2836. $user_id = (int) $user_id;
  2837. // Let's fetch infos of the poll
  2838. $query = $this->db->simple_select("polls", "*", "pid='".intval($poll_id)."'");
  2839. $poll = $this->db->fetch_array($query);
  2840. $poll['timeout'] = $poll['timeout']*60*60*24;
  2841. $this->plugins->run_hooks("polls_vote_start");
  2842. // Does the poll exist?
  2843. if (!$poll['pid'])
  2844. {
  2845. return $this->lang->error_invalidpoll;
  2846. }
  2847. // Does the poll exist in a valid thread?
  2848. $query = $this->db->simple_select("threads", "*", "poll='".$poll['pid']."'");
  2849. $thread = $this->db->fetch_array($query);
  2850. if (!$thread['tid'])
  2851. {
  2852. return $this->lang->error_invalidthread;
  2853. }
  2854. // Do we have the permissino to vote?
  2855. $fid = $thread['fid'];
  2856. $forumpermissions = forum_permissions($fid);
  2857. if ($forumpermissions['canvotepolls'] == 0)
  2858. {
  2859. return false;
  2860. }
  2861. // Has the poll expired?
  2862. $expiretime = $poll['dateline'] + $poll['timeout'];
  2863. if ($poll['closed'] == 1 || $thread['closed'] == 1 || ($expiretime < TIME_NOW && $poll['timeout']))
  2864. {
  2865. return $this->lang->error_pollclosed;
  2866. }
  2867. // Did we pass an option to vote for?
  2868. if (empty($option))
  2869. {
  2870. return $this->lang->error_nopolloptions;
  2871. }
  2872. // Check if the user has voted before...
  2873. if ($user_id > 0)
  2874. {
  2875. $query = $this->db->simple_select("pollvotes", "*", "uid='".$user_id."' AND pid='".$poll['pid']."'");
  2876. $votecheck = $this->db->fetch_array($query);
  2877. }
  2878. if ($votecheck['vid'] || $this->mybb->cookies['pollvotes'][$poll['pid']])
  2879. {
  2880. return $this->lang->error_alreadyvoted;
  2881. }
  2882. elseif ($user_id == 0)
  2883. {
  2884. // Give a cookie to guests to inhibit revotes
  2885. my_setcookie("pollvotes[{$poll['pid']}]", '1');
  2886. }
  2887. $votesql = '';
  2888. $votesarray = explode("||~|~||", $poll['votes']);
  2889. $numvotes = $poll['numvotes'];
  2890. if ($poll['multiple'] == 1)
  2891. {
  2892. foreach ($option as $voteoption => $vote)
  2893. {
  2894. if ($vote == 1 && isset($votesarray[$voteoption-1]))
  2895. {
  2896. if ($votesql)
  2897. {
  2898. $votesql .= ",";
  2899. }
  2900. $votesql .= "('".$poll['pid']."','".$user_id."','".$this->db->escape_string($voteoption)."', ".TIME_NOW.")";
  2901. $votesarray[$voteoption-1]++;
  2902. $numvotes = $numvotes+1;
  2903. }
  2904. }
  2905. }
  2906. else
  2907. {
  2908. if (!isset($votesarray[$option-1]))
  2909. {
  2910. return $this->lang->error_nopolloptions;
  2911. }
  2912. $votesql = "('".$poll['pid']."','".$user_id."','".$this->db->escape_string($option)."', ".TIME_NOW.")";
  2913. $votesarray[$option-1]++;
  2914. $numvotes = $numvotes+1;
  2915. }
  2916. // Save the fact that we voted
  2917. $this->db->write_query("
  2918. INSERT INTO
  2919. ".TABLE_PREFIX."pollvotes (pid,uid,voteoption,dateline)
  2920. VALUES $votesql
  2921. ");
  2922. $voteslist = '';
  2923. for ($i = 1; $i <= $poll['numoptions']; ++$i)
  2924. {
  2925. if ($i > 1)
  2926. {
  2927. $voteslist .= "||~|~||";
  2928. }
  2929. $voteslist .= $votesarray[$i-1];
  2930. }
  2931. $updatedpoll = array(
  2932. "votes" => $this->db->escape_string($voteslist),
  2933. "numvotes" => intval($numvotes),
  2934. );
  2935. $this->plugins->run_hooks("polls_vote_process");
  2936. $this->db->update_query("polls", $updatedpoll, "pid='".$poll['pid']."'");
  2937. $this->plugins->run_hooks("polls_vote_end");
  2938. return true;
  2939. }
  2940. }
  2941. ?>