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

/upload/includes/functions.php

http://torrentpier2.googlecode.com/
PHP | 2954 lines | 2350 code | 343 blank | 261 comment | 394 complexity | 549746820059d5ae3ae502a7fff17e21 MD5 | raw file
  1. <?php
  2. if (!defined('BB_ROOT')) die(basename(__FILE__));
  3. function get_path_from_id ($id, $ext_id, $base_path, $first_div, $sec_div)
  4. {
  5. global $bb_cfg;
  6. $ext = isset($bb_cfg['file_id_ext'][$ext_id]) ? $bb_cfg['file_id_ext'][$ext_id] : '';
  7. return ($base_path ? "$base_path/" : '') . floor($id/$first_div) .'/'. ($id % $sec_div) .'/'. $id . ($ext ? ".$ext" : '');
  8. }
  9. function get_avatar_path ($id, $ext_id, $base_path = '')
  10. {
  11. return get_path_from_id($id, $ext_id, $base_path, 5000000, 100);
  12. }
  13. function delete_avatar ($user_id, $avatar_ext_id)
  14. {
  15. global $bb_cfg;
  16. $avatar_file = ($avatar_ext_id) ? get_avatar_path($user_id, $avatar_ext_id, $bb_cfg['avatars']['upload_path']) : '';
  17. return ($avatar_file && file_exists($avatar_file)) ? @unlink($avatar_file) : false;
  18. }
  19. function get_attach_path ($id)
  20. {
  21. global $bb_cfg;
  22. return get_path_from_id($id, '', $bb_cfg['attach']['upload_path'], 1000000, 100);
  23. }
  24. function get_tracks ($type)
  25. {
  26. static $pattern = '#^a:\d+:{[i:;\d]+}$#';
  27. switch ($type)
  28. {
  29. case 'topic':
  30. $c_name = COOKIE_TOPIC;
  31. break;
  32. case 'forum':
  33. $c_name = COOKIE_FORUM;
  34. break;
  35. case 'pm':
  36. $c_name = COOKIE_PM;
  37. break;
  38. default:
  39. trigger_error(__FUNCTION__ .": invalid type '$type'", E_USER_ERROR);
  40. }
  41. $tracks = !empty($_COOKIE[$c_name]) ? @unserialize($_COOKIE[$c_name]) : false;
  42. return ($tracks) ? $tracks : array();
  43. }
  44. function set_tracks ($cookie_name, &$tracking_ary, $tracks = null, $val = TIMENOW)
  45. {
  46. global $tracking_topics, $tracking_forums, $user;
  47. if (IS_GUEST) return;
  48. $prev_tracking_ary = $tracking_ary;
  49. if ($tracks)
  50. {
  51. if (!is_array($tracks))
  52. {
  53. $tracks = array($tracks => $val);
  54. }
  55. foreach ($tracks as $key => $val)
  56. {
  57. $key = (int) $key;
  58. $val++;
  59. $curr_track_val = !empty($tracking_ary[$key]) ? $tracking_ary[$key] : 0;
  60. if ($val > max($curr_track_val, $user->data['user_lastvisit']))
  61. {
  62. $tracking_ary[$key] = $val;
  63. }
  64. elseif ($curr_track_val < $user->data['user_lastvisit'])
  65. {
  66. unset($tracking_ary[$key]);
  67. }
  68. }
  69. }
  70. $overflow = count($tracking_topics) + count($tracking_forums) - COOKIE_MAX_TRACKS;
  71. if ($overflow > 0)
  72. {
  73. arsort($tracking_ary);
  74. for ($i=0; $i < $overflow; $i++)
  75. {
  76. array_pop($tracking_ary);
  77. }
  78. }
  79. if (array_diff($tracking_ary, $prev_tracking_ary))
  80. {
  81. bb_setcookie($cookie_name, serialize($tracking_ary));
  82. }
  83. }
  84. function get_last_read ($topic_id = 0, $forum_id = 0)
  85. {
  86. global $tracking_topics, $tracking_forums, $user;
  87. $t = isset($tracking_topics[$topic_id]) ? $tracking_topics[$topic_id] : 0;
  88. $f = isset($tracking_forums[$forum_id]) ? $tracking_forums[$forum_id] : 0;
  89. return max($t, $f, $user->data['user_lastvisit']);
  90. }
  91. function is_unread ($ref, $topic_id = 0, $forum_id = 0)
  92. {
  93. return (!IS_GUEST && $ref > get_last_read($topic_id, $forum_id));
  94. }
  95. //
  96. // Ads
  97. //
  98. class ads_common
  99. {
  100. var $ad_blocks = array();
  101. var $active_ads = array();
  102. /**
  103. * Constructor
  104. */
  105. function ads_common ()
  106. {
  107. global $bb_cfg;
  108. $this->ad_blocks =& $bb_cfg['ad_blocks'];
  109. $this->active_ads = !empty($bb_cfg['active_ads']) ? unserialize($bb_cfg['active_ads']) : array();
  110. }
  111. /**
  112. * Get ads to show for each block
  113. */
  114. function get ($block_types)
  115. {
  116. $ads = array();
  117. if ($this->active_ads)
  118. {
  119. $block_ids = $this->get_block_ids($block_types);
  120. if ($ad_ids = $this->get_ad_ids($block_ids))
  121. {
  122. $ad_html = $this->get_ads_html();
  123. foreach ($ad_ids as $block_id => $ad_id)
  124. {
  125. $ads[$block_id] =& $ad_html[$ad_id];
  126. }
  127. }
  128. }
  129. return $ads;
  130. }
  131. /**
  132. * Get ads html
  133. */
  134. function get_ads_html ()
  135. {
  136. global $datastore;
  137. if (!$ads_html = $datastore->get('ads'))
  138. {
  139. $datastore->update('ads');
  140. $ads_html = $datastore->get('ads');
  141. }
  142. return $ads_html;
  143. }
  144. /**
  145. * Get block_ids for specified block_types
  146. */
  147. function get_block_ids ($block_types)
  148. {
  149. $block_ids = array();
  150. foreach ($block_types as $block_type)
  151. {
  152. if ($blocks =& $this->ad_blocks[$block_type])
  153. {
  154. $block_ids = array_merge($block_ids, array_keys($blocks));
  155. }
  156. }
  157. return $block_ids;
  158. }
  159. /**
  160. * Get ad_ids for specified blocks
  161. */
  162. function get_ad_ids ($block_ids)
  163. {
  164. $ad_ids = array();
  165. foreach ($block_ids as $block_id)
  166. {
  167. if ($ads =& $this->active_ads[$block_id])
  168. {
  169. shuffle($ads);
  170. $ad_ids[$block_id] = $ads[0];
  171. }
  172. }
  173. return $ad_ids;
  174. }
  175. }
  176. //
  177. // Auth
  178. //
  179. define('AUTH_LIST_ALL', 0);
  180. // forum's ACL types (bb_forums: auth_view, auth_read... values)
  181. define('AUTH_REG', 1);
  182. define('AUTH_ACL', 2);
  183. define('AUTH_ADMIN', 5);
  184. // forum_perm bitfields - backward compatible with auth($type)
  185. define('AUTH_ALL', 0);
  186. define('AUTH_VIEW', 1);
  187. define('AUTH_READ', 2);
  188. define('AUTH_MOD', 3);
  189. define('AUTH_POST', 4);
  190. define('AUTH_REPLY', 5);
  191. define('AUTH_EDIT', 6);
  192. define('AUTH_DELETE', 7);
  193. define('AUTH_STICKY', 8);
  194. define('AUTH_ANNOUNCE', 9);
  195. define('AUTH_VOTE', 10);
  196. define('AUTH_POLLCREATE', 11);
  197. define('AUTH_ATTACH', 12);
  198. define('AUTH_DOWNLOAD', 13);
  199. define('BF_AUTH_MOD', bit2dec(AUTH_MOD));
  200. // When defining user permissions, take into account:
  201. define('UG_PERM_BOTH', 1); // both user and group
  202. define('UG_PERM_USER_ONLY', 2); // only personal user permissions
  203. define('UG_PERM_GROUP_ONLY', 3); // only group permissions
  204. $bf['forum_perm'] = array(
  205. 'auth_view' => AUTH_VIEW,
  206. 'auth_read' => AUTH_READ,
  207. 'auth_mod' => AUTH_MOD,
  208. 'auth_post' => AUTH_POST,
  209. 'auth_reply' => AUTH_REPLY,
  210. 'auth_edit' => AUTH_EDIT,
  211. 'auth_delete' => AUTH_DELETE,
  212. 'auth_sticky' => AUTH_STICKY,
  213. 'auth_announce' => AUTH_ANNOUNCE,
  214. 'auth_vote' => AUTH_VOTE,
  215. 'auth_pollcreate' => AUTH_POLLCREATE,
  216. 'auth_attachments' => AUTH_ATTACH,
  217. 'auth_download' => AUTH_DOWNLOAD,
  218. );
  219. $bf['user_opt'] = array(
  220. 'viewemail' => 0, // ?????????? e-mail
  221. 'allow_sig' => 1, // ?????? ?? ???????
  222. 'allow_avatar' => 2, // ?????? ?? ??????
  223. 'allow_pm' => 3, // ?????? ?? ???????? ??
  224. 'allow_viewonline' => 4, // ???????? ?????????? ????????????
  225. 'notify' => 5, // ???????? ?? ??????? ? ????????????? ?????
  226. 'notify_pm' => 6, // ???????? ? ????? ??
  227. 'allow_passkey' => 7, // ?????? ?? ?????????? passkey, ?? ?? ?????? ?? ?????????? ?????????
  228. 'hide_porn_forums' => 8, // ???????? pron ??????
  229. 'allow_gallery' => 9, // ?????????????? (?????? ????????????? ???????)
  230. 'hide_ads' => 10, // ?????? ?? ????? ???????
  231. 'allow_topic' => 11, // ?????? ?? ???????? ????? ???
  232. 'allow_post' => 12, // ?????? ?? ???????? ?????????
  233. 'allow_post_edit' => 13, // ?????? ?? ?????????????? ?????????
  234. 'allow_dls' => 14, // ?????? ?? ?????? ??????? ??????? ? ???????
  235. );
  236. function bit2dec ($bit_num)
  237. {
  238. if (is_array($bit_num))
  239. {
  240. $dec = 0;
  241. foreach ($bit_num as $bit)
  242. {
  243. $dec |= (1 << $bit);
  244. }
  245. return $dec;
  246. }
  247. return (1 << $bit_num);
  248. }
  249. function bf_bit2dec ($bf_array_name, $key)
  250. {
  251. global $bf;
  252. if (!isset($bf[$bf_array_name][$key]))
  253. {
  254. trigger_error(__FUNCTION__ .": bitfield '$key' not found", E_USER_ERROR);
  255. }
  256. return (1 << $bf[$bf_array_name][$key]);
  257. }
  258. function bf ($int, $bf_array_name, $key)
  259. {
  260. return (bf_bit2dec($bf_array_name, $key) & (int) $int);
  261. }
  262. function setbit (&$int, $bit_num, $on)
  263. {
  264. return ($on) ? $int |= (1 << $bit_num) : $int &= ~(1 << $bit_num);
  265. }
  266. /*
  267. $type's accepted (pre-pend with AUTH_):
  268. VIEW, READ, POST, REPLY, EDIT, DELETE, STICKY, ANNOUNCE, VOTE, POLLCREATE
  269. Possible options ($type/forum_id combinations):
  270. * If you include a type and forum_id then a specific lookup will be done and
  271. the single result returned
  272. * If you set type to AUTH_ALL and specify a forum_id an array of all auth types
  273. will be returned
  274. * If you provide a forum_id a specific lookup on that forum will be done
  275. * If you set forum_id to AUTH_LIST_ALL and specify a type an array listing the
  276. results for all forums will be returned
  277. * If you set forum_id to AUTH_LIST_ALL and type to AUTH_ALL a multidimensional
  278. array containing the auth permissions for all types and all forums for that
  279. user is returned
  280. All results are returned as associative arrays, even when a single auth type is
  281. specified.
  282. If available you can send an array (either one or two dimensional) containing the
  283. forum auth levels, this will prevent the auth function having to do its own
  284. lookup
  285. */
  286. function auth ($type, $forum_id, $ug_data, $f_access = array(), $group_perm = UG_PERM_BOTH)
  287. {
  288. global $lang, $bf, $datastore;
  289. $is_guest = true;
  290. $is_admin = false;
  291. $auth = $auth_fields = $u_access = array();
  292. $add_auth_type_desc = ($forum_id != AUTH_LIST_ALL);
  293. //
  294. // Get $auth_fields
  295. //
  296. if ($type == AUTH_ALL)
  297. {
  298. $auth_fields = array_keys($bf['forum_perm']);
  299. }
  300. else if ($auth_type = array_search($type, $bf['forum_perm']))
  301. {
  302. $auth_fields = array($auth_type);
  303. }
  304. if (empty($auth_fields))
  305. {
  306. trigger_error(__FUNCTION__ .'(): empty $auth_fields', E_USER_ERROR);
  307. }
  308. //
  309. // Get $f_access
  310. //
  311. // If f_access has been passed, or auth is needed to return an array of forums
  312. // then we need to pull the auth information on the given forum (or all forums)
  313. if (empty($f_access))
  314. {
  315. if (!$forums = $datastore->get('cat_forums'))
  316. {
  317. $datastore->update('cat_forums');
  318. $forums = $datastore->get('cat_forums');
  319. }
  320. if ($forum_id == AUTH_LIST_ALL)
  321. {
  322. $f_access = $forums['f'];
  323. }
  324. else if (isset($forums['f'][$forum_id]))
  325. {
  326. $f_access[$forum_id] = $forums['f'][$forum_id];
  327. }
  328. }
  329. else if (isset($f_access['forum_id']))
  330. {
  331. // Change passed $f_access format for later using in foreach()
  332. $f_access = array($f_access['forum_id'] => $f_access);
  333. }
  334. if (empty($f_access))
  335. {
  336. trigger_error(__FUNCTION__ .'(): empty $f_access', E_USER_ERROR);
  337. }
  338. //
  339. // Get user or group permissions
  340. //
  341. $forum_match_sql = ($forum_id != AUTH_LIST_ALL) ? "AND aa.forum_id = ". (int) $forum_id : '';
  342. // GROUP mode
  343. if (!empty($ug_data['group_id']))
  344. {
  345. $is_guest = false;
  346. $is_admin = false;
  347. $sql = "SELECT aa.forum_id, aa.forum_perm
  348. FROM ". BB_AUTH_ACCESS ." aa
  349. WHERE aa.group_id = ". (int) $ug_data['group_id'] ."
  350. $forum_match_sql";
  351. foreach (DB()->fetch_rowset($sql) as $row)
  352. {
  353. $u_access[$row['forum_id']] = $row['forum_perm'];
  354. }
  355. }
  356. // USER mode
  357. else if (!empty($ug_data['user_id']))
  358. {
  359. $is_guest = empty($ug_data['session_logged_in']);
  360. $is_admin = (!$is_guest && $ug_data['user_level'] == ADMIN);
  361. if ($group_perm != UG_PERM_BOTH)
  362. {
  363. $group_single_user = ($group_perm == UG_PERM_USER_ONLY) ? 1 : 0;
  364. $sql = "
  365. SELECT
  366. aa.forum_id, BIT_OR(aa.forum_perm) AS forum_perm
  367. FROM
  368. ". BB_USER_GROUP ." ug,
  369. ". BB_GROUPS ." g,
  370. ". BB_AUTH_ACCESS ." aa
  371. WHERE
  372. ug.user_id = ". (int) $ug_data['user_id'] ."
  373. AND ug.user_pending = 0
  374. AND g.group_id = ug.group_id
  375. AND g.group_single_user = $group_single_user
  376. AND aa.group_id = g.group_id
  377. $forum_match_sql
  378. GROUP BY aa.forum_id
  379. ";
  380. foreach (DB()->fetch_rowset($sql) as $row)
  381. {
  382. $u_access[$row['forum_id']] = $row['forum_perm'];
  383. }
  384. }
  385. else
  386. {
  387. if (!$is_guest && !$is_admin)
  388. {
  389. $sql = "SELECT SQL_CACHE aa.forum_id, aa.forum_perm
  390. FROM ". BB_AUTH_ACCESS_SNAP ." aa
  391. WHERE aa.user_id = ". (int) $ug_data['user_id'] ."
  392. $forum_match_sql";
  393. foreach (DB()->fetch_rowset($sql) as $row)
  394. {
  395. $u_access[$row['forum_id']] = $row['forum_perm'];
  396. }
  397. }
  398. }
  399. }
  400. // If the user is logged on and the forum type is either ALL or REG then the user has access
  401. //
  402. // If the type if ACL, MOD or ADMIN then we need to see if the user has specific permissions
  403. // to do whatever it is they want to do ... to do this we pull relevant information for the
  404. // user (and any groups they belong to)
  405. //
  406. // Now we compare the users access level against the forums. We assume here that a moderator
  407. // and admin automatically have access to an ACL forum, similarly we assume admins meet an
  408. // auth requirement of MOD
  409. //
  410. foreach ($f_access as $f_id => $f_data)
  411. {
  412. $auth[$f_id]['auth_mod'] = auth_check('forum_perm', 'auth_mod', $u_access, $f_id, $is_admin);
  413. foreach ($auth_fields as $auth_type)
  414. {
  415. if (!isset($f_data[$auth_type]))
  416. {
  417. continue;
  418. }
  419. switch ($f_data[$auth_type])
  420. {
  421. case AUTH_ALL:
  422. $auth[$f_id][$auth_type] = true;
  423. break;
  424. case AUTH_REG:
  425. $auth[$f_id][$auth_type] = !$is_guest;
  426. break;
  427. case AUTH_ACL:
  428. $auth[$f_id][$auth_type] = (auth_check('forum_perm', $auth_type, $u_access, $f_id, $is_admin) || $auth[$f_id]['auth_mod']);
  429. break;
  430. case AUTH_MOD:
  431. $auth[$f_id][$auth_type] = $auth[$f_id]['auth_mod'];
  432. break;
  433. case AUTH_ADMIN:
  434. $auth[$f_id][$auth_type] = $is_admin;
  435. break;
  436. default:
  437. $auth[$f_id][$auth_type] = false;
  438. }
  439. if ($add_auth_type_desc)
  440. {
  441. $auth[$f_id][$auth_type .'_type'] =& $lang['AUTH_TYPES'][$f_data[$auth_type]];
  442. }
  443. }
  444. }
  445. return ($forum_id == AUTH_LIST_ALL) ? $auth : $auth[$forum_id];
  446. }
  447. function auth_check ($bf_ary, $bf_key, $perm_ary, $perm_key, $is_admin = false)
  448. {
  449. if ($is_admin) return true;
  450. if (!isset($perm_ary[$perm_key])) return false;
  451. return bf($perm_ary[$perm_key], $bf_ary, $bf_key);
  452. }
  453. class Date_Delta
  454. {
  455. var $auto_granularity = array(
  456. 60 => 'seconds', // set granularity to "seconds" if delta less then 1 minute
  457. 10800 => 'minutes', // 3 hours
  458. 259200 => 'hours', // 3 days
  459. 31363200 => 'mday', // 12 months
  460. 311040000 => 'mon', // 10 years
  461. );
  462. var $intervals = array();
  463. var $format = '';
  464. // Creates new object.
  465. function Date_Delta()
  466. {
  467. global $lang;
  468. $this->intervals = $lang['DELTA_TIME']['INTERVALS'];
  469. $this->format = $lang['DELTA_TIME']['FORMAT'];
  470. }
  471. // Makes the spellable phrase.
  472. function spellDelta($first, $last, $from = 'auto')
  473. {
  474. if ($last < $first)
  475. {
  476. $old_first = $first;
  477. $first = $last;
  478. $last = $old_first;
  479. }
  480. if ($from == 'auto')
  481. {
  482. $from = 'year';
  483. $diff = $last - $first;
  484. foreach ($this->auto_granularity as $seconds_count => $granule)
  485. {
  486. if ($diff < $seconds_count)
  487. {
  488. $from = $granule;
  489. break;
  490. }
  491. }
  492. }
  493. // Solve data delta.
  494. $delta = $this->getDelta($first, $last);
  495. if (!$delta) return false;
  496. // Make spellable phrase.
  497. $parts = array();
  498. $intervals = $GLOBALS['lang']['DELTA_TIME']['INTERVALS'];
  499. foreach (array_reverse($delta) as $k => $n)
  500. {
  501. if (!$n)
  502. {
  503. if ($k == $from)
  504. {
  505. if (!$parts)
  506. {
  507. $parts[] = declension($n, $this->intervals[$k], $this->format);
  508. }
  509. break;
  510. }
  511. continue;
  512. }
  513. $parts[] = declension($n, $this->intervals[$k], $this->format);
  514. if ($k == $from) break;
  515. }
  516. return join(' ', $parts);
  517. }
  518. // returns the associative array with date deltas.
  519. function getDelta($first, $last)
  520. {
  521. if ($last < $first) return false;
  522. // Solve H:M:S part.
  523. $hms = ($last - $first) % (3600 * 24);
  524. $delta['seconds'] = $hms % 60;
  525. $delta['minutes'] = floor($hms/60) % 60;
  526. $delta['hours'] = floor($hms/3600) % 60;
  527. // Now work only with date, delta time = 0.
  528. $last -= $hms;
  529. $f = getdate($first);
  530. $l = getdate($last); // the same daytime as $first!
  531. $dYear = $dMon = $dDay = 0;
  532. // Delta day. Is negative, month overlapping.
  533. $dDay += $l['mday'] - $f['mday'];
  534. if ($dDay < 0) {
  535. $monlen = $this->monthLength(date('Y', $first), date('m', $first));
  536. $dDay += $monlen;
  537. $dMon--;
  538. }
  539. $delta['mday'] = $dDay;
  540. // Delta month. If negative, year overlapping.
  541. $dMon += $l['mon'] - $f['mon'];
  542. if ($dMon < 0) {
  543. $dMon += 12;
  544. $dYear --;
  545. }
  546. $delta['mon'] = $dMon;
  547. // Delta year.
  548. $dYear += $l['year'] - $f['year'];
  549. $delta['year'] = $dYear;
  550. return $delta;
  551. }
  552. // Returns the length (in days) of the specified month.
  553. function monthLength($year, $mon)
  554. {
  555. $l = 28;
  556. while (checkdate($mon, $l+1, $year)) $l++;
  557. return $l;
  558. }
  559. }
  560. function delta_time ($timestamp_1, $timestamp_2 = TIMENOW, $granularity = 'auto')
  561. {
  562. return $GLOBALS['DeltaTime']->spellDelta($timestamp_1, $timestamp_2, $granularity);
  563. }
  564. function get_select ($select, $selected = null, $return_as = 'html', $first_opt = '&raquo;&raquo; ??????? ')
  565. {
  566. $select_ary = array();
  567. switch ($select)
  568. {
  569. case 'groups':
  570. $sql = "SELECT group_id, group_name FROM ". BB_GROUPS ." WHERE group_single_user = 0 ORDER BY group_name";
  571. foreach (DB()->fetch_rowset($sql) as $row)
  572. {
  573. $select_ary[$row['group_name']] = $row['group_id'];
  574. }
  575. $select_name = 'g';
  576. break;
  577. case 'forum_tpl':
  578. $sql = "SELECT tpl_id, tpl_name FROM ". BB_TOPIC_TPL ." ORDER BY tpl_name";
  579. $select_ary[$first_opt] = 0;
  580. foreach (DB()->fetch_rowset($sql) as $row)
  581. {
  582. $select_ary[$row['tpl_name']] = $row['tpl_id'];
  583. }
  584. $select_name = 'forum_tpl_select';
  585. break;
  586. }
  587. return ($return_as == 'html') ? build_select($select_name, $select_ary, $selected) : $select_ary;
  588. }
  589. class html_common
  590. {
  591. var $options = '';
  592. var $attr = array();
  593. var $cur_attr = null;
  594. var $max_length = HTML_SELECT_MAX_LENGTH;
  595. var $selected = array();
  596. function build_select ($name, $params, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '')
  597. {
  598. if (empty($params)) return '';
  599. $this->options = '';
  600. $this->selected = array_flip((array) $selected);
  601. $this->max_length = $max_length;
  602. $this->attr = array();
  603. $this->cur_attr =& $this->attr;
  604. if (isset($params['__attributes']))
  605. {
  606. $this->attr = $params['__attributes'];
  607. unset($params['__attributes']);
  608. }
  609. $this->_build_select_rec($params);
  610. $select_params = ($js) ? " $js" : '';
  611. $select_params .= ($multiple_size) ? ' multiple="multiple" size="'. $multiple_size .'"' : '';
  612. $select_params .= ' name="'. htmlCHR($name) .'"';
  613. $select_params .= ' id="'. htmlCHR($name) .'"';
  614. return "\n<select $select_params>\n". $this->options ."</select>\n";
  615. }
  616. function _build_select_rec ($params)
  617. {
  618. foreach ($params as $opt_name => $opt_val)
  619. {
  620. $opt_name = rtrim($opt_name);
  621. if (is_array($opt_val))
  622. {
  623. $this->cur_attr =& $this->cur_attr[$opt_name];
  624. $label = htmlCHR(str_short($opt_name, $this->max_length));
  625. $this->options .= "\t<optgroup label=\"&nbsp;". $label ."\">\n";
  626. $this->_build_select_rec($opt_val);
  627. $this->options .= "\t</optgroup>\n";
  628. $this->cur_attr =& $this->attr;
  629. }
  630. else
  631. {
  632. $text = htmlCHR(str_short($opt_name, $this->max_length));
  633. $value = ' value="'. htmlCHR($opt_val) .'"';
  634. $class = isset($this->cur_attr[$opt_name]['class']) ? ' class="'. $this->cur_attr[$opt_name]['class'] .'"' : '';
  635. $style = isset($this->cur_attr[$opt_name]['style']) ? ' style="'. $this->cur_attr[$opt_name]['style'] .'"' : '';
  636. $selected = isset($this->selected[$opt_val]) ? HTML_SELECTED : '';
  637. $disabled = isset($this->cur_attr[$opt_name]['disabled']) ? HTML_DISABLED : '';
  638. $this->options .= "\t\t<option". $class . $style . $selected . $disabled . $value .'>&nbsp;'. $text ."&nbsp;</option>\n";
  639. }
  640. }
  641. }
  642. function array2html ($array, $ul = 'ul', $li = 'li')
  643. {
  644. $this->out = '';
  645. $this->_array2html_rec($array, $ul, $li);
  646. return "<$ul class=\"tree-root\">{$this->out}</$ul>";
  647. }
  648. function _array2html_rec ($array, $ul, $li)
  649. {
  650. foreach ($array as $k => $v)
  651. {
  652. if (is_array($v))
  653. {
  654. $this->out .= "<$li><span class=\"b\">$k</span><$ul>";
  655. $this->_array2html_rec($v, $ul, $li);
  656. $this->out .= "</$ul></$li>";
  657. }
  658. else
  659. {
  660. $this->out .= "<$li><span>$v</span></$li>";
  661. }
  662. }
  663. }
  664. // all arguments should be already htmlspecialchar()d (if needed)
  665. function build_checkbox ($name, $title, $checked = false, $disabled = false, $class = null, $id = null, $value = 1)
  666. {
  667. $name = ' name="'. $name .'" ';
  668. $value = ' value="'. $value .'" ';
  669. $title = ($class) ? '<span class="'. $class .'">'. $title .'</span>' : $title;
  670. $id = ($id) ? " id=\"$id\" " : '';
  671. $checked = ($checked) ? HTML_CHECKED : '';
  672. $disabled = ($disabled) ? HTML_DISABLED : '';
  673. return '<label><input type="checkbox" '. $id . $name . $value . $checked . $disabled .' />&nbsp;'. $title .'&nbsp;</label>';
  674. }
  675. # function build_option ($opt_name, $opt_val, $selected = null, $max_length = false)
  676. # {
  677. # return "\t\t<option value=\"". htmlCHR($opt_val) .'"'. (($selected) ? ' selected="selected"' : '') .'>'. htmlCHR(str_short($opt_name, $max_length)) ."</option>\n";
  678. # }
  679. # function build_optgroup ($label, $contents, $max_length = false)
  680. # {
  681. # return "\t<optgroup label=\"&nbsp;". htmlCHR(str_short($label, $max_length)) ."\">\n". $contents ."\t</optgroup>\n";
  682. # }
  683. }
  684. function build_select ($name, $params, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '')
  685. {
  686. global $html;
  687. return $html->build_select($name, $params, $selected, $max_length, $multiple_size, $js);
  688. }
  689. function build_checkbox ($name, $title, $checked = false, $disabled = false, $class = null, $id = null, $value = 1)
  690. {
  691. global $html;
  692. return $html->build_checkbox($name, $title, $checked, $disabled, $class, $id, $value);
  693. }
  694. function replace_quote ($str, $double = true, $single = true)
  695. {
  696. if ($double) $str = str_replace('"', '&quot;', $str);
  697. if ($single) $str = str_replace("'", '&#039;', $str);
  698. return $str;
  699. }
  700. /**
  701. * Build simple hidden fields from array
  702. */
  703. function build_hidden_fields ($fields_ary)
  704. {
  705. $out = "\n";
  706. foreach ($fields_ary as $name => $val)
  707. {
  708. if (is_array($val))
  709. {
  710. foreach ($val as $ary_key => $ary_val)
  711. {
  712. $out .= '<input type="hidden" name="'. $name .'['. $ary_key .']" value="'. $ary_val ."\" />\n";
  713. }
  714. }
  715. else
  716. {
  717. $out .= '<input type="hidden" name="'. $name .'" value="'. $val ."\" />\n";
  718. }
  719. }
  720. return $out;
  721. }
  722. /**
  723. * Choost russian word declension based on numeric [from dklab.ru]
  724. * Example for $expressions: array("?????", "??????", "???????")
  725. */
  726. function declension ($int, $expressions, $format = '%1$s %2$s')
  727. {
  728. if (!is_array($expressions))
  729. {
  730. $expressions = $GLOBALS['lang']['DECLENSION'][strtoupper($expressions)];
  731. }
  732. if (count($expressions) < 3)
  733. {
  734. $expressions[2] = $expressions[1];
  735. }
  736. $count = intval($int) % 100;
  737. if ($count >= 5 && $count <= 20)
  738. {
  739. $result = $expressions['2'];
  740. }
  741. else
  742. {
  743. $count = $count % 10;
  744. if ($count == 1)
  745. {
  746. $result = $expressions['0'];
  747. }
  748. elseif ($count >= 2 && $count <= 4)
  749. {
  750. $result = $expressions['1'];
  751. }
  752. else
  753. {
  754. $result = $expressions['2'];
  755. }
  756. }
  757. return ($format) ? sprintf($format, $int, $result) : $result;
  758. }
  759. // http://forum.dklab.ru/php/advises/UrlreplaceargChangesValueOfParameterInUrl.html
  760. function url_arg ($url, $arg, $value, $amp = '&amp;')
  761. {
  762. $arg = preg_quote($arg, '/');
  763. // ????????? URL ? ANCHOR
  764. $anchor = '';
  765. if (preg_match('/(.*)(#.*)/s', $url, $m))
  766. {
  767. $url = $m[1];
  768. $anchor = $m[2];
  769. }
  770. // ???????? ????????, ???? ?? ??????????
  771. if (preg_match("/((\?|&|&amp;)$arg=)[^&]*/s", $url, $m))
  772. {
  773. $cur = $m[0];
  774. $new = is_null($value) ? '' : $m[1] . urlencode($value);
  775. $url = str_replace($cur, $new, $url);
  776. }
  777. // ????????? ????????
  778. else if (!is_null($value))
  779. {
  780. $div = (strpos($url, '?') !== false) ? $amp : '?';
  781. $url = $url . $div . $arg .'='. urlencode($value);
  782. }
  783. return $url . $anchor;
  784. }
  785. /**
  786. * Adds commas between every group of thousands
  787. */
  788. function commify ($number)
  789. {
  790. return number_format($number);
  791. }
  792. /**
  793. * Returns a size formatted in a more human-friendly format, rounded to the nearest GB, MB, KB..
  794. */
  795. function humn_size ($size, $rounder = null, $min = null, $space = '&nbsp;')
  796. {
  797. static $sizes = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
  798. static $rounders = array(0, 0, 0, 2, 3, 3, 3, 3, 3);
  799. $size = (float) $size;
  800. $ext = $sizes[0];
  801. $rnd = $rounders[0];
  802. if ($min == 'KB' && $size < 1024)
  803. {
  804. $size = $size / 1024;
  805. $ext = 'KB';
  806. $rounder = 1;
  807. }
  808. else
  809. {
  810. for ($i=1, $cnt=count($sizes); ($i < $cnt && $size >= 1024); $i++)
  811. {
  812. $size = $size / 1024;
  813. $ext = $sizes[$i];
  814. $rnd = $rounders[$i];
  815. }
  816. }
  817. if (!$rounder)
  818. {
  819. $rounder = $rnd;
  820. }
  821. return round($size, $rounder) . $space . $ext;
  822. }
  823. function bt_show_ip ($ip, $port = '')
  824. {
  825. global $bb_cfg;
  826. if (IS_AM)
  827. {
  828. $ip = decode_ip($ip);
  829. $ip .= ($port) ? ":$port" : '';
  830. return $ip;
  831. }
  832. else
  833. {
  834. return ($bb_cfg['bt_show_ip_only_moder']) ? false : decode_ip_xx($ip);
  835. }
  836. }
  837. function bt_show_port ($port)
  838. {
  839. global $bb_cfg;
  840. if (IS_AM)
  841. {
  842. return $port;
  843. }
  844. else
  845. {
  846. return ($bb_cfg['bt_show_port_only_moder']) ? false : $port;
  847. }
  848. }
  849. function decode_ip_xx ($ip)
  850. {
  851. $h = explode('.', chunk_split($ip, 2, '.'));
  852. return hexdec($h[0]) .'.'. hexdec($h[1]) .'.'. hexdec($h[2]) .'.xx';
  853. }
  854. function checkbox_get_val (&$key, &$val, $default = 1, $on = 1, $off = 0)
  855. {
  856. global $previous_settings, $search_id;
  857. if (isset($_REQUEST[$key]) && is_string($_REQUEST[$key]))
  858. {
  859. $val = (int) $_REQUEST[$key];
  860. }
  861. else if (!isset($_REQUEST[$key]) && isset($_REQUEST['prev_'. $key]))
  862. {
  863. $val = $off;
  864. }
  865. else if (isset($previous_settings[$key]) && (!IS_GUEST || !empty($search_id)))
  866. {
  867. $val = ($previous_settings[$key]) ? $on : $off;
  868. }
  869. else
  870. {
  871. $val = $default;
  872. }
  873. }
  874. function select_get_val ($key, &$val, $options_ary, $default, $num = true)
  875. {
  876. global $previous_settings;
  877. if (isset($_REQUEST[$key]) && is_string($_REQUEST[$key]))
  878. {
  879. if (isset($options_ary[$_REQUEST[$key]]))
  880. {
  881. $val = ($num) ? intval($_REQUEST[$key]) : $_REQUEST[$key];
  882. }
  883. }
  884. else if (isset($previous_settings[$key]))
  885. {
  886. $val = $previous_settings[$key];
  887. }
  888. else
  889. {
  890. $val = $default;
  891. }
  892. }
  893. /**
  894. * set_var
  895. *
  896. * Set variable, used by {@link request_var the request_var function}
  897. *
  898. * @access private
  899. */
  900. function set_var(&$result, $var, $type, $multibyte = false, $strip = true)
  901. {
  902. settype($var, $type);
  903. $result = $var;
  904. if ($type == 'string')
  905. {
  906. $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result)));
  907. if (!empty($result))
  908. {
  909. // Make sure multibyte characters are wellformed
  910. if ($multibyte)
  911. {
  912. if (!preg_match('/^./u', $result))
  913. {
  914. $result = '';
  915. }
  916. }
  917. }
  918. $result = ($strip) ? stripslashes($result) : $result;
  919. }
  920. }
  921. /**
  922. * request_var
  923. *
  924. * Used to get passed variable
  925. */
  926. function request_var($var_name, $default, $multibyte = false, $cookie = false)
  927. {
  928. if (!$cookie && isset($_COOKIE[$var_name]))
  929. {
  930. if (!isset($_GET[$var_name]) && !isset($_POST[$var_name]))
  931. {
  932. return (is_array($default)) ? array() : $default;
  933. }
  934. $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name];
  935. }
  936. if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name])))
  937. {
  938. return (is_array($default)) ? array() : $default;
  939. }
  940. $var = $_REQUEST[$var_name];
  941. if (!is_array($default))
  942. {
  943. $type = gettype($default);
  944. }
  945. else
  946. {
  947. list($key_type, $type) = each($default);
  948. $type = gettype($type);
  949. $key_type = gettype($key_type);
  950. if ($type == 'array')
  951. {
  952. reset($default);
  953. $default = current($default);
  954. list($sub_key_type, $sub_type) = each($default);
  955. $sub_type = gettype($sub_type);
  956. $sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type;
  957. $sub_key_type = gettype($sub_key_type);
  958. }
  959. }
  960. if (is_array($var))
  961. {
  962. $_var = $var;
  963. $var = array();
  964. foreach ($_var as $k => $v)
  965. {
  966. set_var($k, $k, $key_type);
  967. if ($type == 'array' && is_array($v))
  968. {
  969. foreach ($v as $_k => $_v)
  970. {
  971. if (is_array($_v))
  972. {
  973. $_v = null;
  974. }
  975. set_var($_k, $_k, $sub_key_type);
  976. set_var($var[$k][$_k], $_v, $sub_type, $multibyte);
  977. }
  978. }
  979. else
  980. {
  981. if ($type == 'array' || is_array($v))
  982. {
  983. $v = null;
  984. }
  985. set_var($var[$k], $v, $type, $multibyte);
  986. }
  987. }
  988. }
  989. else
  990. {
  991. set_var($var, $var, $type, $multibyte);
  992. }
  993. return $var;
  994. }
  995. function get_username ($user_id)
  996. {
  997. if (empty($user_id))
  998. {
  999. return is_array($user_id) ? array() : false;
  1000. }
  1001. if (is_array($user_id))
  1002. {
  1003. $usernames = array();
  1004. foreach (DB()->fetch_rowset("SELECT user_id, username FROM ". BB_USERS ." WHERE user_id IN(". get_id_csv($user_id) .")") as $row)
  1005. {
  1006. $usernames[$row['user_id']] = $row['username'];
  1007. }
  1008. return $usernames;
  1009. }
  1010. else
  1011. {
  1012. $row = DB()->fetch_row("SELECT username FROM ". BB_USERS ." WHERE user_id = $user_id LIMIT 1");
  1013. return $row['username'];
  1014. }
  1015. }
  1016. function get_user_id ($username)
  1017. {
  1018. if (empty($username)) return false;
  1019. $row = DB()->fetch_row("SELECT user_id FROM ". BB_USERS ." WHERE username = '". DB()->escape($username) ."' LIMIT 1");
  1020. return $row['user_id'];
  1021. }
  1022. function str_short ($text, $max_length, $space = ' ')
  1023. {
  1024. if ($max_length && mb_strlen($text, 'UTF-8') > $max_length)
  1025. {
  1026. $text = mb_substr($text, 0, $max_length, 'UTF-8');
  1027. if ($last_space_pos = $max_length - intval(strpos(strrev($text), $space)))
  1028. {
  1029. if ($last_space_pos > round($max_length * 3/4))
  1030. {
  1031. $last_space_pos--;
  1032. $text = mb_substr($text, 0, $last_space_pos, 'UTF-8');
  1033. }
  1034. }
  1035. $text .= '...';
  1036. $text = preg_replace('!&#?(\w+)?;?(\w{1,5})?\.\.\.$!', '...', $text);
  1037. }
  1038. return $text;
  1039. }
  1040. function wbr ($text, $max_word_length = HTML_WBR_LENGTH)
  1041. {
  1042. return preg_replace("/([\w\->;:.,~!?(){}@#$%^*\/\\\\]{". $max_word_length ."})/ui", '$1<wbr>', $text);
  1043. }
  1044. function get_bt_userdata ($user_id)
  1045. {
  1046. return DB()->fetch_row("SELECT bt.*, SUM(tr.speed_up) as speed_up, SUM(tr.speed_down) as speed_down
  1047. FROM ". BB_BT_USERS ." bt
  1048. LEFT JOIN ". BB_BT_TRACKER ." tr ON (bt.user_id = tr.user_id)
  1049. WHERE bt.user_id = ". (int) $user_id ."
  1050. GROUP BY bt.user_id");
  1051. }
  1052. function get_bt_ratio ($btu)
  1053. {
  1054. return
  1055. (!empty($btu['u_down_total']) && $btu['u_down_total'] > MIN_DL_FOR_RATIO)
  1056. ? round((($btu['u_up_total'] + $btu['u_up_release'] + $btu['u_up_bonus']) / $btu['u_down_total']), 2)
  1057. : null
  1058. ;
  1059. }
  1060. function show_bt_userdata ($user_id)
  1061. {
  1062. global $lang, $template;
  1063. $btu = get_bt_userdata($user_id);
  1064. $template->assign_vars(array(
  1065. 'SHOW_BT_USERDATA' => true,
  1066. 'UP_TOTAL' => humn_size($btu['u_up_total']),
  1067. 'UP_BONUS' => humn_size($btu['u_up_bonus']),
  1068. 'RELEASED' => humn_size($btu['u_up_release']),
  1069. 'DOWN_TOTAL' => humn_size($btu['u_down_total']),
  1070. 'DOWN_TOTAL_BYTES' => $btu['u_down_total'],
  1071. 'USER_RATIO' => get_bt_ratio($btu),
  1072. 'MIN_DL_FOR_RATIO' => humn_size(MIN_DL_FOR_RATIO),
  1073. 'MIN_DL_BYTES' => MIN_DL_FOR_RATIO,
  1074. 'AUTH_KEY' => ($btu['auth_key']) ? $btu['auth_key'] : $lang['NONE'],
  1075. 'TD_DL' => humn_size($btu['down_today']),
  1076. 'TD_UL' => humn_size($btu['up_today']),
  1077. 'TD_REL' => humn_size($btu['up_release_today']),
  1078. 'TD_BONUS' => humn_size($btu['up_bonus_today']),
  1079. 'TD_POINTS' => ($btu['auth_key']) ? $btu['points_today'] : '0.00',
  1080. 'YS_DL' => humn_size($btu['down_yesterday']),
  1081. 'YS_UL' => humn_size($btu['up_yesterday']),
  1082. 'YS_REL' => humn_size($btu['up_release_yesterday']),
  1083. 'YS_BONUS' => humn_size($btu['up_bonus_yesterday']),
  1084. 'YS_POINTS' => ($btu['auth_key']) ? $btu['points_yesterday'] : '0.00',
  1085. 'SPEED_UP' => humn_size($btu['speed_up'], 0, 'KB') .'/s',
  1086. 'SPEED_DOWN' => humn_size($btu['speed_down'], 0, 'KB') .'/s',
  1087. ));
  1088. }
  1089. function get_attachments_dir ($cfg = null)
  1090. {
  1091. if (!$cfg AND !$cfg = $GLOBALS['attach_config'])
  1092. {
  1093. $cfg = bb_get_config(BB_ATTACH_CONFIG, true, false);
  1094. }
  1095. if (!$cfg['allow_ftp_upload'])
  1096. {
  1097. if ($cfg['upload_dir'][0] == '/' || ($cfg['upload_dir'][0] != '/' && $cfg['upload_dir'][1] == ':'))
  1098. {
  1099. return $cfg['upload_dir'];
  1100. }
  1101. else
  1102. {
  1103. return BB_ROOT . $cfg['upload_dir'];
  1104. }
  1105. }
  1106. else
  1107. {
  1108. return $cfg['download_path'];
  1109. }
  1110. }
  1111. function bb_get_config ($table, $from_db = false, $update_cache = true)
  1112. {
  1113. if ($from_db OR !$cfg = CACHE('bb_cache')->get("config_{$table}"))
  1114. {
  1115. $cfg = array();
  1116. foreach (DB()->fetch_rowset("SELECT * FROM $table") as $row)
  1117. {
  1118. $cfg[$row['config_name']] = $row['config_value'];
  1119. }
  1120. if ($update_cache)
  1121. {
  1122. CACHE('bb_cache')->set("config_{$table}", $cfg);
  1123. }
  1124. }
  1125. return $cfg;
  1126. }
  1127. function bb_update_config ($params, $table = BB_CONFIG)
  1128. {
  1129. $updates = array();
  1130. foreach ($params as $name => $val)
  1131. {
  1132. $updates[] = array(
  1133. 'config_name' => $name,
  1134. 'config_value' => $val,
  1135. );
  1136. }
  1137. $updates = DB()->build_array('MULTI_INSERT', $updates);
  1138. DB()->query("REPLACE INTO $table $updates");
  1139. // Update cache
  1140. bb_get_config($table, true, true);
  1141. }
  1142. function get_db_stat($mode)
  1143. {
  1144. switch( $mode )
  1145. {
  1146. case 'usercount':
  1147. $sql = "SELECT COUNT(user_id) AS total
  1148. FROM " . BB_USERS;
  1149. break;
  1150. case 'newestuser':
  1151. $sql = "SELECT user_id, username
  1152. FROM " . BB_USERS . "
  1153. WHERE user_id <> " . GUEST_UID . "
  1154. ORDER BY user_id DESC
  1155. LIMIT 1";
  1156. break;
  1157. case 'postcount':
  1158. case 'topiccount':
  1159. $sql = "SELECT SUM(forum_topics) AS topic_total, SUM(forum_posts) AS post_total
  1160. FROM " . BB_FORUMS;
  1161. break;
  1162. }
  1163. if ( !($result = DB()->sql_query($sql)) )
  1164. {
  1165. return false;
  1166. }
  1167. $row = DB()->sql_fetchrow($result);
  1168. switch ( $mode )
  1169. {
  1170. case 'usercount':
  1171. return $row['total'];
  1172. break;
  1173. case 'newestuser':
  1174. return $row;
  1175. break;
  1176. case 'postcount':
  1177. return $row['post_total'];
  1178. break;
  1179. case 'topiccount':
  1180. return $row['topic_total'];
  1181. break;
  1182. }
  1183. return false;
  1184. }
  1185. function clean_username($username)
  1186. {
  1187. $username = mb_substr(htmlspecialchars(str_replace("\'", "'", trim($username))), 0, 25, 'UTF-8');
  1188. $username = bb_rtrim($username, "\\");
  1189. $username = str_replace("'", "\'", $username);
  1190. return $username;
  1191. }
  1192. function bb_ltrim($str, $charlist = false)
  1193. {
  1194. if ($charlist === false)
  1195. {
  1196. return ltrim($str);
  1197. }
  1198. $str = ltrim($str, $charlist);
  1199. return $str;
  1200. }
  1201. function bb_rtrim($str, $charlist = false)
  1202. {
  1203. if ($charlist === false)
  1204. {
  1205. return rtrim($str);
  1206. }
  1207. $str = rtrim($str, $charlist);
  1208. return $str;
  1209. }
  1210. // Get Userdata, $u can be username or user_id. If $force_name is true, the username will be forced.
  1211. function get_userdata ($u, $force_name = false, $allow_guest = false)
  1212. {
  1213. if (!$u) return false;
  1214. if (intval($u) == GUEST_UID && $allow_guest)
  1215. {
  1216. if ($u_data = CACHE('bb_cache')->get('guest_userdata'))
  1217. {
  1218. return $u_data;
  1219. }
  1220. }
  1221. $u_data = array();
  1222. $name_search = false;
  1223. $exclude_anon_sql = (!$allow_guest) ? "AND user_id != ". GUEST_UID : '';
  1224. if ($force_name || !is_numeric($u))
  1225. {
  1226. $name_search = true;
  1227. $where_sql = "WHERE username = '". DB()->escape(clean_username($u)) ."'";
  1228. }
  1229. else
  1230. {
  1231. $where_sql = "WHERE user_id = ". (int) $u;
  1232. }
  1233. $sql = "SELECT * FROM ". BB_USERS ." $where_sql $exclude_anon_sql LIMIT 1";
  1234. if (!$u_data = DB()->fetch_row($sql))
  1235. {
  1236. if (!is_int($u) && !$name_search)
  1237. {
  1238. $where_sql = "WHERE username = '". DB()->escape(clean_username($u)) ."'";
  1239. $sql = "SELECT * FROM ". BB_USERS ." $where_sql $exclude_anon_sql LIMIT 1";
  1240. $u_data = DB()->fetch_row($sql);
  1241. }
  1242. }
  1243. if ($u_data['user_id'] == GUEST_UID)
  1244. {
  1245. CACHE('bb_cache')->set('guest_userdata', $u_data);
  1246. }
  1247. return $u_data;
  1248. }
  1249. function make_jumpbox ($selected = 0)
  1250. {
  1251. global $datastore, $template;
  1252. if (!$jumpbox = $datastore->get('jumpbox'))
  1253. {
  1254. $datastore->update('jumpbox');
  1255. $jumpbox = $datastore->get('jumpbox');
  1256. }
  1257. $template->assign_vars(array(
  1258. 'JUMPBOX' => (IS_GUEST) ? $jumpbox['guest'] : $jumpbox['user'],
  1259. ));
  1260. }
  1261. // $mode: array(not_auth_forum1,not_auth_forum2,..) or (string) 'mode'
  1262. function get_forum_select ($mode = 'guest', $name = POST_FORUM_URL, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '', $all_forums_option = null)
  1263. {
  1264. global $lang, $datastore;
  1265. if (is_array($mode))
  1266. {
  1267. $not_auth_forums_fary = array_flip($mode);
  1268. $mode = 'not_auth_forums';
  1269. }
  1270. if (is_null($max_length))
  1271. {
  1272. $max_length = HTML_SELECT_MAX_LENGTH;
  1273. }
  1274. $select = is_null($all_forums_option) ? array() : array($lang['ALL_AVAILABLE'] => $all_forums_option);
  1275. if (!$forums = $datastore->get('cat_forums'))
  1276. {
  1277. $datastore->update('cat_forums');
  1278. $forums = $datastore->get('cat_forums');
  1279. }
  1280. foreach ($forums['f'] as $fid => $f)
  1281. {
  1282. switch ($mode)
  1283. {
  1284. case 'guest':
  1285. if ($f['auth_view'] != AUTH_ALL) continue 2;
  1286. break;
  1287. case 'user':
  1288. if ($f['auth_view'] != AUTH_ALL && $f['auth_view'] != AUTH_REG) continue 2;
  1289. break;
  1290. case 'not_auth_forums':
  1291. if (isset($not_auth_forums_fary[$f['forum_id']])) continue 2;
  1292. break;
  1293. case 'admin':
  1294. break;
  1295. default:
  1296. trigger_error(__FUNCTION__ .": invalid mode '$mode'", E_USER_ERROR);
  1297. }
  1298. $cat_title = $forums['c'][$f['cat_id']]['cat_title'];
  1299. $f_name = ($f['forum_parent']) ? ' |- ' : '';
  1300. $f_name .= $f['forum_name'];
  1301. while (isset($select[$cat_title][$f_name]))
  1302. {
  1303. $f_name .= ' ';
  1304. }
  1305. $select[$cat_title][$f_name] = $fid;
  1306. if (!$f['forum_parent'])
  1307. {
  1308. $class = 'root_forum';
  1309. $class .= isset($f['subforums']) ? ' has_sf' : '';
  1310. $select['__attributes'][$cat_title][$f_name]['class'] = $class;
  1311. }
  1312. }
  1313. return build_select($name, $select, $selected, $max_length, $multiple_size, $js);
  1314. }
  1315. function setup_style ()
  1316. {
  1317. global $bb_cfg, $template, $userdata;
  1318. // AdminCP works only with default template
  1319. $tpl_dir_name = defined('IN_ADMIN') ? 'default' : basename($bb_cfg['tpl_name']);
  1320. $stylesheet = defined('IN_ADMIN') ? 'main.css' : basename($bb_cfg['stylesheet']);
  1321. if (!IS_GUEST && !empty($userdata['tpl_name']))
  1322. {
  1323. foreach ($bb_cfg['templates'] as $folder => $name)
  1324. {
  1325. if ($userdata['tpl_name'] == $folder) $tpl_dir_name = basename($userdata['tpl_name']);
  1326. }
  1327. }
  1328. $template = new Template(TEMPLATES_DIR . $tpl_dir_name);
  1329. $css_dir = basename(TEMPLATES_DIR) ."/$tpl_dir_name/css/";
  1330. $template->assign_vars(array(
  1331. 'BB_ROOT' => BB_ROOT,
  1332. 'SPACER' => make_url('/images/spacer.gif'),
  1333. 'STYLESHEET' => make_url($css_dir . $stylesheet),
  1334. 'EXT_LINK_NEW_WIN' => $bb_cfg['ext_link_new_win'],
  1335. 'TPL_DIR' => make_url($css_dir),
  1336. 'SITE_URL' => make_url('/'),
  1337. ));
  1338. require(TEMPLATES_DIR . $tpl_dir_name .'/tpl_config.php');
  1339. $theme = array('template_name' => $tpl_dir_name);
  1340. return $theme;
  1341. }
  1342. // Create date/time from format and timezone
  1343. function bb_date ($gmepoch, $format = false, $tz = null)
  1344. {
  1345. global $bb_cfg, $lang, $userdata;
  1346. if (!$format) $format = $bb_cfg['default_dateformat'];
  1347. if (empty($lang)) require_once($bb_cfg['default_lang_dir'] .'lang_main.php');
  1348. if (is_null($tz) || $tz == 'false')
  1349. {
  1350. if (empty($userdata['session_logged_in']))
  1351. {
  1352. $tz2 = $bb_cfg['board_timezone'];
  1353. }
  1354. else $tz2 = $userdata['user_timezone'];
  1355. }
  1356. elseif (is_numeric($tz)) $tz2 = $tz;
  1357. $date = gmdate($format, $gmepoch + (3600 * $tz2));
  1358. if ($tz != 'false')
  1359. {
  1360. $time_format = " H:i";
  1361. $today = gmdate("d", TIMENOW + (3600 * $tz2));
  1362. $month = gmdate("m", TIMENOW + (3600 * $tz2));
  1363. $year = gmdate("Y", TIMENOW + (3600 * $tz2));
  1364. $date_today = gmdate("d", $gmepoch + (3600 * $tz2));
  1365. $date_month = gmdate("m", $gmepoch + (3600 * $tz2));
  1366. $date_year = gmdate("Y", $gmepoch + (3600 * $tz2));
  1367. if ($date_today == $today && $date_month == $month && $date_year == $year)
  1368. {
  1369. $date = 'today' . gmdate($time_format, $gmepoch + (3600 * $tz2));
  1370. }
  1371. elseif ($today != 1 && $date_today == ($today-1) && $date_month == $month && $date_year == $year)
  1372. {
  1373. $date = 'yesterday' . gmdate($time_format, $gmepoch + (3600 * $tz2));
  1374. }
  1375. elseif ($today == 1 && $month != 1)
  1376. {
  1377. $yesterday = date ("t", mktime(0, 0, 0, ($month-1), 1, $year));
  1378. if ($date_today == $yesterday && $date_month == ($month-1) && $date_year == $year)
  1379. $date = 'yesterday' . gmdate($time_format, $gmepoch + (3600 * $tz2));
  1380. }
  1381. elseif ($today == 1 && $month == 1)
  1382. {
  1383. $yesterday = date ("t", mktime(0, 0, 0, 12, 1, ($year -1)));
  1384. if ($date_today == $yesterday && $date_month == 12 && $date_year == ($year-1))
  1385. $date = 'yesterday' . gmdate($time_format, $gmepoch + (3600 * $tz));
  1386. }
  1387. }
  1388. return ($bb_cfg['translate_dates']) ? strtr(strtoupper($date), $lang['DATETIME']) : $date;
  1389. }
  1390. // Birthday
  1391. // Add function mkrealdate for Birthday MOD
  1392. // the originate php "mktime()", does not work proberly on all OS, especially when going back in time
  1393. // before year 1970 (year 0), this function "mkrealtime()", has a mutch larger valid date range,
  1394. // from 1901 - 2099. it returns a "like" UNIX timestamp divided by 86400, so
  1395. // calculation from the originate php date and mktime is easy.
  1396. // mkrealdate, returns the number of day (with sign) from 1.1.1970.
  1397. function mkrealdate ($day, $month, $birth_year)
  1398. {
  1399. // define epoch
  1400. $epoch = 0;
  1401. // range check months
  1402. if ($month < 1 || $month > 12) return "error";
  1403. // range check days
  1404. switch ($month)
  1405. {
  1406. case 1: if ($day > 31) return "error"; break;
  1407. case 2: if ($day > 29) return "error";
  1408. $epoch = $epoch+31; break;
  1409. case 3: if ($day > 31) return "error";
  1410. $epoch = $epoch+59; break;
  1411. case 4: if ($day > 30) return "error" ;
  1412. $epoch = $epoch+90; break;
  1413. case 5: if ($day > 31) return "error";
  1414. $epoch = $epoch+120; break;
  1415. case 6: if ($day > 30) return "error";
  1416. $epoch = $epoch+151; break;
  1417. case 7: if ($day > 31) return "error";
  1418. $epoch = $epoch+181; break;
  1419. case 8: if ($day > 31) return "error";
  1420. $epoch = $epoch+212; break;
  1421. case 9: if ($day > 30) return "error";
  1422. $epoch = $epoch+243; break;
  1423. case 10: if ($day > 31) return "error";
  1424. $epoch = $epoch+273; break;
  1425. case 11: if ($day > 30) return "error";
  1426. $epoch = $epoch+304; break;
  1427. case 12: if ($day > 31) return "error";
  1428. $epoch = $epoch+334; break;
  1429. }
  1430. $epoch = $epoch+$day;
  1431. $epoch_Y = sqrt(($birth_year-1970)*($birth_year-1970));
  1432. $leapyear = round((($epoch_Y+2) / 4)-.5);
  1433. if (($epoch_Y+2)%4 == 0)
  1434. {// curent year is leapyear
  1435. $leapyear--;
  1436. if ($birth_year > 1970 && $month >= 3) $epoch = $epoch+1;
  1437. if ($birth_year < 1970 && $month < 3) $epoch = $epoch-1;
  1438. }
  1439. else if ($month == 2 && $day > 28) return "error";//only 28 days in feb.
  1440. //year
  1441. if ($birth_year > 1970)
  1442. {
  1443. $epoch = $epoch + $epoch_Y*365-1 + $leapyear;
  1444. }
  1445. else
  1446. {
  1447. $epoch = $epoch - $epoch_Y*365-1 - $leapyear;
  1448. }
  1449. return $epoch;
  1450. }
  1451. // Add function realdate for Birthday MOD
  1452. // the originate php "date()", does not work proberly on all OS, especially when going back in time
  1453. // before year 1970 (year 0), this function "realdate()", has a mutch larger valid date range,
  1454. // from 1901 - 2099. it returns a "like" UNIX date format (only date, related letters may be used, due to the fact that
  1455. // the given date value should already be divided by 86400 - leaving no time information left)
  1456. // a input like a UNIX timestamp divided by 86400 is expected, so
  1457. // calculation from the originate php date and mktime is easy.
  1458. // e.g. realdate ("m d Y", 3) returns the string "1 3 1970"
  1459. // UNIX users should replace this function with the below code, since this should be faster
  1460. //
  1461. function realdate ($date, $format = "Ymd")
  1462. {
  1463. if (!$date) return;
  1464. return bb_date($date*86400 + 1, $format, 0);
  1465. }
  1466. function birthday_age ($date, $list = 0)
  1467. {
  1468. if (!$date) return;
  1469. return delta_time(mktime(11, 0, 0, date('m', strtotime($date)), date('d', strtotime($date)), (date('Y', strtotime($date)) - $list)));
  1470. }
  1471. //
  1472. // Pagination routine, generates
  1473. // page number sequence
  1474. //
  1475. function generate_pagination ($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = TRUE)
  1476. {
  1477. global $lang, $template;
  1478. // Pagination Mod
  1479. $begin_end = 3;
  1480. $from_middle = 1;
  1481. /*
  1482. By default, $begin_end is 3, and $from_middle is 1, so on page 6 in a 12 page view, it will look like this:
  1483. a, d = $begin_end = 3
  1484. b, c = $from_middle = 1
  1485. "begin" "middle" "end"
  1486. | | |
  1487. | a b | c d |
  1488. | | | | | | |
  1489. v v v v v v v
  1490. 1, 2, 3 ... 5, 6, 7 ... 10, 11, 12
  1491. Change $begin_end and $from_middle to suit your needs appropriately
  1492. */
  1493. $total_pages = ceil($num_items/$per_page);
  1494. if ( $total_pages == 1 || $num_items == 0 )
  1495. {
  1496. return '';
  1497. }
  1498. $on_page = floor($start_item / $per_page) + 1;
  1499. $page_string = '';
  1500. if ( $total_pages > ((2*($begin_end + $from_middle)) + 2) )
  1501. {
  1502. $init_page_max = ( $total_pages > $begin_end ) ? $begin_end : $total_pages;
  1503. for($i = 1; $i < $init_page_max + 1; $i++)
  1504. {
  1505. $page_string .= ( $i == $on_page ) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . ( ( $i - 1 ) * $per_page ) . '">' . $i . '</a>';
  1506. if ( $i < $init_page_max )
  1507. {
  1508. $page_string .= ", ";
  1509. }
  1510. }
  1511. if ( $total_pages > $begin_end )
  1512. {
  1513. if ( $on_page > 1 && $on_page < $total_pages )
  1514. {
  1515. $page_string .= ( $on_page > ($begin_end + $from_middle + 1) ) ? ' ... ' : ', ';
  1516. $init_page_min = ( $on_page > ($begin_end + $from_middle) ) ? $on_page : ($begin_end + $from_middle + 1);
  1517. $init_page_max = ( $on_page < $total_pages - ($begin_end + $from_middle) ) ? $on_page : $total_pages - ($begin_end + $from_middle);
  1518. for($i = $init_page_min - $from_middle; $i < $init_page_max + ($from_middle + 1); $i++)
  1519. {
  1520. $page_string .= ($i == $on_page) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . ( ( $i - 1 ) * $per_page ) . '">' . $i . '</a>';
  1521. if ( $i < $init_page_max + $from_middle )
  1522. {
  1523. $page_string .= ', ';
  1524. }
  1525. }
  1526. $page_string .= ( $on_page < $total_pages - ($begin_end + $from_middle) ) ? ' ... ' : ', ';
  1527. }
  1528. else
  1529. {
  1530. $page_string .= '&nbsp;...&nbsp;';
  1531. }
  1532. for($i = $total_pages - ($begin_end - 1); $i < $total_pages + 1; $i++)
  1533. {
  1534. $page_string .= ( $i == $on_page ) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . ( ( $i - 1 ) * $per_page ) . '">' . $i . '</a>';
  1535. if( $i < $total_pages )
  1536. {
  1537. $page_string .= ", ";
  1538. }
  1539. }
  1540. }
  1541. }
  1542. else
  1543. {
  1544. for($i = 1; $i < $total_pages + 1; $i++)
  1545. {
  1546. $page_string .= ( $i == $on_page ) ? '<b>' . $i . '</b>' : '<a href="' . $base_url . "&amp;start=" . ( ( $i - 1 ) * $per_page ) . '">' . $i . '</a>';
  1547. if ( $i < $total_pages )
  1548. {
  1549. $page_string .= ', ';
  1550. }
  1551. }
  1552. }
  1553. if ( $add_prevnext_text )
  1554. {
  1555. if ( $on_page > 1 )
  1556. {
  1557. $page_string = ' <a href="' . $base_url . "&amp;start=" . ( ( $on_page - 2 ) * $per_page ) . '">' . $lang['PREVIOUS_PAGE'] . '</a>&nbsp;&nbsp;' . $page_string;
  1558. }
  1559. if ( $on_page < $total_pages )
  1560. {
  1561. $page_string .= '&nbsp;&nbsp;<a href="' . $base_url . "&amp;start=" . ( $on_page * $per_page ) . '">' . $lang['NEXT_PAGE'] . '</a>';
  1562. }
  1563. }
  1564. $pagination = ($page_string) ? '<a class="menu-root" href="#pg-jump">'. $lang['GOTO_PAGE'] .'</a> :&nbsp;&nbsp;'. $page_string : '';
  1565. $pagination = str_replace('&amp;start=0', '', $pagination);
  1566. $template->assign_vars(array(
  1567. 'PAGINATION' => $pagination,
  1568. 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], ( floor($start_item/$per_page) + 1 ), ceil( $num_items / $per_page )),
  1569. 'PG_BASE_URL' => $base_url,
  1570. 'PG_PER_PAGE' => $per_page,
  1571. ));
  1572. return $pagination;
  1573. }
  1574. //
  1575. // This does exactly what preg_quote() does in PHP 4-ish
  1576. // If you just need the 1-parameter preg_quote call, then don't bother using this.
  1577. //
  1578. function bb_preg_quote($str, $delimiter)
  1579. {
  1580. $text = preg_quote($str);
  1581. $text = str_replace($delimiter, '\\' . $delimiter, $text);
  1582. return $text;
  1583. }
  1584. //
  1585. // Obtain list of naughty words and build preg style replacement arrays for use by the
  1586. // calling script, note that the vars are passed as references this just makes it easier
  1587. // to return both sets of arrays
  1588. //
  1589. function obtain_word_list(&$orig_word, &$replacement_word)
  1590. {
  1591. global $bb_cfg;
  1592. if (!$bb_cfg['use_word_censor']) return;
  1593. if (!$sql = CACHE('bb_cache')->get('censored'))
  1594. {
  1595. $sql = DB()->fetch_rowset("SELECT word, replacement FROM ". BB_WORDS);
  1596. if(!$sql) $sql = array(array('word' => 1, 'replacement' => 1));
  1597. CACHE('bb_cache')->set('censored', $sql, 7200);
  1598. }
  1599. foreach($sql as $row)
  1600. {
  1601. //$orig_word[] = '#(?<!\S)(' . str_replace('\*', '\S*?', preg_quote($row['word'], '#')) . ')(?!\S)#iu';
  1602. $orig_word[] = '#(?<![\p{Nd}\p{L}_])(' . str_replace('\*', '[\p{Nd}\p{L}_]*?', preg_quote($row['word'], '#')) . ')(?![\p{Nd}\p{L}_])#iu';
  1603. $replacement_word[] = $row['replacement'];
  1604. }
  1605. return true;
  1606. }
  1607. function smiley_sort ($a, $b)
  1608. {
  1609. if (strlen($a['code']) == strlen($b['code']))
  1610. {
  1611. return 0;
  1612. }
  1613. return (strlen($a['code']) > strlen($b['code'])) ? -1 : 1;
  1614. }
  1615. function bb_die ($msg_text)
  1616. {
  1617. if (defined('IN_AJAX'))
  1618. {
  1619. $GLOBALS['ajax']->ajax_die($msg_text);
  1620. }
  1621. message_die(GENERAL_MESSAGE, $msg_text);
  1622. }
  1623. function message_die ($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '')
  1624. {
  1625. global $DBS, $template, $bb_cfg, $theme, $lang, $userdata;
  1626. if (defined('HAS_DIED'))
  1627. {
  1628. trigger_error(__FUNCTION__ .' was called multiple times', E_USER_ERROR);
  1629. }
  1630. define('HAS_DIED', 1);
  1631. define('DISABLE_CACHING_OUTPUT', true);
  1632. $sql_store = $sql;
  1633. $debug_text = '';
  1634. // Get SQL error if we are debugging. Do this as soon as possible to prevent
  1635. // subsequent queries from overwriting the status of sql_error()
  1636. if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR))
  1637. {
  1638. if (!empty($DBS) && $sql_store)
  1639. {
  1640. $sql_error = $DBS->sql_error();
  1641. $debug_text .= "<br /><br />SQL Error : {$sql_error['code']}<br /><br />{$sql_error['message']}";
  1642. }
  1643. if ($sql_store)
  1644. {
  1645. $debug_text .= "<br /><br />$sql_store";
  1646. }
  1647. if ($sql_store && $err_line && $err_file)
  1648. {
  1649. $debug_text .= "</br /><br />Line : {$err_line}<br />File : ". basename($err_file);
  1650. }
  1651. }
  1652. if (empty($lang))
  1653. {
  1654. require($bb_cfg['default_lang_dir'] .'lang_main.php');
  1655. }
  1656. if (empty($userdata) && ($msg_code == GENERAL_MESSAGE || $msg_code == GENERAL_ERROR))
  1657. {
  1658. $userdata = session_pagestart();
  1659. }
  1660. // If the header hasn't been output then do it
  1661. if (!defined('PAGE_HEADER_SENT') && $msg_code != CRITICAL_ERROR)
  1662. {
  1663. if (empty($template))
  1664. {
  1665. $template = new Template(BB_ROOT ."templates/{$bb_cfg['tpl_name']}");
  1666. }
  1667. if (empty($theme))
  1668. {
  1669. $theme = setup_style();
  1670. }
  1671. require(PAGE_HEADER);
  1672. }
  1673. switch ($msg_code)
  1674. {
  1675. case GENERAL_MESSAGE:
  1676. if (!$msg_title) $msg_title = $lang['INFORMATION'];
  1677. break;
  1678. case GENERAL_ERROR:
  1679. if (!$msg_text) $msg_text = $lang['AN_ERROR_OCCURED'];
  1680. if (!$msg_title) $msg_title = $lang['GENERAL_ERROR'];
  1681. break;
  1682. case CRITICAL_ERROR:
  1683. // Critical errors mean we cannot rely on _ANY_ DB information being
  1684. // available so we're going to dump out a simple echo'd statement
  1685. if (!$msg_text) $msg_text = $lang['A_CRITICAL_ERROR'];
  1686. if (!$msg_title) $msg_title = 'BB : <b>Critical Error</b>';
  1687. break;
  1688. }
  1689. // Add on DEBUG info if we've enabled debug mode and this is an error. This
  1690. // prevents debug info being output for general messages should DEBUG be
  1691. // set TRUE by accident (preventing confusion for the end user!)
  1692. if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR))
  1693. {
  1694. if ($debug_text)
  1695. {
  1696. $msg_text .= '<br /><br /><b><u>DEBUG MODE</u></b>'. $debug_text;
  1697. }
  1698. }
  1699. if ($msg_code != CRITICAL_ERROR)
  1700. {
  1701. if (!empty($lang[$msg_text]))
  1702. {
  1703. $msg_text = $lang[$msg_text];
  1704. }
  1705. $template->assign_vars(array(
  1706. 'TPL_GENERAL_MESSAGE' => true,
  1707. 'MESSAGE_TITLE' => $msg_title,
  1708. 'MESSAGE_TEXT' => $msg_text,
  1709. ));
  1710. $template->set_filenames(array('message_die' => 'common.tpl'));
  1711. $template->pparse('message_die');
  1712. require(PAGE_FOOTER);
  1713. }
  1714. else
  1715. {
  1716. echo "<html>\n<body>\n". $msg_title ."\n<br /><br />\n". $msg_text ."</body>\n</html>";
  1717. }
  1718. exit;
  1719. }
  1720. function bb_simple_die ($txt)
  1721. {
  1722. global $bb_cfg;
  1723. if (!empty($_COOKIE['explain']))
  1724. {
  1725. bb_die("bb_simple_die:<br /><br />$txt");
  1726. }
  1727. header('Content-Type: text/plain; charset='. $bb_cfg['charset']);
  1728. die($txt);
  1729. }
  1730. function bb_realpath($path)
  1731. {
  1732. return (!@function_exists('realpath') || !@realpath(INC_DIR . 'functions.php')) ? $path : @realpath($path);
  1733. }
  1734. function login_redirect ($url = '')
  1735. {
  1736. redirect(LOGIN_URL . '?redirect='. (($url) ? $url : $_SERVER['REQUEST_URI']));
  1737. }
  1738. function meta_refresh($url, $time = 5)
  1739. {
  1740. global $template;
  1741. $template->assign_var(
  1742. 'META' , '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />'
  1743. );
  1744. }
  1745. function redirect ($url)
  1746. {
  1747. global $bb_cfg;
  1748. if (headers_sent($filename, $linenum))
  1749. {
  1750. trigger_error("Headers already sent in $filename($linenum)", E_USER_ERROR);
  1751. }
  1752. if (strstr(urldecode($url), "\n") || strstr(urldecode($url), "\r") || strstr(urldecode($url), ';url'))
  1753. {
  1754. message_die(CRITICAL_ERROR, 'Tried to redirect to potentially insecure url.');
  1755. }
  1756. $url = trim($url);
  1757. $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://';
  1758. $server_name = preg_replace('#^\/?(.*?)\/?$#', '\1', trim($bb_cfg['server_name']));
  1759. $server_port = ($bb_cfg['server_port'] <> 80) ? ':' . trim($bb_cfg['server_port']) : '';
  1760. $script_name = preg_replace('#^\/?(.*?)\/?$#', '\1', trim($bb_cfg['script_path']));
  1761. if ($script_name)
  1762. {
  1763. $script_name = "/$script_name";
  1764. $url = preg_replace("#^$script_name#", '', $url);
  1765. }
  1766. $redirect_url = $server_protocol . $server_name . $server_port . $script_name . preg_replace('#^\/?(.*?)\/?$#', '/\1', $url);
  1767. // Redirect via an HTML form for PITA webservers
  1768. if (@preg_match('/Microsoft|WebSTAR|Xitami/', getenv('SERVER_SOFTWARE')))
  1769. {
  1770. header('Refresh: 0; URL='. $redirect_url);
  1771. echo '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="refresh" content="0; url='. $redirect_url .'"><title>Redirect</title></head><body><div align="center">If your browser does not support meta redirection please click <a href="'. $redirect_url .'">HERE</a> to be redirected</div></body></html>';
  1772. exit;
  1773. }
  1774. // Behave as per HTTP/1.1 spec for others
  1775. header('Location: '. $redirect_url);
  1776. exit;
  1777. }
  1778. //-- mod : topic display order ---------------------------------------------------------------------
  1779. //-- add
  1780. // build a list of the sortable fields or return field name
  1781. function get_forum_display_sort_option($selected_row=0, $action='list', $list='sort')
  1782. {
  1783. global $lang;
  1784. $forum_display_sort = array(
  1785. 'lang_key' => array('LASTPOST', 'SORT_TOPIC_TITLE', 'SORT_TIME'),
  1786. 'fields' => array('t.topic_last_post_time', 't.topic_title', 't.topic_time'),
  1787. );
  1788. $forum_display_order = array(
  1789. 'lang_key' => array('DESC', 'ASC'),
  1790. 'fields' => array('DESC', 'ASC'),
  1791. );
  1792. // get the good list
  1793. $list_name = 'forum_display_' . $list;
  1794. $listrow = $$list_name;
  1795. // init the result
  1796. $res = '';
  1797. if ( $selected_row > count($listrow['lang_key']) )
  1798. {
  1799. $selected_row = 0;
  1800. }
  1801. // build list
  1802. if ($action == 'list')
  1803. {
  1804. for ($i=0; $i < count($listrow['lang_key']); $i++)
  1805. {
  1806. $selected = ($i==$selected_row) ? ' selected="selected"' : '';
  1807. $l_value = (isset($lang[$listrow['lang_key'][$i]])) ? $lang[$listrow['lang_key'][$i]] : $listrow['lang_key'][$i];
  1808. $res .= '<option value="' . $i . '"' . $selected . '>' . $l_value . '</option>';
  1809. }
  1810. }
  1811. else
  1812. {
  1813. // field
  1814. $res = $listrow['fields'][$selected_row];
  1815. }
  1816. return $res;
  1817. }
  1818. //-- fin mod : topic display order -----------------------------------------------------------------
  1819. function topic_attachment_image($switch_attachment)
  1820. {
  1821. global $is_auth;
  1822. if (!$switch_attachment || !($is_auth['auth_download'] && $is_auth['auth_view']))
  1823. {
  1824. return '';
  1825. }
  1826. return '<img src="images/icon_clip.gif" alt="" border="0" /> ';
  1827. }
  1828. function transliterate ($str)
  1829. {
  1830. static $translit_table;
  1831. if (!isset($translit_table))
  1832. {
  1833. require(DEFAULT_LANG_DIR .'translit_table.php');
  1834. }
  1835. return strtr($str, $translit_table);
  1836. }
  1837. /**
  1838. * array_combine()
  1839. *
  1840. * @package PHP_Compat
  1841. * @link http://php.net/function.array_combine
  1842. * @author Aidan Lister <aidan@php.net>
  1843. * @version $Revision: 1.21 $
  1844. * @since PHP 5
  1845. */
  1846. if (!function_exists('array_combine'))
  1847. {
  1848. function array_combine($keys, $values)
  1849. {
  1850. if (!is_array($keys)) {
  1851. user_error('array_combine() expects parameter 1 to be array, ' .
  1852. gettype($keys) . ' given', E_USER_WARNING);
  1853. return;
  1854. }
  1855. if (!is_array($values)) {
  1856. user_error('array_combine() expects parameter 2 to be array, ' .
  1857. gettype($values) . ' given', E_USER_WARNING);
  1858. return;
  1859. }
  1860. $key_count = count($keys);
  1861. $value_count = count($values);
  1862. if ($key_count !== $value_count) {
  1863. user_error('array_combine() Both parameters should have equal number of elements', E_USER_WARNING);
  1864. return false;
  1865. }
  1866. if ($key_count === 0 || $value_count === 0) {
  1867. user_error('array_combine() Both parameters should have number of elements at least 0', E_USER_WARNING);
  1868. return false;
  1869. }
  1870. $keys = array_values($keys);
  1871. $values = array_values($values);
  1872. $combined = array();
  1873. for ($i = 0; $i < $key_count; $i++) {
  1874. $combined[$keys[$i]] = $values[$i];
  1875. }
  1876. return $combined;
  1877. }
  1878. }
  1879. /**
  1880. * array_intersect_key()
  1881. *
  1882. * @package PHP_Compat
  1883. * @link http://php.net/function.array_intersect_key
  1884. * @author Tom Buskens <ortega@php.net>
  1885. * @version $Revision: 1.4 $
  1886. * @since PHP 5.0.2
  1887. */
  1888. if (!function_exists('array_intersect_key')) {
  1889. function array_intersect_key()
  1890. {
  1891. $args = func_get_args();
  1892. if (count($args) < 2) {
  1893. user_error('Wrong parameter count for array_intersect_key()', E_USER_WARNING);
  1894. return;
  1895. }
  1896. // Check arrays
  1897. $array_count = count($args);
  1898. for ($i = 0; $i !== $array_count; $i++) {
  1899. if (!is_array($args[$i])) {
  1900. user_error('array_intersect_key() Argument #' .
  1901. ($i + 1) . ' is not an array', E_USER_WARNING);
  1902. return;
  1903. }
  1904. }
  1905. // Compare entries
  1906. $result = array();
  1907. foreach ($args[0] as $key1 => $value1) {
  1908. for ($i = 1; $i !== $array_count; $i++) {
  1909. foreach ($args[$i] as $key2 => $value2) {
  1910. if ((string) $key1 === (string) $key2) {
  1911. $result[$key1] = $value1;
  1912. }
  1913. }
  1914. }
  1915. }
  1916. return $result;
  1917. }
  1918. }
  1919. function clear_dl_list ($topics_csv)
  1920. {
  1921. DB()->query("DELETE FROM ". BB_BT_DLSTATUS ." WHERE topic_id IN($topics_csv)");
  1922. DB()->query("DELETE FROM ". BB_BT_DLSTATUS_SNAP ." WHERE topic_id IN($topics_csv)");
  1923. }
  1924. // $ids - array(id1,id2,..) or (string) id
  1925. function get_id_csv ($ids)
  1926. {
  1927. $ids = array_values((array) $ids);
  1928. array_deep($ids, 'intval', 'one-dimensional');
  1929. return (string) join(',', $ids);
  1930. }
  1931. // $ids - array(id1,id2,..) or (string) id1,id2,..
  1932. function get_id_ary ($ids)
  1933. {
  1934. $ids = is_string($ids) ? explode(',', $ids) : array_values((array) $ids);
  1935. array_deep($ids, 'intval', 'one-dimensional');
  1936. return (array) $ids;
  1937. }
  1938. function get_topic_title ($topic_id)
  1939. {
  1940. $row = DB()->fetch_row("
  1941. SELECT topic_title FROM ". BB_TOPICS ." WHERE topic_id = ". (int) $topic_id ."
  1942. ");
  1943. return $row['topic_title'];
  1944. }
  1945. function forum_exists ($forum_id)
  1946. {
  1947. return DB()->fetch_row("SELECT forum_id FROM ". BB_FORUMS ." WHERE forum_id = $forum_id LIMIT 1");
  1948. }
  1949. function cat_exists ($cat_id)
  1950. {
  1951. return DB()->fetch_row("SELECT cat_id FROM ". BB_CATEGORIES ." WHERE cat_id = $cat_id LIMIT 1");
  1952. }
  1953. //
  1954. // Action Log
  1955. //
  1956. class log_action
  1957. {
  1958. var $log_type = array(
  1959. # LOG_TYPE_NAME LOG_TYPE_ID
  1960. 'mod_topic_delete' => 1,
  1961. 'mod_topic_move' => 2,
  1962. 'mod_topic_lock' => 3,
  1963. 'mod_topic_unlock' => 4,
  1964. 'mod_post_delete' => 5,
  1965. 'mod_topic_split' => 6,
  1966. 'adm_user_delete' => 7,
  1967. 'adm_user_ban' => 8,
  1968. 'adm_user_unban' => 9,
  1969. );
  1970. var $log_type_select = array();
  1971. var $log_disabled = false;
  1972. function init ()
  1973. {
  1974. global $lang, $bb_cfg;
  1975. foreach ($lang['LOG_ACTION']['LOG_TYPE'] as $log_type => $log_desc)
  1976. {
  1977. $this->log_type_select[strip_tags($log_desc)] = $this->log_type[$log_type];
  1978. }
  1979. }
  1980. function mod ($type_name, $args = array())
  1981. {
  1982. global $userdata;
  1983. if (empty($this->log_type)) $this->init();
  1984. if ($this->log_disabled) return;
  1985. $forum_id =& $args['forum_id'];
  1986. $forum_id_new =& $args['forum_id_new'];
  1987. $topic_id =& $args['topic_id'];
  1988. $topic_id_new =& $args['topic_id_new'];
  1989. $topic_title =& $args['topic_title'];
  1990. $topic_title_new =& $args['topic_title_new'];
  1991. $log_msg =& $args['log_msg'];
  1992. if (!empty($userdata))
  1993. {
  1994. $user_id = $userdata['user_id'];
  1995. $username = $userdata['username'];
  1996. $session_ip = $userdata['session_ip'];
  1997. }
  1998. else
  1999. {
  2000. $user_id = '';
  2001. $username = defined('IN_CRON') ? 'cron' : CLIENT_IP;
  2002. $session_ip = '';
  2003. }
  2004. $sql_ary = array(
  2005. 'log_type_id' => (int) $this->log_type["$type_name"],
  2006. 'log_user_id' => (int) $user_id,
  2007. 'log_username' => (string) $username,
  2008. 'log_user_ip' => (string) $session_ip,
  2009. 'log_forum_id' => (int) $forum_id,
  2010. 'log_forum_id_new' => (int) $forum_id_new,
  2011. 'log_topic_id' => (int) $topic_id,
  2012. 'log_topic_id_new' => (int) $topic_id_new,
  2013. 'log_topic_title' => (string) $topic_title,
  2014. 'log_topic_title_new' => (string) $topic_title_new,
  2015. 'log_time' => (int) TIMENOW,
  2016. 'log_msg' => (string) $log_msg,
  2017. );
  2018. $sql_args = DB()->build_array('INSERT', $sql_ary);
  2019. DB()->query("INSERT INTO ". BB_LOG ." $sql_args");
  2020. }
  2021. function admin ($type_name, $args = array())
  2022. {
  2023. $this->mod($type_name, $args);
  2024. }
  2025. }
  2026. function get_topic_icon ($topic, $is_unread = null)
  2027. {
  2028. global $bb_cfg, $images;
  2029. $t_hot = ($topic['topic_replies'] >= $bb_cfg['hot_threshold']);
  2030. $is_unread = is_null($is_unread) ? is_unread($topic['topic_last_post_time'], $topic['topic_id'], $topic['forum_id']) : $is_unread;
  2031. if ($topic['topic_status'] == TOPIC_MOVED)
  2032. {
  2033. $folder_image = $images['folder'];
  2034. }
  2035. else
  2036. {
  2037. $folder = ($t_hot) ? $images['folder_hot'] : $images['folder'];
  2038. $folder_new = ($t_hot) ? $images['folder_hot_new'] : $images['folder_new'];
  2039. if ($topic['topic_type'] == POST_ANNOUNCE)
  2040. {
  2041. $folder = $images['folder_announce'];
  2042. $folder_new = $images['folder_announce_new'];
  2043. }
  2044. else if ($topic['topic_type'] == POST_STICKY)
  2045. {
  2046. $folder = $images['folder_sticky'];
  2047. $folder_new = $images['folder_sticky_new'];
  2048. }
  2049. else if ($topic['topic_status'] == TOPIC_LOCKED)
  2050. {
  2051. $folder = $images['folder_locked'];
  2052. $folder_new = $images['folder_locked_new'];
  2053. }
  2054. else if ($topic['topic_dl_type'] == TOPIC_DL_TYPE_DL)
  2055. {
  2056. $folder = ($t_hot) ? $images['folder_dl_hot'] : $images['folder_dl'];
  2057. $folder_new = ($t_hot) ? $images['folder_dl_hot_new'] : $images['folder_dl_new'];
  2058. }
  2059. $folder_image = ($is_unread) ? $folder_new : $folder;
  2060. }
  2061. return $folder_image;
  2062. }
  2063. function build_topic_pagination ($url, $replies, $per_page)
  2064. {
  2065. $pg = '';
  2066. if (++$replies > $per_page)
  2067. {
  2068. $total_pages = ceil($replies / $per_page);
  2069. for ($j=0, $page=1; $j < $replies; $j += $per_page, $page++)
  2070. {
  2071. $href = ($j) ? "$url&amp;start=$j" : $url;
  2072. $pg .= '<a href="'. $href .'" class="topicPG">'. $page .'</a>';
  2073. if ($page == 1 && $total_pages > 3)
  2074. {
  2075. $pg .= ' .. ';
  2076. $page = $total_pages - 2;
  2077. $j += ($total_pages - 3) * $per_page;
  2078. }
  2079. else if ($page < $total_pages)
  2080. {
  2081. $pg .= ', ';
  2082. }
  2083. }
  2084. }
  2085. return $pg;
  2086. }
  2087. //
  2088. // Poll
  2089. //
  2090. function get_poll_data_items_js ($topic_id)
  2091. {
  2092. if (!$topic_id_csv = get_id_csv($topic_id))
  2093. {
  2094. return is_array($topic_id) ? array() : false;
  2095. }
  2096. $items = array();
  2097. if (!$poll_data = CACHE('bb_poll_data')->get("poll_$topic_id"))
  2098. {
  2099. $poll_data = DB()->fetch_rowset("
  2100. SELECT topic_id, vote_id, vote_text, vote_result
  2101. FROM ". BB_POLL_VOTES ."
  2102. WHERE topic_id IN($topic_id_csv)
  2103. ORDER BY topic_id, vote_id
  2104. ");
  2105. CACHE('bb_poll_data')->set("poll_$topic_id", $poll_data);
  2106. }
  2107. foreach ($poll_data as $row)
  2108. {
  2109. $opt_text_for_js = htmlCHR($row['vote_text']);
  2110. $opt_result_for_js = (int) $row['vote_result'];
  2111. $items[$row['topic_id']][$row['vote_id']] = array($opt_text_for_js, $opt_result_for_js);
  2112. }
  2113. foreach ($items as $k => $v)
  2114. {
  2115. $items[$k] = php2js($v);
  2116. }
  2117. return is_array($topic_id) ? $items : $items[$topic_id];
  2118. }
  2119. function poll_is_active ($t_data)
  2120. {
  2121. global $bb_cfg;
  2122. return ($t_data['topic_vote'] == 1 && $t_data['topic_time'] > TIMENOW - $bb_cfg['poll_max_days']*86400);
  2123. }
  2124. function print_confirmation ($tpl_vars)
  2125. {
  2126. global $template, $lang;
  2127. $template->assign_vars(array(
  2128. 'TPL_CONFIRM' => true,
  2129. 'CONFIRM_TITLE' => $lang['CONFIRM'],
  2130. 'FORM_METHOD' => 'post',
  2131. ));
  2132. $template->assign_vars($tpl_vars);
  2133. print_page('common.tpl');
  2134. }
  2135. /**
  2136. * $args = array(
  2137. * 'tpl' => 'template file name',
  2138. * 'simple' => $gen_simple_header,
  2139. * );
  2140. * OR (string) 'template_file_name'
  2141. *
  2142. * $type = '' (common forum page)
  2143. * 'admin' (adminCP page)
  2144. * 'simple' (simple page without common header)
  2145. *
  2146. * $mode = 'no_header'
  2147. * 'no_footer'
  2148. */
  2149. function print_page ($args, $type = '', $mode = '')
  2150. {
  2151. global $template, $gen_simple_header;
  2152. $tpl = (is_array($args) && !empty($args['tpl'])) ? $args['tpl'] : $args;
  2153. $tpl = ($type === 'admin') ? ADMIN_TPL_DIR . $tpl : $tpl;
  2154. $gen_simple_header = (is_array($args) && !empty($args['simple']) OR $type === 'simple') ? true : $gen_simple_header;
  2155. if ($mode !== 'no_header')
  2156. {
  2157. require(PAGE_HEADER);
  2158. }
  2159. $template->set_filenames(array('body' => $tpl));
  2160. $template->pparse('body');
  2161. if ($mode !== 'no_footer')
  2162. {
  2163. require(PAGE_FOOTER);
  2164. }
  2165. }
  2166. function caching_output ($enabled, $mode, $cache_var_name, $ttl = 300)
  2167. {
  2168. if (!$enabled || !CACHE('bb_cache')->used)
  2169. {
  2170. return;
  2171. }
  2172. if ($mode == 'send')
  2173. {
  2174. if ($cached_contents = CACHE('bb_cache')->get($cache_var_name))
  2175. {
  2176. bb_exit($cached_contents);
  2177. }
  2178. }
  2179. else if ($mode == 'store')
  2180. {
  2181. if ($output = ob_get_contents())
  2182. {
  2183. CACHE('bb_cache')->set($cache_var_name, $output, $ttl);
  2184. }
  2185. }
  2186. }
  2187. //
  2188. // Ajax
  2189. //
  2190. /**
  2191. * Encode PHP var to JSON (PHP -> JS)
  2192. */
  2193. function bb_json_encode ($data)
  2194. {
  2195. return json_encode($data);
  2196. }
  2197. /**
  2198. * Decode JSON to PHP (JS -> PHP)
  2199. */
  2200. function bb_json_decode ($data)
  2201. {
  2202. if (!is_string($data)) trigger_error('invalid argument for '. __FUNCTION__, E_USER_ERROR);
  2203. return json_decode($data, true);
  2204. }
  2205. /**
  2206. * -- from JsHttpRequest --
  2207. * Convert a PHP scalar, array or hash to JS scalar/array/hash. This function is
  2208. * an analog of json_encode(), but it can work with a non-UTF8 input and does not
  2209. * analyze the passed data. Output format must be fully JSON compatible.
  2210. *
  2211. * @param mixed $a Any structure to convert to JS.
  2212. * @return string JavaScript equivalent structure.
  2213. */
  2214. function php2js ($a = false)
  2215. {
  2216. if (is_null($a)) return 'null';
  2217. if ($a === false) return 'false';
  2218. if ($a === true) return 'true';
  2219. if (is_scalar($a))
  2220. {
  2221. if (is_float($a))
  2222. {
  2223. // Always use "." for floats.
  2224. $a = str_replace(",", ".", strval($a));
  2225. }
  2226. // All scalars are converted to strings to avoid indeterminism.
  2227. // PHP's "1" and 1 are equal for all PHP operators, but
  2228. // JS's "1" and 1 are not. So if we pass "1" or 1 from the PHP backend,
  2229. // we should get the same result in the JS frontend (string).
  2230. // Character replacements for JSON.
  2231. static $jsonReplaces = array(
  2232. array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'),
  2233. array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'),
  2234. );
  2235. return '"'. str_replace($jsonReplaces[0], $jsonReplaces[1], $a) .'"';
  2236. }
  2237. $isList = true;
  2238. for ($i = 0, reset($a); $i < count($a); $i++, next($a))
  2239. {
  2240. if (key($a) !== $i)
  2241. {
  2242. $isList = false;
  2243. break;
  2244. }
  2245. }
  2246. $result = array();
  2247. if ($isList)
  2248. {
  2249. foreach ($a as $v)
  2250. {
  2251. $result[] = php2js($v);
  2252. }
  2253. return '[ '. join(', ', $result) .' ]';
  2254. }
  2255. else
  2256. {
  2257. foreach ($a as $k => $v)
  2258. {
  2259. $result[] = php2js($k) .': '. php2js($v);
  2260. }
  2261. return '{ '. join(', ', $result) .' }';
  2262. }
  2263. }
  2264. function clean_title ($str, $replace_underscore = false)
  2265. {
  2266. $str = ($replace_underscore) ? str_replace('_', ' ', $str) : $str;
  2267. $str = htmlCHR(str_compact($str));
  2268. return $str;
  2269. }
  2270. function clean_text_match ($text, $ltrim_star = true, $remove_stopwords = false, $die_if_empty = false)
  2271. {
  2272. global $bb_cfg, $lang;
  2273. $text = str_compact($text);
  2274. $ltrim_chars = ($ltrim_star) ? ' *-!' : ' ';
  2275. $wrap_with_quotes = preg_match('#^"[^"]+"$#', $text);
  2276. # $min_word_len = max(2, $bb_cfg['search_min_word_len'] - 1);
  2277. # $max_word_len = $bb_cfg['search_max_word_len'];
  2278. # $text = preg_replace('#\b\w{1,'. $min_word_len .'}\b#', '', $text);
  2279. # $text = preg_replace('#\b\w{'. $max_word_len .',}\b#', '', $text);
  2280. $text = ' '. str_compact(ltrim($text, $ltrim_chars)) .' ';
  2281. if ($remove_stopwords)
  2282. {
  2283. $text = remove_stopwords($text);
  2284. }
  2285. if ($bb_cfg['search_engine_type'] == 'sphinx')
  2286. {
  2287. $text = preg_replace('#(?<=\S)\-#u', ' ', $text); // "1-2-3" -> "1 2 3"
  2288. $text = preg_replace('#[^0-9a-zA-Z?-??-???\-_*|]#u', ' ', $text); // ?????????? ??????? (????? " ??????? ????????)
  2289. $text = str_replace('-', ' -', $text); // - ?????? ? ?????? ?????
  2290. $text = str_replace('*', '* ', $text); // * ?????? ? ????? ?????
  2291. $text = preg_replace('#\s*\|\s*#u', '|', $text); // "| " -> "|"
  2292. $text = preg_replace('#\|+#u', ' | ', $text); // "||" -> "|"
  2293. $text = preg_replace('#(?<=\s)[\-*]+\s#u', ' ', $text); // ????????? " - ", " * "
  2294. $text = trim($text, ' -|');
  2295. $text = str_compact($text);
  2296. $text_match_sql = ($wrap_with_quotes && $text != '') ? '"'. $text .'"' : $text;
  2297. }
  2298. else
  2299. {
  2300. # if ($all_words)
  2301. # {
  2302. # $text = preg_replace('#\s(\b\w)#', ' +$1', $text);
  2303. # }
  2304. $text_match_sql = DB()->escape(trim($text));
  2305. }
  2306. if (!$text_match_sql && $die_if_empty)
  2307. {
  2308. bb_die($lang['NO_SEARCH_MATCH']);
  2309. }
  2310. return $text_match_sql;
  2311. }
  2312. function init_sphinx ()
  2313. {
  2314. global $sphinx;
  2315. if (!isset($sphinx))
  2316. {
  2317. require(INC_DIR .'sphinxapi.php');
  2318. $sphinx = new SphinxClient();
  2319. $sphinx->SetConnectTimeout(5);
  2320. # $sphinx->SetMaxQueryTime(2);
  2321. $sphinx->SetRankingMode(SPH_RANK_NONE);
  2322. $sphinx->SetMatchMode(SPH_MATCH_BOOLEAN);
  2323. # $sphinx->SetSortMode($mode, $sortby="");
  2324. }
  2325. }
  2326. function log_sphinx_error ($err_type, $err_msg, $query = '')
  2327. {
  2328. $ignore_err_txt = array(
  2329. 'negation on top level',
  2330. 'Query word length is less than min prefix length',
  2331. );
  2332. if (!count($ignore_err_txt) || !preg_match('#'. join('|', $ignore_err_txt) .'#i', $err_msg))
  2333. {
  2334. $orig_query = strtr($_REQUEST['nm'], array("\n" => '\n'));
  2335. bb_log(date('m-d H:i:s') ." | $err_type | $err_msg | $orig_query | $query". LOG_LF, 'sphinx_error');
  2336. }
  2337. }
  2338. function get_title_match_topics ($title_match_sql, $forum_ids = array())
  2339. {
  2340. global $bb_cfg, $sphinx, $userdata, $title_match, $lang;
  2341. $where_ids = array();
  2342. if($forum_ids) $forum_ids = array_diff($forum_ids, array(0 => 0));
  2343. $title_match_sql = encode_text_match($title_match_sql);
  2344. if ($bb_cfg['search_engine_type'] == 'sphinx')
  2345. {
  2346. init_sphinx();
  2347. $where = ($title_match) ? 'topics' : 'posts';
  2348. $sphinx->SetServer($bb_cfg['sphinx_topic_titles_host'], $bb_cfg['sphinx_topic_titles_port']);
  2349. if ($forum_ids)
  2350. {
  2351. $sphinx->SetFilter('forum_id', $forum_ids, false);
  2352. }
  2353. if (preg_match('#^"[^"]+"$#u', $title_match_sql))
  2354. {
  2355. $sphinx->SetMatchMode(SPH_MATCH_PHRASE);
  2356. }
  2357. if ($result = $sphinx->Query($title_match_sql, $where, $userdata['username'] .' ('. CLIENT_IP .')'))
  2358. {
  2359. if (!empty($result['matches']))
  2360. {
  2361. $where_ids = array_keys($result['matches']);
  2362. }
  2363. }
  2364. else if ($error = $sphinx->GetLastError())
  2365. {
  2366. if (strpos($error, 'errno=110'))
  2367. {
  2368. bb_die($lang['SEARCH_ERROR']);
  2369. }
  2370. log_sphinx_error('ERR', $error, $title_match_sql);
  2371. }
  2372. if ($warning = $sphinx->GetLastWarning())
  2373. {
  2374. log_sphinx_error('wrn', $warning, $title_match_sql);
  2375. }
  2376. }
  2377. else if ($bb_cfg['search_engine_type'] == 'mysql')
  2378. {
  2379. $where_forum = ($forum_ids) ? "AND forum_id IN(". join(',', $forum_ids) .")" : '';
  2380. $search_bool_mode = ($bb_cfg['allow_search_in_bool_mode']) ? ' IN BOOLEAN MODE' : '';
  2381. if($title_match)
  2382. {
  2383. $where_id = 'topic_id';
  2384. $sql = "SELECT topic_id FROM ". BB_TOPICS ."
  2385. WHERE MATCH (topic_title) AGAINST ('$title_match_sql'$search_bool_mode)
  2386. $where_forum";
  2387. }
  2388. else
  2389. {
  2390. $where_id = 'post_id';
  2391. $sql = "SELECT p.post_id FROM ". BB_POSTS ." p, ". BB_POSTS_SEARCH ." ps
  2392. WHERE ps.post_id = p.post_id
  2393. AND MATCH (ps.search_words) AGAINST ('$title_match_sql'$search_bool_mode)
  2394. $where_forum";
  2395. }
  2396. foreach (DB()->fetch_rowset($sql) as $row)
  2397. {
  2398. $where_ids[] = $row[$where_id];
  2399. }
  2400. }
  2401. else
  2402. {
  2403. bb_die($lang['SEARCH_OFF']);
  2404. }
  2405. return $where_ids;
  2406. }
  2407. // ??? ????? ??????????? ?????? ?? ?????? ?????????? ????????? ???????
  2408. function encode_text_match ($txt)
  2409. {
  2410. return str_replace("'", '&#039;', $txt);
  2411. }
  2412. function decode_text_match ($txt)
  2413. {
  2414. return str_replace('&#039;', "'", $txt);
  2415. }
  2416. function remove_stopwords ($text)
  2417. {
  2418. static $stopwords = null;
  2419. if (is_null($stopwords))
  2420. {
  2421. $stopwords = explode(' ', str_compact(@file_get_contents(LANG_DIR .'search_stopwords.txt')));
  2422. array_deep($stopwords, 'pad_with_space');
  2423. }
  2424. return ($stopwords) ? str_replace($stopwords, ' ', $text) : $text;
  2425. }
  2426. function pad_with_space ($str)
  2427. {
  2428. return ($str) ? " $str " : $str;
  2429. }
  2430. function create_magnet($infohash, $auth_key, $logged_in)
  2431. {
  2432. global $bb_cfg, $_GET, $userdata, $images;
  2433. $passkey_url = ((!$logged_in || isset($_GET['no_passkey'])) && $bb_cfg['bt_tor_browse_only_reg']) ? '' : "?{$bb_cfg['passkey_key']}=$auth_key";
  2434. return '<a href="magnet:?xt=urn:btih:'. bin2hex($infohash) .'&tr='. urlencode($bb_cfg['bt_announce_url'] . $passkey_url) .'"><img src="'. $images['icon_magnet'] .'" width="12" height="12" border="0" /></a>';
  2435. }
  2436. function set_die_append_msg ($forum_id = null, $topic_id = null)
  2437. {
  2438. global $lang, $template;
  2439. $msg = '';
  2440. $msg .= ($topic_id) ? '<p class="mrg_10"><a href="'. TOPIC_URL . $topic_id .'">'. $lang['TOPIC_RETURN'] .'</a></p>' : '';
  2441. $msg .= ($forum_id) ? '<p class="mrg_10"><a href="'. FORUM_URL . $forum_id .'">'. $lang['FORUM_RETURN'] .'</a></p>' : '';
  2442. $msg .= '<p class="mrg_10"><a href="index.php">'. $lang['INDEX_RETURN'] .'</a></p>';
  2443. $template->assign_var('BB_DIE_APPEND_MSG', $msg);
  2444. }
  2445. function set_pr_die_append_msg($pr_uid)
  2446. {
  2447. global $lang, $template;
  2448. $template->assign_var('BB_DIE_APPEND_MSG', '
  2449. <a href="'. PROFILE_URL . $pr_uid .'" onclick="return post2url(this.href, {after_edit: 1});">'. $lang['PROFILE_RETURN'] .'</a>
  2450. <br /><br />
  2451. <a href="profile.php?mode=editprofile'. (IS_ADMIN ? "&amp;u=$pr_uid" : '') .'" onclick="return post2url(this.href, {after_edit: 1});">'. $lang['PROFILE_EDIT_RETURN'] .'</a>
  2452. <br /><br />
  2453. <a href="index.php">'. $lang['INDEX_RETURN'] .'</a>
  2454. ');
  2455. }
  2456. function CAPTCHA ()
  2457. {
  2458. static $captcha_obj = null;
  2459. if ($captcha_obj === null)
  2460. {
  2461. global $bb_cfg;
  2462. require(INC_DIR .'captcha/captcha.php');
  2463. $captcha_obj = new captcha_kcaptcha($bb_cfg['captcha']);
  2464. }
  2465. return $captcha_obj;
  2466. }
  2467. function send_pm ($user_id, $subject, $message, $poster_id = BOT_UID)
  2468. {
  2469. global $userdata;
  2470. $subject = DB()->escape($subject);
  2471. $message = DB()->escape($message);
  2472. if ($poster_id == BOT_UID)
  2473. {
  2474. $poster_ip = '7f000001';
  2475. }
  2476. elseif ($row = DB()->fetch_row("SELECT user_reg_ip FROM ". BB_USERS ." WHERE user_id = $poster_id"))
  2477. {
  2478. $poster_ip = $row['user_reg_ip'];
  2479. }
  2480. else
  2481. {
  2482. $poster_id = $userdata['user_id'];
  2483. $poster_ip = USER_IP;
  2484. }
  2485. DB()->sql_query("INSERT INTO ". BB_PRIVMSGS ." (privmsgs_type, privmsgs_subject, privmsgs_from_userid, privmsgs_to_userid, privmsgs_date, privmsgs_ip)
  2486. VALUES (". PRIVMSGS_NEW_MAIL .", '$subject', {$poster_id}, $user_id, ". TIMENOW .", '$poster_ip')");
  2487. $pm_id = DB()->sql_nextid();
  2488. DB()->sql_query("INSERT INTO " . BB_PRIVMSGS_TEXT . " (privmsgs_text_id, privmsgs_text)
  2489. VALUES ($pm_id, '$message')");
  2490. DB()->sql_query("UPDATE ". BB_USERS ." SET
  2491. user_new_privmsg = user_new_privmsg + 1,
  2492. user_last_privmsg = ". TIMENOW .",
  2493. user_newest_pm_id = $pm_id
  2494. WHERE user_id = $user_id");
  2495. }
  2496. function profile_url ($data)
  2497. {
  2498. global $bb_cfg, $lang, $datastore;
  2499. if (!$ranks = $datastore->get('ranks'))
  2500. {
  2501. $datastore->update('ranks');
  2502. $ranks = $datastore->get('ranks');
  2503. }
  2504. $user_rank = !empty($data['user_rank']) ? $data['user_rank'] : 0;
  2505. if (isset($ranks[$user_rank]))
  2506. {
  2507. $title = $ranks[$user_rank]['rank_title'];
  2508. $style = $ranks[$user_rank]['rank_style'];
  2509. }
  2510. if (empty($title)) $title = $lang['USER'];
  2511. if (empty($style)) $style = 'colorUser';
  2512. if (!$bb_cfg['color_nick']) $style = '';
  2513. $username = !empty($data['username']) ? $data['username'] : $lang['GUEST'];
  2514. $user_id = (!empty($data['user_id']) && $username != $lang['GUEST']) ? $data['user_id'] : GUEST_UID;
  2515. $profile = '<span title="'. $title .'" class="'. $style .'">'. $username .'</span>';
  2516. if (!in_array($user_id, array('', GUEST_UID, BOT_UID)) && $username)
  2517. {
  2518. $profile = '<a href="'. make_url(PROFILE_URL . $user_id) .'">'. $profile .'</a>';
  2519. }
  2520. return $profile;
  2521. }
  2522. function get_avatar ($user_id, $ext_id, $allow_avatar = true, $size = true)
  2523. {
  2524. global $bb_cfg;
  2525. if ($size)
  2526. {
  2527. // TODO
  2528. }
  2529. $user_avatar = '<img src="'. $bb_cfg['avatars']['upload_path'] . $bb_cfg['avatars']['no_avatar'] .'" alt="'. $user_id .'" "/>';
  2530. if ($user_id == BOT_UID && $bb_cfg['avatars']['bot_avatar'])
  2531. {
  2532. $user_avatar = '<img src="'. $bb_cfg['avatars']['upload_path'] . $bb_cfg['avatars']['bot_avatar'] .'" alt="'. $user_id .'" />';
  2533. }
  2534. elseif ($allow_avatar && $ext_id)
  2535. {
  2536. $user_avatar = '<img src="'. $bb_cfg['avatars']['upload_path'] . get_avatar_path($user_id, $ext_id) .'" alt="'. $user_id .'" />';
  2537. }
  2538. return $user_avatar;
  2539. }