Special Ops 2.50
[specialops2.git] / post.php
blob55763bff185f15847c6a580cb30db3b6339a4638
1 <?php
2 /**
3 * Message/Topic posting page
5 * @author Ant P <p@cpi.merseine.nu>
6 * @license file://COPYING
7 * @version 2.15
8 */
10 require 'con.php';
12 SO2::$Page->title = 'Post Message';
15 // Various post limits
16 define('MSG_MIN_LENGTH', 2);
17 define('MSG_MAX_LENGTH', 262144);
18 define('TOPIC_MIN_LENGTH', 2);
19 define('TOPIC_MAX_LENGTH',
20 SO2::$DB->query('SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS '.
21 'WHERE TABLE_SCHEMA = "'.SO2::$Cfg['db']['name'].'" AND TABLE_NAME = "topics" '.
22 'AND COLUMN_NAME = "topic_title"')->fetchColumn(0) );
25 // If messageid specified, validate it then set topic+boardid from that
26 if ( isset($_GET['message']) ) {
27 $messageid = intval($_GET['message']);
28 $topicid = SO2::$DB->q('SELECT @topicid := topicid FROM messages WHERE messageid = ?', $messageid, SO2_PDO::QVALUE);
30 if ( ! $topicid ) {
31 SO2::$Page->message(Page::ERR_NOMSG);
34 $topic = SO2::$DB->query('SELECT topic_title, boardid FROM topics WHERE topicid = @topicid')->fetch(PDO::FETCH_NUM);
36 if ( ! is_array($topic) ) {
37 SO2::$Page->message(Page::ERR_NOTOPIC);
40 $boardid = $topic[1];
41 } else {
42 $boardid = intval($_GET['board']);
46 // Get board metadata
47 $board = SO2::$DB->q('SELECT board_name, view_lvl, topic_lvl, post_lvl, points, @boardid := boardid AS boardid '.
48 'FROM boards WHERE boardid = ?', $boardid);
50 if ( ! $board ) { // Check whether board exists
51 SO2::$Page->message(Page::ERR_NOBOARD);
54 if ( ! SO2::$User->has_access('viewboard', $board) ) { // Check whether user can view board
55 SO2::$Page->message(Page::ERR_ULEVEL);
58 SO2::$Page->nav['Topic List: '.$board['board_name']] = 'topiclist?'.$boardid; // Add link to board if they can view it
59 if ( isset($topicid) ) { // Add link to topic if replying to one
60 SO2::$Page->nav['Message List: '.$topic[0]] = 'messagelist?'.$topicid;
63 // Access control
64 if ( isset($_GET['board']) && ! SO2::$User->has_access('posttopic', $board) ) { // Check if posting topic
65 SO2::$Page->message(Page::ERR_ULEVEL);
66 } elseif ( ! SO2::$User->has_access('postmessage', $board) ) { // Check if replying to topic
67 SO2::$Page->message(Page::ERR_ULEVEL);
71 /**
72 * Selectbox for HTML formatting
74 $html_options = new HTML_Select('html', 3);
75 if ( SO2::$User->has_access('allhtml') ) {
76 $html_options->add_item('Post_XML', 'Full XHTML');
78 if ( 0 < SO2::$User->points ) {
79 $html_options->add_item('Post_Default', 'Default');
81 $html_options->add_item('Post_Plaintext', 'Plaintext');
83 // Used for message preview
84 $mo = new Messagestyle_Default;
86 $score = ceil(SO2::$User->points/300); // Default score is points/300 rounded up: 1 point for 1-299, 2 for 300-599 etc.
87 if ( SO2::$User->posts == 0 ) // New users get one point
88 $score = 1;
89 if ( SO2::$User->points < 0 ) // Negative score users get penalised propotional to the magnitude of their points
90 $score = -(strlen(SO2::$User->points)-1);
92 $tmp = SO2::$DB->query('SELECT COUNT(*) FROM messages WHERE userid = @userid AND mtime > UNIX_TIMESTAMP()-60')->fetchColumn(0);
93 if ( $tmp == 4 ) { // 4 posts in 1 minute is more than you could possibly have a legit use for - flood
94 if ( SO2::$User->points > 0 ) // If their points are above 0, halve them
95 SO2::$User->points >>= 1;
96 $score = -10; // Take 10 off
97 } elseif ( $tmp > 4 ) { // User really is flooding - fuck them over
98 $_POST['logout'] = 'Log Out';
99 setcookie('u', '-', time());
100 setcookie('p', '-', time());
101 SO2::$Page->message(Page::ERR_LOGIN);
104 // Needed to make permalinks in message previews not cause an error
105 define('HERE', $_SERVER['REQUEST_URI']);
107 // Form submit handling
108 if ( isset($_POST['post']) || isset($_POST['preview']) ) {
110 if ( isset($_POST['html']) ) {
111 $html_options->check_value($_POST['html']);
112 $html_options->set_default($_POST['html']);
113 } else {
114 $html_options->set_default('Post_'.SO2::$User->post_html);
117 try {
118 // Checks done on message
119 $message = new $html_options->default(trim($_POST['message_text']));
120 $message->validate(); // Throws InvalidMessageException
122 if ( strlen($message->getOutput()) < MSG_MIN_LENGTH ) {
123 throw new LengthException('Your message is %d character(s) too short.',
124 MSG_MIN_LENGTH - strlen($message->getOutput()) );
127 // Checks done on topic title if posting a topic
128 if ( ! isset($topic) ) {
129 $topic_title = trim( SO2::$User->admin ? $_POST['topic_title'] : htmlspecialchars($_POST['topic_title']) );
130 $t = strlen($topic_title);
131 if ( $t < TOPIC_MIN_LENGTH ) {
132 throw new LengthException('Your topic title is %d character(s) too short.', TOPIC_MIN_LENGTH - $t);
134 if ( $t > TOPIC_MAX_LENGTH ) {
135 throw new LengthException('Your topic title is %d character(s) too long.', $t - TOPIC_MAX_LENGTH);
137 if ( preg_match('/\S{30,}/', $topic_title) ) {
138 throw new LengthException('harbl');
140 if ( SO2::$DB->q('SELECT COUNT(*) FROM topics WHERE topic_title = ? AND boardid = @boardid',
141 $topic_title, SO2_PDO::QVALUE) ) {
142 throw new RateLimitException('A topic with that name already exists.');
146 if ( isset($_POST['post']) ) {
147 if ( ! (SO2::$User instanceof User_Authenticated) ) {
148 throw new Exception('Login warning in plain sight ignored. You are officially retarded.');
151 SO2::$DB->beginTransaction();
153 // Insert topic data if posting a topic
154 if ( ! isset($topic) ) {
155 SO2::$DB->q('INSERT INTO topics (topic_title, boardid, userid) VALUES (?, @boardid, @userid)', $topic_title);
156 $topicid = SO2::$DB->q('SELECT @topicid := ?', SO2::$DB->lastInsertId(), SO2_PDO::QVALUE);
157 mkdir('data/messages/'.$topicid);
159 SO2::$User->points += ($score+1);
160 $messageid = null;
161 } else {
162 assert($messageid);
163 SO2::$User->points += $score;
166 // Message metadata
167 SO2::$DB->q('INSERT INTO messages (topicid, replyto, userid, mtime, origin_ip, score) '.
168 'VALUES (?, ?, @userid, UNIX_TIMESTAMP(), INET_ATON(?), ? )',
169 array($topicid, $messageid, $_SERVER['REMOTE_ADDR'], $score) );
170 $replyid = SO2::$DB->lastInsertId();
172 // The message text
173 file_put_contents("data/messages/$topicid/$replyid", $message->getOutput());
175 SO2::$DB->commit();
177 if ( isset($topicid) ) {
178 $r = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['REQUEST_URI']).'/messagelist?'.$topicid.'#m'.$replyid;
179 } else {
180 $r = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['REQUEST_URI']).'/topiclist?'.$boardid;
183 header('HTTP/1.1 303 See Other');
184 header('Location: '.$r);
185 SO2::$Page->message('Message posted. You should be redirected, if not <a href="'.$r.'">click here.</a>.',
186 E_USER_NOTICE);
187 exit;
189 } elseif ( isset($_POST['preview']) ) {
190 SO2::$Page->pageheader();
191 echo '<fieldset class="',get_class($mo),'"><legend>Message Preview</legend>',"\n",
192 ( isset($topic_title) ? '<h2>'.$topic_title."</h2>\n" : '' );
193 $mo->display(array(
194 'userid' => SO2::$User->userid,
195 'mtime' => T_NOW,
196 'mtext' => $message->getOutput(),
197 'replyto' => null,
198 'score' => $score,
199 'marks' => 0,
200 'messageid' => null,
201 'ip' => $_SERVER['REMOTE_ADDR']
203 echo "</fieldset>\n";
205 } catch ( LengthException $e ) {
206 SO2::$Page->message(sprintf($e->getMessage(), $e->getCode()), E_USER_WARNING);
207 } catch ( RateLimitException $e ) {
208 SO2::$Page->message(sprintf($e->getMessage(), $e->getCode()), E_USER_WARNING);
209 } catch ( InvalidInputException $e ) {
210 SO2::$Page->message('Your message contains formatting errors (only the first error is shown): '.
211 $e->getMessage().' at line '.$e->getCode(), E_USER_WARNING);
213 } else {
214 SO2::$Page->pageheader();
217 // I have no idea what's going on here
218 $message = strpos($_SERVER['HTTP_USER_AGENT'], 'KHTML') ? "\n" : '';
219 if ( ! empty($_POST['message_text']) ) {
220 $message = htmlspecialchars($_POST['message_text']);
221 } elseif ( SO2::$User->sig ) {
222 $message .= "\n".htmlspecialchars(SO2::$User->sig);
225 if ( isset($messageid) ) {
226 echo '<fieldset class="',get_class($mo),'"><legend>Replying to:</legend>',"\n";
227 $mo->display(SO2::$DB->q('SELECT userid, mtime, topicid, replyto, score, marks, messageid, INET_NTOA(origin_ip) AS ip '.
228 'FROM messages WHERE messageid = ?', $messageid));
229 echo "</fieldset>\n",
230 '<form action="post?message=',$messageid,'" method="post">';
231 } else {
232 echo '<form action="post?board=',$boardid,'" method="post">',"\n",
233 ' <fieldset><legend>Topic <small>(Max. ',TOPIC_MAX_LENGTH," chars)</small></legend>\n",
234 ' <input type="text" name="topic_title" maxlength="',TOPIC_MAX_LENGTH,'" size="80"',
235 ( !empty($topic_title) ? ' value="'.htmlspecialchars($_POST['topic_title']).'"' : '' ),' tabindex="1"/>',"\n",
236 " </fieldset>\n";
239 <fieldset><legend>Message <small>(Max. size <?php echo (int)MSG_MAX_LENGTH/1024 ?>kiB)</small></legend>
240 <textarea rows="15" cols="60" name="message_text" id="messagebox" tabindex="1"><?php echo $message ?></textarea>
241 <fieldset class="content">
242 <?php if ( ! (SO2::$User instanceof User_Authenticated) ) {
243 SO2::$Page->message(Page::ERR_LOGIN, E_USER_WARNING); ?>
244 <p><label>Username: <input name="u" tabindex="1" type="text"/></label></p>
245 <p><label>Password: <input name="p" tabindex="1" type="password"/></label></p>
246 <input type="hidden" name="login" value="post"/>
247 <?php } ?>
248 <button type="submit" accesskey="p" tabindex="1" name="post">Post (P)</button>
249 <button type="submit" accesskey="r" tabindex="1" name="preview">Preview (R)</button>
250 <p><label>HTML Formatting: <?php echo $html_options ?></label></p>
251 <p>Allowed HTML in default mode: <?php echo implode(', ', Post_Default::$allowed_html) ?></p>
252 </fieldset>
253 </fieldset>
254 </form>