merge? merge.
[phpbb.git] / phpBB / includes / functions_posting.php
blobe59ecca30a46fcc9a1a6bb10dcc3c7a8e1ac170b
1 <?php
2 /**
4 * @package phpBB3
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * Fill smiley templates (or just the variables) with smilies, either in a window or inline
22 function generate_smilies($mode, $forum_id)
24 global $auth, $db, $user, $config, $template;
26 if ($mode == 'window')
28 if ($forum_id)
30 $sql = 'SELECT forum_style
31 FROM ' . FORUMS_TABLE . "
32 WHERE forum_id = $forum_id";
33 $result = $db->sql_query_limit($sql, 1);
34 $row = $db->sql_fetchrow($result);
35 $db->sql_freeresult($result);
37 $user->setup('posting', (int) $row['forum_style']);
39 else
41 $user->setup('posting');
44 page_header($user->lang['SMILIES']);
46 $template->set_filenames(array(
47 'body' => 'posting_smilies.html')
51 $display_link = false;
52 if ($mode == 'inline')
54 $sql = 'SELECT smiley_id
55 FROM ' . SMILIES_TABLE . '
56 WHERE display_on_posting = 0';
57 $result = $db->sql_query_limit($sql, 1, 0, 3600);
59 if ($row = $db->sql_fetchrow($result))
61 $display_link = true;
63 $db->sql_freeresult($result);
66 $last_url = '';
68 $sql = 'SELECT *
69 FROM ' . SMILIES_TABLE .
70 (($mode == 'inline') ? ' WHERE display_on_posting = 1 ' : '') . '
71 ORDER BY smiley_order';
72 $result = $db->sql_query($sql, 3600);
74 $smilies = array();
75 while ($row = $db->sql_fetchrow($result))
77 if (empty($smilies[$row['smiley_url']]))
79 $smilies[$row['smiley_url']] = $row;
82 $db->sql_freeresult($result);
84 if (sizeof($smilies))
86 foreach ($smilies as $row)
88 $template->assign_block_vars('smiley', array(
89 'SMILEY_CODE' => $row['code'],
90 'A_SMILEY_CODE' => addslashes($row['code']),
91 'SMILEY_IMG' => PHPBB_ROOT_PATH . $config['smilies_path'] . '/' . $row['smiley_url'],
92 'SMILEY_WIDTH' => $row['smiley_width'],
93 'SMILEY_HEIGHT' => $row['smiley_height'],
94 'SMILEY_DESC' => $row['emotion'])
99 if ($mode == 'inline' && $display_link)
101 $template->assign_vars(array(
102 'S_SHOW_SMILEY_LINK' => true,
103 'U_MORE_SMILIES' => append_sid('posting', 'mode=smilies&amp;f=' . $forum_id))
107 if ($mode == 'window')
109 page_footer();
114 * Update last post information
115 * Should be used instead of sync() if only the last post information are out of sync... faster
117 * @param string $type Can be forum|topic
118 * @param mixed $ids topic/forum ids
119 * @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL
121 function update_post_information($type, $ids, $return_update_sql = false)
123 global $db;
125 if (empty($ids))
127 return;
129 if (!is_array($ids))
131 $ids = array($ids);
135 $update_sql = $empty_forums = $not_empty_forums = array();
137 if ($type != 'topic')
139 $topic_join = ', ' . TOPICS_TABLE . ' t';
140 $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_approved = 1';
142 else
144 $topic_join = '';
145 $topic_condition = '';
148 if (sizeof($ids) == 1)
150 $sql = 'SELECT MAX(p.post_id) as last_post_id
151 FROM ' . POSTS_TABLE . " p $topic_join
152 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
153 $topic_condition
154 AND p.post_approved = 1";
156 else
158 $sql = 'SELECT p.' . $type . '_id, MAX(p.post_id) as last_post_id
159 FROM ' . POSTS_TABLE . " p $topic_join
160 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
161 $topic_condition
162 AND p.post_approved = 1
163 GROUP BY p.{$type}_id";
165 $result = $db->sql_query($sql);
167 $last_post_ids = array();
168 while ($row = $db->sql_fetchrow($result))
170 if (sizeof($ids) == 1)
172 $row[$type . '_id'] = $ids[0];
175 if ($type == 'forum')
177 $not_empty_forums[] = $row['forum_id'];
179 if (empty($row['last_post_id']))
181 $empty_forums[] = $row['forum_id'];
185 $last_post_ids[] = $row['last_post_id'];
187 $db->sql_freeresult($result);
189 if ($type == 'forum')
191 $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums));
193 foreach ($empty_forums as $void => $forum_id)
195 $update_sql[$forum_id][] = 'forum_last_post_id = 0';
196 $update_sql[$forum_id][] = "forum_last_post_subject = ''";
197 $update_sql[$forum_id][] = 'forum_last_post_time = 0';
198 $update_sql[$forum_id][] = 'forum_last_poster_id = 0';
199 $update_sql[$forum_id][] = "forum_last_poster_name = ''";
200 $update_sql[$forum_id][] = "forum_last_poster_colour = ''";
204 if (sizeof($last_post_ids))
206 $sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
207 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
208 WHERE p.poster_id = u.user_id
209 AND ' . $db->sql_in_set('p.post_id', $last_post_ids);
210 $result = $db->sql_query($sql);
212 while ($row = $db->sql_fetchrow($result))
214 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id'];
215 $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
216 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time'];
217 $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id'];
218 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
219 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'";
221 $db->sql_freeresult($result);
223 unset($empty_forums, $ids, $last_post_ids);
225 if ($return_update_sql || !sizeof($update_sql))
227 return $update_sql;
230 $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE;
232 foreach ($update_sql as $update_id => $update_sql_ary)
234 $sql = "UPDATE $table
235 SET " . implode(', ', $update_sql_ary) . "
236 WHERE {$type}_id = $update_id";
237 $db->sql_query($sql);
240 return;
244 * Generate Topic Icons for display
246 function posting_gen_topic_icons($mode, $icon_id)
248 global $config, $template, $cache;
250 // Grab icons
251 $icons = cache::obtain_icons();
253 if (!$icon_id)
255 $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"');
258 if (sizeof($icons))
260 foreach ($icons as $id => $data)
262 if ($data['display'])
264 $template->assign_block_vars('topic_icon', array(
265 'ICON_ID' => $id,
266 'ICON_IMG' => PHPBB_ROOT_PATH . $config['icons_path'] . '/' . $data['img'],
267 'ICON_WIDTH' => $data['width'],
268 'ICON_HEIGHT' => $data['height'],
270 'S_CHECKED' => ($id == $icon_id) ? true : false,
271 'S_ICON_CHECKED' => ($id == $icon_id) ? ' checked="checked"' : '')
276 return true;
279 return false;
283 * Build topic types able to be selected
285 function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
287 global $auth, $user, $template, $topic_type;
289 $toggle = false;
291 $topic_types = array(
292 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
293 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
294 'global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
297 $topic_type_array = array();
299 foreach ($topic_types as $auth_key => $topic_value)
301 // We do not have a special post global announcement permission
302 $auth_key = ($auth_key == 'global') ? 'announce' : $auth_key;
304 if ($auth->acl_get('f_' . $auth_key, $forum_id))
306 $toggle = true;
308 $topic_type_array[] = array(
309 'VALUE' => $topic_value['const'],
310 'S_CHECKED' => ($cur_topic_type == $topic_value['const'] || ($forum_id == 0 && $topic_value['const'] == POST_GLOBAL)) ? ' checked="checked"' : '',
311 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']]
316 if ($toggle)
318 $topic_type_array = array_merge(array(0 => array(
319 'VALUE' => POST_NORMAL,
320 'S_CHECKED' => ($topic_type == POST_NORMAL) ? ' checked="checked"' : '',
321 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])),
323 $topic_type_array
326 foreach ($topic_type_array as $array)
328 $template->assign_block_vars('topic_type', $array);
331 $template->assign_vars(array(
332 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)),
333 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_get('f_announce', $forum_id)))
337 return $toggle;
341 // Attachment related functions
345 * Upload Attachment - filedata is generated here
346 * Uses upload class
348 function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false)
350 global $auth, $user, $config, $db, $cache;
352 $filedata = array(
353 'error' => array()
356 include_once(PHPBB_ROOT_PATH . 'includes/functions_upload.' . PHP_EXT);
357 $upload = new fileupload();
359 if ($config['check_attachment_content'])
361 $upload->set_disallowed_content(explode('|', $config['mime_triggers']));
364 if (!$local)
366 $filedata['post_attach'] = ($upload->is_valid($form_name)) ? true : false;
368 else
370 $filedata['post_attach'] = true;
373 if (!$filedata['post_attach'])
375 $filedata['error'][] = $user->lang['NO_UPLOAD_FORM_FOUND'];
376 return $filedata;
379 $extensions = cache::obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
380 $upload->set_allowed_extensions(array_keys($extensions['_allowed_']));
382 $file = ($local) ? $upload->local_upload($local_storage, $local_filedata) : $upload->form_upload($form_name);
384 if ($file->init_error)
386 $filedata['post_attach'] = false;
387 return $filedata;
390 $cat_id = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] : ATTACHMENT_CATEGORY_NONE;
392 // Make sure the image category only holds valid images...
393 if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image())
395 $file->remove();
397 // If this error occurs a user tried to exploit an IE Bug by renaming extensions
398 // Since the image category is displaying content inline we need to catch this.
399 trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
402 // Do we have to create a thumbnail?
403 $filedata['thumbnail'] = ($cat_id == ATTACHMENT_CATEGORY_IMAGE && $config['img_create_thumbnail']) ? 1 : 0;
405 // Check Image Size, if it is an image
406 if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id) && $cat_id == ATTACHMENT_CATEGORY_IMAGE)
408 $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
411 // Admins and mods are allowed to exceed the allowed filesize
412 if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id))
414 if (!empty($extensions[$file->get('extension')]['max_filesize']))
416 $allowed_filesize = $extensions[$file->get('extension')]['max_filesize'];
418 else
420 $allowed_filesize = ($is_message) ? $config['max_filesize_pm'] : $config['max_filesize'];
423 $file->upload->set_max_filesize($allowed_filesize);
426 $file->clean_filename('unique', $user->data['user_id'] . '_');
428 // Are we uploading an image *and* this image being within the image category? Only then perform additional image checks.
429 $no_image = ($cat_id == ATTACHMENT_CATEGORY_IMAGE) ? false : true;
431 $file->move_file($config['upload_path'], false, $no_image);
433 if (sizeof($file->error))
435 $file->remove();
436 $filedata['error'] = array_merge($filedata['error'], $file->error);
437 $filedata['post_attach'] = false;
439 return $filedata;
442 $filedata['filesize'] = $file->get('filesize');
443 $filedata['mimetype'] = $file->get('mimetype');
444 $filedata['extension'] = $file->get('extension');
445 $filedata['physical_filename'] = $file->get('realname');
446 $filedata['real_filename'] = $file->get('uploadname');
447 $filedata['filetime'] = time();
449 // Check our complete quota
450 if ($config['attachment_quota'])
452 if ($config['upload_dir_size'] + $file->get('filesize') > $config['attachment_quota'])
454 $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
455 $filedata['post_attach'] = false;
457 $file->remove();
459 return $filedata;
463 // Check free disk space
464 if ($free_space = @disk_free_space(PHPBB_ROOT_PATH . $config['upload_path']))
466 if ($free_space <= $file->get('filesize'))
468 $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
469 $filedata['post_attach'] = false;
471 $file->remove();
473 return $filedata;
477 // Create Thumbnail
478 if ($filedata['thumbnail'])
480 $source = $file->get('destination_file');
481 $destination = $file->get('destination_path') . '/thumb_' . $file->get('realname');
483 if (!create_thumbnail($source, $destination, $file->get('mimetype')))
485 $filedata['thumbnail'] = 0;
489 return $filedata;
493 * Calculate the needed size for Thumbnail
495 function get_img_size_format($width, $height)
497 global $config;
499 // Maximum Width the Image can take
500 $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400;
502 if ($width > $height)
504 return array(
505 round($width * ($max_width / $width)),
506 round($height * ($max_width / $width))
509 else
511 return array(
512 round($width * ($max_width / $height)),
513 round($height * ($max_width / $height))
519 * Return supported image types
521 function get_supported_image_types($type = false)
523 if (@extension_loaded('gd'))
525 $format = imagetypes();
526 $new_type = 0;
528 if ($type !== false)
530 // Type is one of the IMAGETYPE constants - it is fetched from getimagesize()
531 // We do not use the constants here, because some were not available in PHP 4.3.x
532 switch ($type)
534 // GIF
535 case 1:
536 $new_type = ($format & IMG_GIF) ? IMG_GIF : false;
537 break;
539 // JPG, JPC, JP2
540 case 2:
541 case 9:
542 case 10:
543 case 11:
544 case 12:
545 $new_type = ($format & IMG_JPG) ? IMG_JPG : false;
546 break;
548 // PNG
549 case 3:
550 $new_type = ($format & IMG_PNG) ? IMG_PNG : false;
551 break;
553 // WBMP
554 case 15:
555 $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false;
556 break;
559 else
561 $new_type = array();
562 $go_through_types = array(IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP);
564 foreach ($go_through_types as $check_type)
566 if ($format & $check_type)
568 $new_type[] = $check_type;
573 return array(
574 'gd' => ($new_type) ? true : false,
575 'format' => $new_type,
576 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1
580 return array('gd' => false);
584 * Create Thumbnail
586 function create_thumbnail($source, $destination, $mimetype)
588 global $config;
590 $min_filesize = (int) $config['img_min_thumb_filesize'];
591 $img_filesize = (file_exists($source)) ? @filesize($source) : false;
593 if (!$img_filesize || $img_filesize <= $min_filesize)
595 return false;
598 $dimension = @getimagesize($source);
600 if ($dimension === false)
602 return false;
605 list($width, $height, $type, ) = $dimension;
607 if (empty($width) || empty($height))
609 return false;
612 list($new_width, $new_height) = get_img_size_format($width, $height);
614 // Do not create a thumbnail if the resulting width/height is bigger than the original one
615 if ($new_width > $width && $new_height > $height)
617 return false;
620 $used_imagick = false;
622 // Only use imagemagick if defined and the passthru function not disabled
623 if ($config['img_imagick'] && function_exists('passthru'))
625 if (substr($config['img_imagick'], -1) !== '/')
627 $config['img_imagick'] .= '/';
630 @passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -antialias -sample ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" +profile "*" "' . str_replace('\\', '/', $destination) . '"');
632 if (file_exists($destination))
634 $used_imagick = true;
638 if (!$used_imagick)
640 $type = get_supported_image_types($type);
642 if ($type['gd'])
644 // If the type is not supported, we are not able to create a thumbnail
645 if ($type['format'] === false)
647 return false;
650 switch ($type['format'])
652 case IMG_GIF:
653 $image = @imagecreatefromgif($source);
654 break;
656 case IMG_JPG:
657 $image = @imagecreatefromjpeg($source);
658 break;
660 case IMG_PNG:
661 $image = @imagecreatefrompng($source);
662 break;
664 case IMG_WBMP:
665 $image = @imagecreatefromwbmp($source);
666 break;
669 if ($type['version'] == 1)
671 $new_image = imagecreate($new_width, $new_height);
673 if ($new_image === false)
675 return false;
678 imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
680 else
682 $new_image = imagecreatetruecolor($new_width, $new_height);
684 if ($new_image === false)
686 return false;
689 imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
692 // If we are in safe mode create the destination file prior to using the gd functions to circumvent a PHP bug
693 if (@ini_get('safe_mode') || @strtolower(ini_get('safe_mode')) == 'on')
695 @touch($destination);
698 switch ($type['format'])
700 case IMG_GIF:
701 imagegif($new_image, $destination);
702 break;
704 case IMG_JPG:
705 imagejpeg($new_image, $destination, 90);
706 break;
708 case IMG_PNG:
709 imagepng($new_image, $destination);
710 break;
712 case IMG_WBMP:
713 imagewbmp($new_image, $destination);
714 break;
717 imagedestroy($new_image);
719 else
721 return false;
725 if (!file_exists($destination))
727 return false;
730 @chmod($destination, 0666);
732 return true;
736 * Assign Inline attachments (build option fields)
738 function posting_gen_inline_attachments(&$attachment_data)
740 global $template;
742 if (sizeof($attachment_data))
744 $s_inline_attachment_options = '';
746 foreach ($attachment_data as $i => $attachment)
748 $s_inline_attachment_options .= '<option value="' . $i . '">' . basename($attachment['real_filename']) . '</option>';
751 $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options);
753 return true;
756 return false;
760 * Generate inline attachment entry
762 function posting_gen_attachment_entry($attachment_data, &$filename_data)
764 global $template, $config, $user;
766 $template->assign_vars(array(
767 'S_SHOW_ATTACH_BOX' => true)
770 if (sizeof($attachment_data))
772 $template->assign_vars(array(
773 'S_HAS_ATTACHMENTS' => true)
776 // We display the posted attachments within the desired order.
777 ($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data);
779 foreach ($attachment_data as $count => $attach_row)
781 $hidden = '';
782 $attach_row['real_filename'] = basename($attach_row['real_filename']);
784 foreach ($attach_row as $key => $value)
786 $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />';
789 $download_link = append_sid('download/file', 'mode=view&amp;id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false);
791 $template->assign_block_vars('attach_row', array(
792 'FILENAME' => basename($attach_row['real_filename']),
793 'A_FILENAME' => addslashes(basename($attach_row['real_filename'])),
794 'FILE_COMMENT' => $attach_row['attach_comment'],
795 'ATTACH_ID' => $attach_row['attach_id'],
796 'S_IS_ORPHAN' => $attach_row['is_orphan'],
797 'ASSOC_INDEX' => $count,
799 'U_VIEW_ATTACHMENT' => $download_link,
800 'S_HIDDEN' => $hidden)
805 $template->assign_vars(array(
806 'FILE_COMMENT' => $filename_data['filecomment'],
807 'FILESIZE' => $config['max_filesize'])
810 return sizeof($attachment_data);
814 // General Post functions
818 * Load Drafts
820 function load_drafts($topic_id = 0, $forum_id = 0, $id = 0)
822 global $user, $db, $template, $auth;
824 $topic_ids = $forum_ids = $draft_rows = array();
826 // Load those drafts not connected to forums/topics
827 // If forum_id == 0 AND topic_id == 0 then this is a PM draft
828 if (!$topic_id && !$forum_id)
830 $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0';
832 else
834 $sql_and = '';
835 $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : '';
836 $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : '';
839 $sql = 'SELECT d.*, f.forum_id, f.forum_name
840 FROM ' . DRAFTS_TABLE . ' d
841 LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id)
842 WHERE d.user_id = ' . $user->data['user_id'] . "
843 $sql_and
844 ORDER BY d.save_time DESC";
845 $result = $db->sql_query($sql);
847 while ($row = $db->sql_fetchrow($result))
849 if ($row['topic_id'])
851 $topic_ids[] = (int) $row['topic_id'];
853 $draft_rows[] = $row;
855 $db->sql_freeresult($result);
857 if (!sizeof($draft_rows))
859 return;
862 $topic_rows = array();
863 if (sizeof($topic_ids))
865 $sql = 'SELECT topic_id, forum_id, topic_title
866 FROM ' . TOPICS_TABLE . '
867 WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids));
868 $result = $db->sql_query($sql);
870 while ($row = $db->sql_fetchrow($result))
872 $topic_rows[$row['topic_id']] = $row;
874 $db->sql_freeresult($result);
876 unset($topic_ids);
878 $template->assign_var('S_SHOW_DRAFTS', true);
880 foreach ($draft_rows as $draft)
882 $link_topic = $link_forum = $link_pm = false;
883 $insert_url = $view_url = $title = '';
885 if (isset($topic_rows[$draft['topic_id']])
886 && (
887 ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id']))
889 (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read'))
892 $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id;
894 $link_topic = true;
895 $view_url = append_sid('viewtopic', 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id']);
896 $title = $topic_rows[$draft['topic_id']]['topic_title'];
898 $insert_url = append_sid('posting', 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id'] . '&amp;mode=reply&amp;d=' . $draft['draft_id']);
900 else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id']))
902 $link_forum = true;
903 $view_url = append_sid('viewforum', 'f=' . $draft['forum_id']);
904 $title = $draft['forum_name'];
906 $insert_url = append_sid('posting', 'f=' . $draft['forum_id'] . '&amp;mode=post&amp;d=' . $draft['draft_id']);
908 else
910 // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards...
911 $link_pm = true;
912 $insert_url = append_sid('ucp', "i=$id&amp;mode=compose&amp;d={$draft['draft_id']}");
915 $template->assign_block_vars('draftrow', array(
916 'DRAFT_ID' => $draft['draft_id'],
917 'DATE' => $user->format_date($draft['save_time']),
918 'DRAFT_SUBJECT' => $draft['draft_subject'],
920 'TITLE' => $title,
921 'U_VIEW' => $view_url,
922 'U_INSERT' => $insert_url,
924 'S_LINK_PM' => $link_pm,
925 'S_LINK_TOPIC' => $link_topic,
926 'S_LINK_FORUM' => $link_forum)
932 * Topic Review
934 function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
936 global $user, $auth, $db, $template, $bbcode, $cache, $config;
938 // Go ahead and pull all data for this topic
939 $sql = 'SELECT p.post_id
940 FROM ' . POSTS_TABLE . ' p' . "
941 WHERE p.topic_id = $topic_id
942 " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . '
943 ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . '
944 ORDER BY p.post_time ';
945 $sql .= ($mode == 'post_review') ? 'ASC' : 'DESC';
946 $result = $db->sql_query_limit($sql, $config['posts_per_page']);
948 $post_list = array();
950 while ($row = $db->sql_fetchrow($result))
952 $post_list[] = $row['post_id'];
955 $db->sql_freeresult($result);
957 if (!sizeof($post_list))
959 return false;
962 $sql = $db->sql_build_query('SELECT', array(
963 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*',
965 'FROM' => array(
966 USERS_TABLE => 'u',
967 POSTS_TABLE => 'p',
970 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . '
971 AND u.user_id = p.poster_id'
974 $result = $db->sql_query($sql);
976 $bbcode_bitfield = '';
977 $rowset = array();
978 $has_attachments = false;
979 while ($row = $db->sql_fetchrow($result))
981 $rowset[$row['post_id']] = $row;
982 $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
984 if ($row['post_attachment'])
986 $has_attachments = true;
989 $db->sql_freeresult($result);
991 // Instantiate BBCode class
992 if (!isset($bbcode) && $bbcode_bitfield !== '')
994 include_once(PHPBB_ROOT_PATH . 'includes/bbcode.' . PHP_EXT);
995 $bbcode = new bbcode(base64_encode($bbcode_bitfield));
998 // Grab extensions
999 $extensions = $attachments = array();
1000 if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
1002 $extensions = cache::obtain_attach_extensions($forum_id);
1004 // Get attachments...
1005 $sql = 'SELECT *
1006 FROM ' . ATTACHMENTS_TABLE . '
1007 WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . '
1008 AND in_message = 0
1009 ORDER BY filetime DESC, post_msg_id ASC';
1010 $result = $db->sql_query($sql);
1012 while ($row = $db->sql_fetchrow($result))
1014 $attachments[$row['post_msg_id']][] = $row;
1016 $db->sql_freeresult($result);
1019 for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
1021 // A non-existing rowset only happens if there was no user present for the entered poster_id
1022 // This could be a broken posts table.
1023 if (!isset($rowset[$post_list[$i]]))
1025 continue;
1028 $row =& $rowset[$post_list[$i]];
1030 $poster_id = $row['user_id'];
1031 $post_subject = $row['post_subject'];
1032 $message = censor_text($row['post_text']);
1034 $decoded_message = false;
1036 if ($show_quote_button && $auth->acl_get('f_reply', $forum_id))
1038 $decoded_message = $message;
1039 decode_message($decoded_message, $row['bbcode_uid']);
1041 $decoded_message = bbcode_nl2br($decoded_message);
1044 if ($row['bbcode_bitfield'])
1046 $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
1049 $message = bbcode_nl2br($message);
1050 $message = smiley_text($message, !$row['enable_smilies']);
1052 if (!empty($attachments[$row['post_id']]))
1054 $update_count = array();
1055 parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
1058 $post_subject = censor_text($post_subject);
1060 $template->assign_block_vars($mode . '_row', array(
1061 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1062 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1063 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1064 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1066 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false,
1068 'POST_SUBJECT' => $post_subject,
1069 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']),
1070 'POST_DATE' => $user->format_date($row['post_time']),
1071 'MESSAGE' => $message,
1072 'DECODED_MESSAGE' => $decoded_message,
1073 'POST_ID' => $row['post_id'],
1074 'U_MINI_POST' => append_sid('viewtopic', 'p=' . $row['post_id']) . '#p' . $row['post_id'],
1075 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid('mcp', 'i=main&amp;mode=post_details&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
1076 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '')
1079 // Display not already displayed Attachments for this post, we already parsed them. ;)
1080 if (!empty($attachments[$row['post_id']]))
1082 foreach ($attachments[$row['post_id']] as $attachment)
1084 $template->assign_block_vars($mode . '_row.attachment', array(
1085 'DISPLAY_ATTACHMENT' => $attachment)
1090 unset($rowset[$i]);
1093 if ($mode == 'topic_review')
1095 $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']));
1098 return true;
1102 * User Notification
1104 function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id)
1106 global $db, $user, $config, $auth;
1108 $topic_notification = ($mode == 'reply' || $mode == 'quote') ? true : false;
1109 $forum_notification = ($mode == 'post') ? true : false;
1111 if (!$topic_notification && !$forum_notification)
1113 trigger_error('WRONG_NOTIFICATION_MODE');
1116 if (($topic_notification && !$config['allow_topic_notify']) || ($forum_notification && !$config['allow_forum_notify']))
1118 return;
1121 $topic_title = ($topic_notification) ? $topic_title : $subject;
1122 $topic_title = censor_text($topic_title);
1124 // Get banned User ID's
1125 $sql = 'SELECT ban_userid
1126 FROM ' . BANLIST_TABLE . '
1127 WHERE ban_userid <> 0
1128 AND ban_exclude <> 1';
1129 $result = $db->sql_query($sql);
1131 $sql_ignore_users = ANONYMOUS . ', ' . $user->data['user_id'];
1132 while ($row = $db->sql_fetchrow($result))
1134 $sql_ignore_users .= ', ' . (int) $row['ban_userid'];
1136 $db->sql_freeresult($result);
1138 $notify_rows = array();
1140 // -- get forum_userids || topic_userids
1141 $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
1142 FROM ' . (($topic_notification) ? TOPICS_WATCH_TABLE : FORUMS_WATCH_TABLE) . ' w, ' . USERS_TABLE . ' u
1143 WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . "
1144 AND w.user_id NOT IN ($sql_ignore_users)
1145 AND w.notify_status = 0
1146 AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')
1147 AND u.user_id = w.user_id';
1148 $result = $db->sql_query($sql);
1150 while ($row = $db->sql_fetchrow($result))
1152 $notify_rows[$row['user_id']] = array(
1153 'user_id' => $row['user_id'],
1154 'username' => $row['username'],
1155 'user_email' => $row['user_email'],
1156 'user_jabber' => $row['user_jabber'],
1157 'user_lang' => $row['user_lang'],
1158 'notify_type' => ($topic_notification) ? 'topic' : 'forum',
1159 'template' => ($topic_notification) ? 'topic_notify' : 'newtopic_notify',
1160 'method' => $row['user_notify_type'],
1161 'allowed' => false
1164 $db->sql_freeresult($result);
1166 // forum notification is sent to those not already receiving topic notifications
1167 if ($topic_notification)
1169 if (sizeof($notify_rows))
1171 $sql_ignore_users .= ', ' . implode(', ', array_keys($notify_rows));
1174 $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
1175 FROM ' . FORUMS_WATCH_TABLE . ' fw, ' . USERS_TABLE . " u
1176 WHERE fw.forum_id = $forum_id
1177 AND fw.user_id NOT IN ($sql_ignore_users)
1178 AND fw.notify_status = 0
1179 AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')
1180 AND u.user_id = fw.user_id';
1181 $result = $db->sql_query($sql);
1183 while ($row = $db->sql_fetchrow($result))
1185 $notify_rows[$row['user_id']] = array(
1186 'user_id' => $row['user_id'],
1187 'username' => $row['username'],
1188 'user_email' => $row['user_email'],
1189 'user_jabber' => $row['user_jabber'],
1190 'user_lang' => $row['user_lang'],
1191 'notify_type' => 'forum',
1192 'template' => 'forum_notify',
1193 'method' => $row['user_notify_type'],
1194 'allowed' => false
1197 $db->sql_freeresult($result);
1200 if (!sizeof($notify_rows))
1202 return;
1205 // Make sure users are allowed to read the forum
1206 foreach ($auth->acl_get_list(array_keys($notify_rows), 'f_read', $forum_id) as $forum_id => $forum_ary)
1208 foreach ($forum_ary as $auth_option => $user_ary)
1210 foreach ($user_ary as $user_id)
1212 $notify_rows[$user_id]['allowed'] = true;
1218 // Now, we have to do a little step before really sending, we need to distinguish our users a little bit. ;)
1219 $msg_users = $delete_ids = $update_notification = array();
1220 foreach ($notify_rows as $user_id => $row)
1222 if (!$row['allowed'] || !trim($row['user_email']))
1224 $delete_ids[$row['notify_type']][] = $row['user_id'];
1226 else
1228 $msg_users[] = $row;
1229 $update_notification[$row['notify_type']][] = $row['user_id'];
1232 unset($notify_rows);
1234 // Now, we are able to really send out notifications
1235 if (sizeof($msg_users))
1237 include_once(PHPBB_ROOT_PATH . 'includes/functions_messenger.' . PHP_EXT);
1238 $messenger = new messenger();
1240 $msg_list_ary = array();
1241 foreach ($msg_users as $row)
1243 $pos = (!isset($msg_list_ary[$row['template']])) ? 0 : sizeof($msg_list_ary[$row['template']]);
1245 $msg_list_ary[$row['template']][$pos]['method'] = $row['method'];
1246 $msg_list_ary[$row['template']][$pos]['email'] = $row['user_email'];
1247 $msg_list_ary[$row['template']][$pos]['jabber'] = $row['user_jabber'];
1248 $msg_list_ary[$row['template']][$pos]['name'] = $row['username'];
1249 $msg_list_ary[$row['template']][$pos]['lang'] = $row['user_lang'];
1251 unset($msg_users);
1253 foreach ($msg_list_ary as $email_template => $email_list)
1255 foreach ($email_list as $addr)
1257 $messenger->template($email_template, $addr['lang']);
1259 $messenger->to($addr['email'], $addr['name']);
1260 $messenger->im($addr['jabber'], $addr['name']);
1262 $messenger->assign_vars(array(
1263 'USERNAME' => htmlspecialchars_decode($addr['name']),
1264 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title),
1265 'FORUM_NAME' => htmlspecialchars_decode($forum_name),
1267 'U_FORUM' => generate_board_url() . '/viewforum.' . PHP_EXT . "?f=$forum_id",
1268 'U_TOPIC' => generate_board_url() . '/viewtopic.' . PHP_EXT . "?f=$forum_id&t=$topic_id",
1269 'U_NEWEST_POST' => generate_board_url() . '/viewtopic.' . PHP_EXT . "?f=$forum_id&t=$topic_id&p=$post_id&e=$post_id",
1270 'U_STOP_WATCHING_TOPIC' => generate_board_url() . '/viewtopic.' . PHP_EXT . "?f=$forum_id&t=$topic_id&unwatch=topic",
1271 'U_STOP_WATCHING_FORUM' => generate_board_url() . '/viewforum.' . PHP_EXT . "?f=$forum_id&unwatch=forum",
1274 $messenger->send($addr['method']);
1277 unset($msg_list_ary);
1279 $messenger->save_queue();
1282 // Handle the DB updates
1283 $db->sql_transaction('begin');
1285 if (!empty($update_notification['topic']))
1287 $sql = 'UPDATE ' . TOPICS_WATCH_TABLE . "
1288 SET notify_status = 1
1289 WHERE topic_id = $topic_id
1290 AND " . $db->sql_in_set('user_id', $update_notification['topic']);
1291 $db->sql_query($sql);
1294 if (!empty($update_notification['forum']))
1296 $sql = 'UPDATE ' . FORUMS_WATCH_TABLE . "
1297 SET notify_status = 1
1298 WHERE forum_id = $forum_id
1299 AND " . $db->sql_in_set('user_id', $update_notification['forum']);
1300 $db->sql_query($sql);
1303 // Now delete the user_ids not authorised to receive notifications on this topic/forum
1304 if (!empty($delete_ids['topic']))
1306 $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . "
1307 WHERE topic_id = $topic_id
1308 AND " . $db->sql_in_set('user_id', $delete_ids['topic']);
1309 $db->sql_query($sql);
1312 if (!empty($delete_ids['forum']))
1314 $sql = 'DELETE FROM ' . FORUMS_WATCH_TABLE . "
1315 WHERE forum_id = $forum_id
1316 AND " . $db->sql_in_set('user_id', $delete_ids['forum']);
1317 $db->sql_query($sql);
1320 $db->sql_transaction('commit');
1324 // Post handling functions
1328 * Delete Post
1330 function delete_post($forum_id, $topic_id, $post_id, &$data)
1332 global $db, $user, $auth, $config;
1334 // Specify our post mode
1335 $post_mode = 'delete';
1336 if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && $data['topic_replies_real'] == 0)
1338 $post_mode = 'delete_topic';
1340 else if ($data['topic_first_post_id'] == $post_id)
1342 $post_mode = 'delete_first_post';
1344 else if ($data['topic_last_post_id'] == $post_id)
1346 $post_mode = 'delete_last_post';
1348 $sql_data = array();
1349 $next_post_id = false;
1351 include_once(PHPBB_ROOT_PATH . 'includes/functions_admin.' . PHP_EXT);
1353 $db->sql_transaction('begin');
1355 // we must make sure to update forums that contain the shadow'd topic
1356 if ($post_mode == 'delete_topic')
1358 $shadow_forum_ids = array();
1360 $sql = 'SELECT forum_id
1361 FROM ' . TOPICS_TABLE . '
1362 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id);
1363 $result = $db->sql_query($sql);
1364 while ($row = $db->sql_fetchrow($result))
1366 if (!isset($shadow_forum_ids[(int) $row['forum_id']]))
1368 $shadow_forum_ids[(int) $row['forum_id']] = 1;
1370 else
1372 $shadow_forum_ids[(int) $row['forum_id']]++;
1375 $db->sql_freeresult($result);
1378 if (!delete_posts('post_id', array($post_id), false, false))
1380 // Try to delete topic, we may had an previous error causing inconsistency
1381 if ($post_mode == 'delete_topic')
1383 delete_topics('topic_id', array($topic_id), false);
1385 trigger_error('ALREADY_DELETED');
1388 $db->sql_transaction('commit');
1390 // Collect the necessary information for updating the tables
1391 $sql_data[FORUMS_TABLE] = '';
1392 switch ($post_mode)
1394 case 'delete_topic':
1396 foreach ($shadow_forum_ids as $updated_forum => $topic_count)
1398 // counting is fun! we only have to do sizeof($forum_ids) number of queries,
1399 // even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
1400 $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_topics_real = forum_topics_real - ' . $topic_count . ', forum_topics = forum_topics - ' . $topic_count . ' WHERE forum_id = ' . $updated_forum);
1401 update_post_information('forum', $updated_forum);
1404 delete_topics('topic_id', array($topic_id), false);
1406 if ($data['topic_type'] != POST_GLOBAL)
1408 $sql_data[FORUMS_TABLE] .= 'forum_topics_real = forum_topics_real - 1';
1409 $sql_data[FORUMS_TABLE] .= ($data['topic_approved']) ? ', forum_posts = forum_posts - 1, forum_topics = forum_topics - 1' : '';
1412 $update_sql = update_post_information('forum', $forum_id, true);
1413 if (sizeof($update_sql))
1415 $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
1416 $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
1418 break;
1420 case 'delete_first_post':
1421 $sql = 'SELECT p.post_id, p.poster_id, p.post_username, u.username, u.user_colour
1422 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
1423 WHERE p.topic_id = $topic_id
1424 AND p.poster_id = u.user_id
1425 ORDER BY p.post_time ASC";
1426 $result = $db->sql_query_limit($sql, 1);
1427 $row = $db->sql_fetchrow($result);
1428 $db->sql_freeresult($result);
1430 if ($data['topic_type'] != POST_GLOBAL)
1432 $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
1435 $sql_data[TOPICS_TABLE] = 'topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . "', topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'";
1437 // Decrementing topic_replies here is fine because this case only happens if there is more than one post within the topic - basically removing one "reply"
1438 $sql_data[TOPICS_TABLE] .= ', topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
1440 $next_post_id = (int) $row['post_id'];
1441 break;
1443 case 'delete_last_post':
1444 if ($data['topic_type'] != POST_GLOBAL)
1446 $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
1449 $update_sql = update_post_information('forum', $forum_id, true);
1450 if (sizeof($update_sql))
1452 $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
1453 $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
1456 $sql_data[TOPICS_TABLE] = 'topic_bumped = 0, topic_bumper = 0, topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
1458 $update_sql = update_post_information('topic', $topic_id, true);
1459 if (sizeof($update_sql))
1461 $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
1462 $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
1464 else
1466 $sql = 'SELECT MAX(post_id) as last_post_id
1467 FROM ' . POSTS_TABLE . "
1468 WHERE topic_id = $topic_id " .
1469 ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : '');
1470 $result = $db->sql_query($sql);
1471 $row = $db->sql_fetchrow($result);
1472 $db->sql_freeresult($result);
1474 $next_post_id = (int) $row['last_post_id'];
1476 break;
1478 case 'delete':
1479 $sql = 'SELECT post_id
1480 FROM ' . POSTS_TABLE . "
1481 WHERE topic_id = $topic_id " .
1482 ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : '') . '
1483 AND post_time > ' . $data['post_time'] . '
1484 ORDER BY post_time ASC';
1485 $result = $db->sql_query_limit($sql, 1);
1486 $row = $db->sql_fetchrow($result);
1487 $db->sql_freeresult($result);
1489 if ($data['topic_type'] != POST_GLOBAL)
1491 $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
1494 $sql_data[TOPICS_TABLE] = 'topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
1495 $next_post_id = (int) $row['post_id'];
1496 break;
1499 // $sql_data[USERS_TABLE] = ($data['post_postcount']) ? 'user_posts = user_posts - 1' : '';
1501 $db->sql_transaction('begin');
1503 $where_sql = array(
1504 FORUMS_TABLE => "forum_id = $forum_id",
1505 TOPICS_TABLE => "topic_id = $topic_id",
1506 USERS_TABLE => 'user_id = ' . $data['poster_id']
1509 foreach ($sql_data as $table => $update_sql)
1511 if ($update_sql)
1513 $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]);
1517 // Adjust posted info for this user by looking for a post by him/her within this topic...
1518 if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS)
1520 $sql = 'SELECT poster_id
1521 FROM ' . POSTS_TABLE . '
1522 WHERE topic_id = ' . $topic_id . '
1523 AND poster_id = ' . $data['poster_id'];
1524 $result = $db->sql_query_limit($sql, 1);
1525 $poster_id = (int) $db->sql_fetchfield('poster_id');
1526 $db->sql_freeresult($result);
1528 // The user is not having any more posts within this topic
1529 if (!$poster_id)
1531 $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
1532 WHERE topic_id = ' . $topic_id . '
1533 AND user_id = ' . $data['poster_id'];
1534 $db->sql_query($sql);
1538 $db->sql_transaction('commit');
1540 if ($data['post_reported'] && ($post_mode != 'delete_topic'))
1542 sync('topic_reported', 'topic_id', array($topic_id));
1545 return $next_post_id;
1549 * Submit Post
1551 function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true)
1553 global $db, $auth, $user, $config, $template;
1555 // We do not handle erasing posts here
1556 if ($mode == 'delete')
1558 return false;
1561 $current_time = time();
1563 if ($mode == 'post')
1565 $post_mode = 'post';
1566 $update_message = true;
1568 else if ($mode != 'edit')
1570 $post_mode = 'reply';
1571 $update_message = true;
1573 else if ($mode == 'edit')
1575 $post_mode = ($data['topic_replies_real'] == 0) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit'));
1578 // First of all make sure the subject and topic title are having the correct length.
1579 // To achieve this without cutting off between special chars we convert to an array and then count the elements.
1580 $subject = truncate_string($subject);
1581 $data['topic_title'] = truncate_string($data['topic_title']);
1583 // Collect some basic information about which tables and which rows to update/insert
1584 $sql_data = $topic_row = array();
1585 $poster_id = ($mode == 'edit') ? $data['poster_id'] : (int) $user->data['user_id'];
1587 // Retrieve some additional information if not present
1588 if ($mode == 'edit' && (!isset($data['post_approved']) || !isset($data['topic_approved']) || $data['post_approved'] === false || $data['topic_approved'] === false))
1590 $sql = 'SELECT p.post_approved, t.topic_type, t.topic_replies, t.topic_replies_real, t.topic_approved
1591 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
1592 WHERE t.topic_id = p.topic_id
1593 AND p.post_id = ' . $data['post_id'];
1594 $result = $db->sql_query($sql);
1595 $topic_row = $db->sql_fetchrow($result);
1596 $db->sql_freeresult($result);
1598 $data['topic_approved'] = $topic_row['topic_approved'];
1599 $data['post_approved'] = $topic_row['post_approved'];
1602 // Start the transaction here
1603 $db->sql_transaction('begin');
1606 // Collect Information
1607 switch ($post_mode)
1609 case 'post':
1610 case 'reply':
1611 $sql_data[POSTS_TABLE]['sql'] = array(
1612 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
1613 'poster_id' => (int) $user->data['user_id'],
1614 'icon_id' => $data['icon_id'],
1615 'poster_ip' => $user->ip,
1616 'post_time' => $current_time,
1617 'post_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : 1,
1618 'enable_bbcode' => $data['enable_bbcode'],
1619 'enable_smilies' => $data['enable_smilies'],
1620 'enable_magic_url' => $data['enable_urls'],
1621 'enable_sig' => $data['enable_sig'],
1622 'post_username' => (!$user->data['is_registered']) ? $username : '',
1623 'post_subject' => $subject,
1624 'post_text' => $data['message'],
1625 'post_checksum' => $data['message_md5'],
1626 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
1627 'bbcode_bitfield' => $data['bbcode_bitfield'],
1628 'bbcode_uid' => $data['bbcode_uid'],
1629 'post_postcount' => ($auth->acl_get('f_postcount', $data['forum_id'])) ? 1 : 0,
1630 'post_edit_locked' => $data['post_edit_locked']
1632 break;
1634 case 'edit_first_post':
1635 case 'edit':
1637 case 'edit_last_post':
1638 case 'edit_topic':
1640 // If edit reason is given always display edit info
1642 // If editing last post then display no edit info
1643 // If m_edit permission then display no edit info
1644 // If normal edit display edit info
1646 // Display edit info if edit reason given or user is editing his post, which is not the last within the topic.
1647 if ($data['post_edit_reason'] || (!$auth->acl_get('m_edit', $data['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
1649 $data['post_edit_reason'] = truncate_string($data['post_edit_reason'], 255, 255, false);
1651 $sql_data[POSTS_TABLE]['sql'] = array(
1652 'post_edit_time' => $current_time,
1653 'post_edit_reason' => $data['post_edit_reason'],
1654 'post_edit_user' => (int) $data['post_edit_user'],
1657 $sql_data[POSTS_TABLE]['stat'][] = 'post_edit_count = post_edit_count + 1';
1659 else if (!$data['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data['forum_id']))
1661 $sql_data[POSTS_TABLE]['sql'] = array(
1662 'post_edit_reason' => '',
1666 // If the person editing this post is different to the one having posted then we will add a log entry stating the edit
1667 // Could be simplified by only adding to the log if the edit is not tracked - but this may confuse admins/mods
1668 if ($user->data['user_id'] != $poster_id)
1670 $log_subject = ($subject) ? $subject : $data['topic_title'];
1671 add_log('mod', $data['forum_id'], $data['topic_id'], 'LOG_POST_EDITED', $log_subject, (!empty($username)) ? $username : $user->lang['GUEST']);
1674 if (!isset($sql_data[POSTS_TABLE]['sql']))
1676 $sql_data[POSTS_TABLE]['sql'] = array();
1679 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1680 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
1681 'poster_id' => $data['poster_id'],
1682 'icon_id' => $data['icon_id'],
1683 'post_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : $data['post_approved'],
1684 'enable_bbcode' => $data['enable_bbcode'],
1685 'enable_smilies' => $data['enable_smilies'],
1686 'enable_magic_url' => $data['enable_urls'],
1687 'enable_sig' => $data['enable_sig'],
1688 'post_username' => ($username && $data['poster_id'] == ANONYMOUS) ? $username : '',
1689 'post_subject' => $subject,
1690 'post_checksum' => $data['message_md5'],
1691 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
1692 'bbcode_bitfield' => $data['bbcode_bitfield'],
1693 'bbcode_uid' => $data['bbcode_uid'],
1694 'post_edit_locked' => $data['post_edit_locked'])
1697 if ($update_message)
1699 $sql_data[POSTS_TABLE]['sql']['post_text'] = $data['message'];
1702 break;
1705 $post_approved = $sql_data[POSTS_TABLE]['sql']['post_approved'];
1706 $topic_row = array();
1708 // And the topic ladies and gentlemen
1709 switch ($post_mode)
1711 case 'post':
1712 $sql_data[TOPICS_TABLE]['sql'] = array(
1713 'topic_poster' => (int) $user->data['user_id'],
1714 'topic_time' => $current_time,
1715 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
1716 'icon_id' => $data['icon_id'],
1717 'topic_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : 1,
1718 'topic_title' => $subject,
1719 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
1720 'topic_first_poster_colour' => $user->data['user_colour'],
1721 'topic_type' => $topic_type,
1722 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
1723 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
1726 if (isset($poll['poll_options']) && !empty($poll['poll_options']))
1728 $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array(
1729 'poll_title' => $poll['poll_title'],
1730 'poll_start' => ($poll['poll_start']) ? $poll['poll_start'] : $current_time,
1731 'poll_max_options' => $poll['poll_max_options'],
1732 'poll_length' => ($poll['poll_length'] * 86400),
1733 'poll_vote_change' => $poll['poll_vote_change'])
1737 $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id'])) ? ', user_posts = user_posts + 1' : '');
1739 if ($topic_type != POST_GLOBAL)
1741 if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id']))
1743 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
1745 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) ? ', forum_topics = forum_topics + 1' : '');
1747 break;
1749 case 'reply':
1750 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies_real = topic_replies_real + 1, topic_bumped = 0, topic_bumper = 0' . (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) ? ', topic_replies = topic_replies + 1' : '') . ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : '');
1752 $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id'])) ? ', user_posts = user_posts + 1' : '');
1754 if (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) && $topic_type != POST_GLOBAL)
1756 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
1758 break;
1760 case 'edit_topic':
1761 case 'edit_first_post':
1763 $sql_data[TOPICS_TABLE]['sql'] = array(
1764 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
1765 'icon_id' => $data['icon_id'],
1766 'topic_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : $data['topic_approved'],
1767 'topic_title' => $subject,
1768 'topic_first_poster_name' => $username,
1769 'topic_type' => $topic_type,
1770 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
1771 'poll_title' => (isset($poll['poll_options'])) ? $poll['poll_title'] : '',
1772 'poll_start' => (isset($poll['poll_options'])) ? (($poll['poll_start']) ? $poll['poll_start'] : $current_time) : 0,
1773 'poll_max_options' => (isset($poll['poll_options'])) ? $poll['poll_max_options'] : 1,
1774 'poll_length' => (isset($poll['poll_options'])) ? ($poll['poll_length'] * 86400) : 0,
1775 'poll_vote_change' => (isset($poll['poll_vote_change'])) ? $poll['poll_vote_change'] : 0,
1777 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0),
1780 // Correctly set back the topic replies and forum posts... only if the topic was approved before and now gets disapproved
1781 if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && $data['topic_approved'])
1783 // Do we need to grab some topic informations?
1784 if (!sizeof($topic_row))
1786 $sql = 'SELECT topic_type, topic_replies, topic_replies_real, topic_approved
1787 FROM ' . TOPICS_TABLE . '
1788 WHERE topic_id = ' . $data['topic_id'];
1789 $result = $db->sql_query($sql);
1790 $topic_row = $db->sql_fetchrow($result);
1791 $db->sql_freeresult($result);
1794 // If this is the only post remaining we do not need to decrement topic_replies.
1795 // Also do not decrement if first post - then the topic_replies will not be adjusted if approving the topic again.
1797 // If this is an edited topic or the first post the topic gets completely disapproved later on...
1798 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics = forum_topics - 1';
1799 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - ' . ($topic_row['topic_replies'] + 1);
1801 set_config('num_topics', $config['num_topics'] - 1, true);
1802 set_config('num_posts', $config['num_posts'] - ($topic_row['topic_replies'] + 1), true);
1805 break;
1807 case 'edit':
1808 case 'edit_last_post':
1810 // Correctly set back the topic replies and forum posts... but only if the post was approved before.
1811 if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && $data['post_approved'])
1813 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies = topic_replies - 1';
1814 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - 1';
1816 set_config('num_posts', $config['num_posts'] - 1, true);
1819 break;
1822 // Submit new topic
1823 if ($post_mode == 'post')
1825 $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' .
1826 $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']);
1827 $db->sql_query($sql);
1829 $data['topic_id'] = $db->sql_nextid();
1831 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1832 'topic_id' => $data['topic_id'])
1834 unset($sql_data[TOPICS_TABLE]['sql']);
1837 // Submit new post
1838 if ($post_mode == 'post' || $post_mode == 'reply')
1840 if ($post_mode == 'reply')
1842 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1843 'topic_id' => $data['topic_id'])
1847 $sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
1848 $db->sql_query($sql);
1849 $data['post_id'] = $db->sql_nextid();
1851 if ($post_mode == 'post')
1853 $sql_data[TOPICS_TABLE]['sql'] = array(
1854 'topic_first_post_id' => $data['post_id'],
1855 'topic_last_post_id' => $data['post_id'],
1856 'topic_last_post_time' => $current_time,
1857 'topic_last_poster_id' => (int) $user->data['user_id'],
1858 'topic_last_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
1859 'topic_last_poster_colour' => $user->data['user_colour'],
1860 'topic_last_post_subject' => (string) $subject,
1864 unset($sql_data[POSTS_TABLE]['sql']);
1867 $make_global = false;
1869 // Are we globalising or unglobalising?
1870 if ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic')
1872 if (!sizeof($topic_row))
1874 $sql = 'SELECT topic_type, topic_replies, topic_replies_real, topic_approved, topic_last_post_id
1875 FROM ' . TOPICS_TABLE . '
1876 WHERE topic_id = ' . $data['topic_id'];
1877 $result = $db->sql_query($sql);
1878 $topic_row = $db->sql_fetchrow($result);
1879 $db->sql_freeresult($result);
1882 // globalise/unglobalise?
1883 if (($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL) || ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL))
1885 if (!empty($sql_data[FORUMS_TABLE]['stat']) && implode('', $sql_data[FORUMS_TABLE]['stat']))
1887 $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET ' . implode(', ', $sql_data[FORUMS_TABLE]['stat']) . ' WHERE forum_id = ' . $data['forum_id']);
1890 $make_global = true;
1891 $sql_data[FORUMS_TABLE]['stat'] = array();
1894 // globalise
1895 if ($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL)
1897 // Decrement topic/post count
1898 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - ' . ($topic_row['topic_replies_real'] + 1);
1899 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real - 1' . (($topic_row['topic_approved']) ? ', forum_topics = forum_topics - 1' : '');
1901 // Update forum_ids for all posts
1902 $sql = 'UPDATE ' . POSTS_TABLE . '
1903 SET forum_id = 0
1904 WHERE topic_id = ' . $data['topic_id'];
1905 $db->sql_query($sql);
1907 // unglobalise
1908 else if ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL)
1910 // Increment topic/post count
1911 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + ' . ($topic_row['topic_replies_real'] + 1);
1912 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($topic_row['topic_approved']) ? ', forum_topics = forum_topics + 1' : '');
1914 // Update forum_ids for all posts
1915 $sql = 'UPDATE ' . POSTS_TABLE . '
1916 SET forum_id = ' . $data['forum_id'] . '
1917 WHERE topic_id = ' . $data['topic_id'];
1918 $db->sql_query($sql);
1922 // Update the topics table
1923 if (isset($sql_data[TOPICS_TABLE]['sql']))
1925 $sql = 'UPDATE ' . TOPICS_TABLE . '
1926 SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
1927 WHERE topic_id = ' . $data['topic_id'];
1928 $db->sql_query($sql);
1931 // Update the posts table
1932 if (isset($sql_data[POSTS_TABLE]['sql']))
1934 $sql = 'UPDATE ' . POSTS_TABLE . '
1935 SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
1936 WHERE post_id = ' . $data['post_id'];
1937 $db->sql_query($sql);
1940 // Update Poll Tables
1941 if (isset($poll['poll_options']) && !empty($poll['poll_options']))
1943 $cur_poll_options = array();
1945 if ($poll['poll_start'] && $mode == 'edit')
1947 $sql = 'SELECT *
1948 FROM ' . POLL_OPTIONS_TABLE . '
1949 WHERE topic_id = ' . $data['topic_id'] . '
1950 ORDER BY poll_option_id';
1951 $result = $db->sql_query($sql);
1953 $cur_poll_options = array();
1954 while ($row = $db->sql_fetchrow($result))
1956 $cur_poll_options[] = $row;
1958 $db->sql_freeresult($result);
1961 $sql_insert_ary = array();
1963 for ($i = 0, $size = sizeof($poll['poll_options']); $i < $size; $i++)
1965 if (strlen(trim($poll['poll_options'][$i])))
1967 if (empty($cur_poll_options[$i]))
1969 // If we add options we need to put them to the end to be able to preserve votes...
1970 $sql_insert_ary[] = array(
1971 'poll_option_id' => (int) sizeof($cur_poll_options) + 1 + sizeof($sql_insert_ary),
1972 'topic_id' => (int) $data['topic_id'],
1973 'poll_option_text' => (string) $poll['poll_options'][$i]
1976 else if ($poll['poll_options'][$i] != $cur_poll_options[$i])
1978 $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
1979 SET poll_option_text = '" . $db->sql_escape($poll['poll_options'][$i]) . "'
1980 WHERE poll_option_id = " . $cur_poll_options[$i]['poll_option_id'] . '
1981 AND topic_id = ' . $data['topic_id'];
1982 $db->sql_query($sql);
1987 $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary);
1989 if (sizeof($poll['poll_options']) < sizeof($cur_poll_options))
1991 $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . '
1992 WHERE poll_option_id > ' . sizeof($poll['poll_options']) . '
1993 AND topic_id = ' . $data['topic_id'];
1994 $db->sql_query($sql);
1997 // If edited, we would need to reset votes (since options can be re-ordered above, you can't be sure if the change is for changing the text or adding an option
1998 if ($mode == 'edit' && sizeof($poll['poll_options']) != sizeof($cur_poll_options))
2000 $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data['topic_id']);
2001 $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data['topic_id']);
2005 // Submit Attachments
2006 if (!empty($data['attachment_data']) && $data['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
2008 $space_taken = $files_added = 0;
2009 $orphan_rows = array();
2011 foreach ($data['attachment_data'] as $pos => $attach_row)
2013 $orphan_rows[(int) $attach_row['attach_id']] = array();
2016 if (sizeof($orphan_rows))
2018 $sql = 'SELECT attach_id, filesize, physical_filename
2019 FROM ' . ATTACHMENTS_TABLE . '
2020 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
2021 AND is_orphan = 1
2022 AND poster_id = ' . $user->data['user_id'];
2023 $result = $db->sql_query($sql);
2025 $orphan_rows = array();
2026 while ($row = $db->sql_fetchrow($result))
2028 $orphan_rows[$row['attach_id']] = $row;
2030 $db->sql_freeresult($result);
2033 foreach ($data['attachment_data'] as $pos => $attach_row)
2035 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
2037 continue;
2040 if (!$attach_row['is_orphan'])
2042 // update entry in db if attachment already stored in db and filespace
2043 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
2044 SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
2045 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
2046 AND is_orphan = 0';
2047 $db->sql_query($sql);
2049 else
2051 // insert attachment into db
2052 if (!@file_exists(PHPBB_ROOT_PATH . $config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
2054 continue;
2057 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
2058 $files_added++;
2060 $attach_sql = array(
2061 'post_msg_id' => $data['post_id'],
2062 'topic_id' => $data['topic_id'],
2063 'is_orphan' => 0,
2064 'poster_id' => $poster_id,
2065 'attach_comment' => $attach_row['attach_comment'],
2068 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
2069 WHERE attach_id = ' . $attach_row['attach_id'] . '
2070 AND is_orphan = 1
2071 AND poster_id = ' . $user->data['user_id'];
2072 $db->sql_query($sql);
2076 if ($space_taken && $files_added)
2078 set_config('upload_dir_size', $config['upload_dir_size'] + $space_taken, true);
2079 set_config('num_files', $config['num_files'] + $files_added, true);
2083 // we need to update the last forum information
2084 // only applicable if the topic is not global and it is approved
2085 // we also check to make sure we are not dealing with globaling the latest topic (pretty rare but still needs to be checked)
2086 if ($topic_type != POST_GLOBAL && !$make_global && ($post_approved || !$data['post_approved']))
2088 // the last post makes us update the forum table. This can happen if...
2089 // We make a new topic
2090 // We reply to a topic
2091 // We edit the last post in a topic and this post is the latest in the forum (maybe)
2092 // We edit the only post in the topic
2093 // We edit the first post in the topic and all the other posts are not approved
2094 if (($post_mode == 'post' || $post_mode == 'reply') && $post_approved)
2096 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id'];
2097 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
2098 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
2099 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
2100 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
2101 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
2103 else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies']))
2105 // this does not _necessarily_ mean that we must update the info again,
2106 // it just means that we might have to
2107 $sql = 'SELECT forum_last_post_id, forum_last_post_subject
2108 FROM ' . FORUMS_TABLE . '
2109 WHERE forum_id = ' . (int) $data['forum_id'];
2110 $result = $db->sql_query($sql);
2111 $row = $db->sql_fetchrow($result);
2112 $db->sql_freeresult($result);
2114 // this post is the latest post in the forum, better update
2115 if ($row['forum_last_post_id'] == $data['post_id'])
2117 if ($post_approved && $row['forum_last_post_subject'] !== $subject)
2119 // the only data that can really be changed is the post's subject
2120 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_subject = \'' . $db->sql_escape($subject) . '\'';
2122 else if ($data['post_approved'] !== $post_approved)
2124 // we need a fresh change of socks, everything has become invalidated
2125 $sql = 'SELECT MAX(topic_last_post_id) as last_post_id
2126 FROM ' . TOPICS_TABLE . '
2127 WHERE forum_id = ' . (int) $data['forum_id'] . '
2128 AND topic_approved = 1';
2129 $result = $db->sql_query($sql);
2130 $row = $db->sql_fetchrow($result);
2131 $db->sql_freeresult($result);
2133 // any posts left in this forum?
2134 if (!empty($row['last_post_id']))
2136 $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
2137 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
2138 WHERE p.poster_id = u.user_id
2139 AND p.post_id = ' . (int) $row['last_post_id'];
2140 $result = $db->sql_query($sql);
2141 $row = $db->sql_fetchrow($result);
2142 $db->sql_freeresult($result);
2144 // salvation, a post is found! jam it into the forums table
2145 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id'];
2146 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
2147 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time'];
2148 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id'];
2149 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
2150 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
2152 else
2154 // just our luck, the last topic in the forum has just been turned unapproved...
2155 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = 0';
2156 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = ''";
2157 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = 0';
2158 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = 0';
2159 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = ''";
2160 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = ''";
2166 else if ($make_global)
2168 // somebody decided to be a party pooper, we must recalculate the whole shebang (maybe)
2169 $sql = 'SELECT forum_last_post_id
2170 FROM ' . FORUMS_TABLE . '
2171 WHERE forum_id = ' . (int) $data['forum_id'];
2172 $result = $db->sql_query($sql);
2173 $forum_row = $db->sql_fetchrow($result);
2174 $db->sql_freeresult($result);
2176 // we made a topic global, go get new data
2177 if ($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL && $forum_row['forum_last_post_id'] == $topic_row['topic_last_post_id'])
2179 // we need a fresh change of socks, everything has become invalidated
2180 $sql = 'SELECT MAX(topic_last_post_id) as last_post_id
2181 FROM ' . TOPICS_TABLE . '
2182 WHERE forum_id = ' . (int) $data['forum_id'] . '
2183 AND topic_approved = 1';
2184 $result = $db->sql_query($sql);
2185 $row = $db->sql_fetchrow($result);
2186 $db->sql_freeresult($result);
2188 // any posts left in this forum?
2189 if (!empty($row['last_post_id']))
2191 $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
2192 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
2193 WHERE p.poster_id = u.user_id
2194 AND p.post_id = ' . (int) $row['last_post_id'];
2195 $result = $db->sql_query($sql);
2196 $row = $db->sql_fetchrow($result);
2197 $db->sql_freeresult($result);
2199 // salvation, a post is found! jam it into the forums table
2200 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id'];
2201 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
2202 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time'];
2203 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id'];
2204 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
2205 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
2207 else
2209 // just our luck, the last topic in the forum has just been globalized...
2210 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = 0';
2211 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = ''";
2212 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = 0';
2213 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = 0';
2214 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = ''";
2215 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = ''";
2218 else if ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL && $forum_row['forum_last_post_id'] < $topic_row['topic_last_post_id'])
2220 // this post has a higher id, it is newer
2221 $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
2222 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
2223 WHERE p.poster_id = u.user_id
2224 AND p.post_id = ' . (int) $topic_row['topic_last_post_id'];
2225 $result = $db->sql_query($sql);
2226 $row = $db->sql_fetchrow($result);
2227 $db->sql_freeresult($result);
2229 // salvation, a post is found! jam it into the forums table
2230 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id'];
2231 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
2232 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time'];
2233 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id'];
2234 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
2235 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
2239 // topic sync time!
2240 // simply, we update if it is a reply or the last post is edited
2241 if ($post_approved)
2243 // reply requires the whole thing
2244 if ($post_mode == 'reply')
2246 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $data['post_id'];
2247 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $user->data['user_id'];
2248 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
2249 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . (($user->data['user_id'] != ANONYMOUS) ? $db->sql_escape($user->data['user_colour']) : '') . "'";
2250 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
2251 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $current_time;
2253 else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies']))
2255 // only the subject can be changed from edit
2256 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
2259 else if (!$data['post_approved'] && ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies'])))
2261 // like having the rug pulled from under us
2262 $sql = 'SELECT MAX(post_id) as last_post_id
2263 FROM ' . POSTS_TABLE . '
2264 WHERE topic_id = ' . (int) $data['topic_id'] . '
2265 AND post_approved = 1';
2266 $result = $db->sql_query($sql);
2267 $row = $db->sql_fetchrow($result);
2268 $db->sql_freeresult($result);
2270 // any posts left in this forum?
2271 if (!empty($row['last_post_id']))
2273 $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
2274 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
2275 WHERE p.poster_id = u.user_id
2276 AND p.post_id = ' . (int) $row['last_post_id'];
2277 $result = $db->sql_query($sql);
2278 $row = $db->sql_fetchrow($result);
2279 $db->sql_freeresult($result);
2281 // salvation, a post is found! jam it into the topics table
2282 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $row['post_id'];
2283 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
2284 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $row['post_time'];
2285 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $row['poster_id'];
2286 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
2287 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
2291 // Update total post count, do not consider moderated posts/topics
2292 if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id']))
2294 if ($post_mode == 'post')
2296 set_config('num_topics', $config['num_topics'] + 1, true);
2297 set_config('num_posts', $config['num_posts'] + 1, true);
2300 if ($post_mode == 'reply')
2302 set_config('num_posts', $config['num_posts'] + 1, true);
2306 // Update forum stats
2307 $where_sql = array(POSTS_TABLE => 'post_id = ' . $data['post_id'], TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], USERS_TABLE => 'user_id = ' . $user->data['user_id']);
2309 foreach ($sql_data as $table => $update_ary)
2311 if (isset($update_ary['stat']) && implode('', $update_ary['stat']))
2313 $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table];
2314 $db->sql_query($sql);
2318 // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement
2319 if ($make_global)
2321 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
2322 WHERE topic_moved_id = ' . $data['topic_id'];
2323 $db->sql_query($sql);
2326 // Committing the transaction before updating search index
2327 $db->sql_transaction('commit');
2329 // Delete draft if post was loaded...
2330 $draft_id = request_var('draft_loaded', 0);
2331 if ($draft_id)
2333 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
2334 WHERE draft_id = $draft_id
2335 AND user_id = {$user->data['user_id']}";
2336 $db->sql_query($sql);
2339 // Index message contents
2340 if ($update_message && $data['enable_indexing'])
2342 // Select the search method and do some additional checks to ensure it can actually be utilised
2343 $search_type = basename($config['search_type']);
2345 if (!file_exists(PHPBB_ROOT_PATH . 'includes/search/' . $search_type . '.' . PHP_EXT))
2347 trigger_error('NO_SUCH_SEARCH_MODULE');
2350 if (!class_exists($search_type))
2352 include(PHPBB_ROOT_PATH . "includes/search/$search_type." . PHP_EXT);
2355 $error = false;
2356 $search = new $search_type($error);
2358 if ($error)
2360 trigger_error($error);
2363 $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']);
2366 // Topic Notification, do not change if moderator is changing other users posts...
2367 if ($user->data['user_id'] == $poster_id)
2369 if (!$data['notify_set'] && $data['notify'])
2371 $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id)
2372 VALUES (' . $user->data['user_id'] . ', ' . $data['topic_id'] . ')';
2373 $db->sql_query($sql);
2375 else if ($data['notify_set'] && !$data['notify'])
2377 $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
2378 WHERE user_id = ' . $user->data['user_id'] . '
2379 AND topic_id = ' . $data['topic_id'];
2380 $db->sql_query($sql);
2384 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote')
2386 // Mark this topic as posted to
2387 markread('post', $data['forum_id'], $data['topic_id'], $data['post_time']);
2390 // Mark this topic as read
2391 // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message)
2392 markread('topic', $data['forum_id'], $data['topic_id'], time());
2395 if ($config['load_db_lastread'] && $user->data['is_registered'])
2397 $sql = 'SELECT mark_time
2398 FROM ' . FORUMS_TRACK_TABLE . '
2399 WHERE user_id = ' . $user->data['user_id'] . '
2400 AND forum_id = ' . $data['forum_id'];
2401 $result = $db->sql_query($sql);
2402 $f_mark_time = (int) $db->sql_fetchfield('mark_time');
2403 $db->sql_freeresult($result);
2405 else if ($config['load_anon_lastread'] || $user->data['is_registered'])
2407 $f_mark_time = false;
2410 if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
2412 // Update forum info
2413 $sql = 'SELECT forum_last_post_time
2414 FROM ' . FORUMS_TABLE . '
2415 WHERE forum_id = ' . $data['forum_id'];
2416 $result = $db->sql_query($sql);
2417 $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
2418 $db->sql_freeresult($result);
2420 update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false);
2423 // Send Notifications
2424 if ($mode != 'edit' && $mode != 'delete' && ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])))
2426 user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']);
2429 $params = $add_anchor = '';
2431 if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id']))
2433 $params .= '&amp;t=' . $data['topic_id'];
2435 if ($mode != 'post')
2437 $params .= '&amp;p=' . $data['post_id'];
2438 $add_anchor = '#p' . $data['post_id'];
2441 else if ($mode != 'post' && $post_mode != 'edit_first_post' && $post_mode != 'edit_topic')
2443 $params .= '&amp;t=' . $data['topic_id'];
2446 $url = (!$params) ? 'viewforum' : 'viewtopic';
2447 $url = append_sid($url, 'f=' . $data['forum_id'] . $params) . $add_anchor;
2449 return $url;