1 | <?php |
||
2 | |||
3 | /** |
||
4 | * This file contains just one function that formats a topic to be printer |
||
5 | * friendly. |
||
6 | * |
||
7 | * Simple Machines Forum (SMF) |
||
8 | * |
||
9 | * @package SMF |
||
10 | * @author Simple Machines https://www.simplemachines.org |
||
11 | * @copyright 2022 Simple Machines and individual contributors |
||
12 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
13 | * |
||
14 | * @version 2.1.0 |
||
15 | */ |
||
16 | |||
17 | if (!defined('SMF')) |
||
18 | die('No direct access...'); |
||
19 | |||
20 | /** |
||
21 | * Format a topic to be printer friendly. |
||
22 | * Must be called with a topic specified. |
||
23 | * Accessed via ?action=printpage. |
||
24 | * |
||
25 | * Uses Printpage template, main sub-template. |
||
26 | * Uses print_above/print_below later without the main layer. |
||
27 | */ |
||
28 | |||
29 | function PrintTopic() |
||
30 | { |
||
31 | global $topic, $txt, $scripturl, $context, $user_info; |
||
32 | global $board_info, $smcFunc, $modSettings; |
||
33 | |||
34 | // Redirect to the boardindex if no valid topic id is provided. |
||
35 | if (empty($topic)) |
||
36 | redirectexit(); |
||
37 | |||
38 | if (!empty($modSettings['disable_print_topic'])) |
||
39 | { |
||
40 | unset($_REQUEST['action']); |
||
41 | $context['theme_loaded'] = false; |
||
42 | fatal_lang_error('feature_disabled', false); |
||
43 | } |
||
44 | |||
45 | // Whatever happens don't index this. |
||
46 | $context['robot_no_index'] = true; |
||
47 | |||
48 | // Get the topic starter information. |
||
49 | $request = $smcFunc['db_query']('', ' |
||
50 | SELECT mem.id_member, m.poster_time, COALESCE(mem.real_name, m.poster_name) AS poster_name, t.id_poll |
||
51 | FROM {db_prefix}messages AS m |
||
52 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||
53 | LEFT JOIN {db_prefix}topics as t ON (t.id_first_msg = m.id_msg) |
||
54 | WHERE m.id_topic = {int:current_topic} |
||
55 | ORDER BY m.id_msg |
||
56 | LIMIT 1', |
||
57 | array( |
||
58 | 'current_topic' => $topic, |
||
59 | ) |
||
60 | ); |
||
61 | // Redirect to the boardindex if no valid topic id is provided. |
||
62 | if ($smcFunc['db_num_rows']($request) == 0) |
||
63 | redirectexit(); |
||
64 | $row = $smcFunc['db_fetch_assoc']($request); |
||
65 | $smcFunc['db_free_result']($request); |
||
66 | |||
67 | if (!empty($row['id_poll'])) |
||
68 | { |
||
69 | loadLanguage('Post'); |
||
70 | // Get the question and if it's locked. |
||
71 | $request = $smcFunc['db_query']('', ' |
||
72 | SELECT |
||
73 | p.question, p.voting_locked, p.hide_results, p.expire_time, p.max_votes, p.change_vote, |
||
74 | p.guest_vote, p.id_member, COALESCE(mem.real_name, p.poster_name) AS poster_name, p.num_guest_voters, p.reset_poll |
||
75 | FROM {db_prefix}polls AS p |
||
76 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = p.id_member) |
||
77 | WHERE p.id_poll = {int:id_poll} |
||
78 | LIMIT 1', |
||
79 | array( |
||
80 | 'id_poll' => $row['id_poll'], |
||
81 | ) |
||
82 | ); |
||
83 | $pollinfo = $smcFunc['db_fetch_assoc']($request); |
||
84 | $smcFunc['db_free_result']($request); |
||
85 | |||
86 | $request = $smcFunc['db_query']('', ' |
||
87 | SELECT COUNT(DISTINCT id_member) AS total |
||
88 | FROM {db_prefix}log_polls |
||
89 | WHERE id_poll = {int:id_poll} |
||
90 | AND id_member != {int:not_guest}', |
||
91 | array( |
||
92 | 'id_poll' => $row['id_poll'], |
||
93 | 'not_guest' => 0, |
||
94 | ) |
||
95 | ); |
||
96 | list ($pollinfo['total']) = $smcFunc['db_fetch_row']($request); |
||
97 | $smcFunc['db_free_result']($request); |
||
98 | |||
99 | // Total voters needs to include guest voters |
||
100 | $pollinfo['total'] += $pollinfo['num_guest_voters']; |
||
101 | |||
102 | // Get all the options, and calculate the total votes. |
||
103 | $request = $smcFunc['db_query']('', ' |
||
104 | SELECT pc.id_choice, pc.label, pc.votes, COALESCE(lp.id_choice, -1) AS voted_this |
||
105 | FROM {db_prefix}poll_choices AS pc |
||
106 | LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_choice = pc.id_choice AND lp.id_poll = {int:id_poll} AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest}) |
||
107 | WHERE pc.id_poll = {int:id_poll}', |
||
108 | array( |
||
109 | 'current_member' => $user_info['id'], |
||
110 | 'id_poll' => $row['id_poll'], |
||
111 | 'not_guest' => 0, |
||
112 | ) |
||
113 | ); |
||
114 | $pollOptions = array(); |
||
115 | $realtotal = 0; |
||
116 | $pollinfo['has_voted'] = false; |
||
117 | while ($voterow = $smcFunc['db_fetch_assoc']($request)) |
||
118 | { |
||
119 | censorText($voterow['label']); |
||
120 | $pollOptions[$voterow['id_choice']] = $voterow; |
||
121 | $realtotal += $voterow['votes']; |
||
122 | $pollinfo['has_voted'] |= $voterow['voted_this'] != -1; |
||
123 | } |
||
124 | $smcFunc['db_free_result']($request); |
||
125 | |||
126 | // If this is a guest we need to do our best to work out if they have voted, and what they voted for. |
||
127 | if ($user_info['is_guest'] && $pollinfo['guest_vote'] && allowedTo('poll_vote')) |
||
128 | { |
||
129 | if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $row['id_poll'] . ',') !== false) |
||
130 | { |
||
131 | // ;id,timestamp,[vote,vote...]; etc |
||
132 | $guestinfo = explode(';', $_COOKIE['guest_poll_vote']); |
||
133 | // Find the poll we're after. |
||
134 | foreach ($guestinfo as $i => $guestvoted) |
||
135 | { |
||
136 | $guestvoted = explode(',', $guestvoted); |
||
137 | if ($guestvoted[0] == $row['id_poll']) |
||
138 | break; |
||
139 | } |
||
140 | // Has the poll been reset since guest voted? |
||
141 | if ($pollinfo['reset_poll'] > $guestvoted[1]) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||
142 | { |
||
143 | // Remove the poll info from the cookie to allow guest to vote again |
||
144 | unset($guestinfo[$i]); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
145 | if (!empty($guestinfo)) |
||
146 | $_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo); |
||
147 | else |
||
148 | unset($_COOKIE['guest_poll_vote']); |
||
149 | } |
||
150 | else |
||
151 | { |
||
152 | // What did they vote for? |
||
153 | unset($guestvoted[0], $guestvoted[1]); |
||
154 | foreach ($pollOptions as $choice => $details) |
||
155 | { |
||
156 | $pollOptions[$choice]['voted_this'] = in_array($choice, $guestvoted) ? 1 : -1; |
||
157 | $pollinfo['has_voted'] |= $pollOptions[$choice]['voted_this'] != -1; |
||
158 | } |
||
159 | unset($choice, $details, $guestvoted); |
||
160 | } |
||
161 | unset($guestinfo, $guestvoted, $i); |
||
162 | } |
||
163 | } |
||
164 | |||
165 | $context['user']['started'] = $user_info['id'] == $row['id_member'] && !$user_info['is_guest']; |
||
166 | // Set up the basic poll information. |
||
167 | $context['poll'] = array( |
||
168 | 'id' => $row['id_poll'], |
||
169 | 'image' => 'normal_' . (empty($pollinfo['voting_locked']) ? 'poll' : 'locked_poll'), |
||
170 | 'question' => parse_bbc($pollinfo['question']), |
||
171 | 'total_votes' => $pollinfo['total'], |
||
172 | 'change_vote' => !empty($pollinfo['change_vote']), |
||
173 | 'is_locked' => !empty($pollinfo['voting_locked']), |
||
174 | 'options' => array(), |
||
175 | 'lock' => allowedTo('poll_lock_any') || ($context['user']['started'] && allowedTo('poll_lock_own')), |
||
176 | 'edit' => allowedTo('poll_edit_any') || ($context['user']['started'] && allowedTo('poll_edit_own')), |
||
177 | 'allowed_warning' => $pollinfo['max_votes'] > 1 ? sprintf($txt['poll_options_limit'], min(count($pollOptions), $pollinfo['max_votes'])) : '', |
||
178 | 'is_expired' => !empty($pollinfo['expire_time']) && $pollinfo['expire_time'] < time(), |
||
179 | 'expire_time' => !empty($pollinfo['expire_time']) ? timeformat($pollinfo['expire_time']) : 0, |
||
180 | 'has_voted' => !empty($pollinfo['has_voted']), |
||
181 | 'starter' => array( |
||
182 | 'id' => $pollinfo['id_member'], |
||
183 | 'name' => $row['poster_name'], |
||
184 | 'href' => $pollinfo['id_member'] == 0 ? '' : $scripturl . '?action=profile;u=' . $pollinfo['id_member'], |
||
185 | 'link' => $pollinfo['id_member'] == 0 ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $pollinfo['id_member'] . '">' . $row['poster_name'] . '</a>' |
||
186 | ) |
||
187 | ); |
||
188 | |||
189 | // Make the lock and edit permissions defined above more directly accessible. |
||
190 | $context['allow_lock_poll'] = $context['poll']['lock']; |
||
191 | $context['allow_edit_poll'] = $context['poll']['edit']; |
||
192 | |||
193 | // You're allowed to view the results if: |
||
194 | // 1. you're just a super-nice-guy, or |
||
195 | // 2. anyone can see them (hide_results == 0), or |
||
196 | // 3. you can see them after you voted (hide_results == 1), or |
||
197 | // 4. you've waited long enough for the poll to expire. (whether hide_results is 1 or 2.) |
||
198 | $context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hide_results'] == 0 || ($pollinfo['hide_results'] == 1 && $context['poll']['has_voted']) || $context['poll']['is_expired']; |
||
199 | |||
200 | // Calculate the percentages and bar lengths... |
||
201 | $divisor = $realtotal == 0 ? 1 : $realtotal; |
||
0 ignored issues
–
show
|
|||
202 | |||
203 | // Determine if a decimal point is needed in order for the options to add to 100%. |
||
204 | $precision = $realtotal == 100 ? 0 : 1; |
||
0 ignored issues
–
show
|
|||
205 | |||
206 | // Now look through each option, and... |
||
207 | foreach ($pollOptions as $i => $option) |
||
208 | { |
||
209 | // First calculate the percentage, and then the width of the bar... |
||
210 | $bar = round(($option['votes'] * 100) / $divisor, $precision); |
||
211 | $barWide = $bar == 0 ? 1 : floor(($bar * 8) / 3); |
||
212 | |||
213 | // Now add it to the poll's contextual theme data. |
||
214 | $context['poll']['options'][$i] = array( |
||
215 | 'id' => 'options-' . $i, |
||
216 | 'percent' => $bar, |
||
217 | 'votes' => $option['votes'], |
||
218 | 'voted_this' => $option['voted_this'] != -1, |
||
219 | // Note: IE < 8 requires us to set a width on the container, too. |
||
220 | 'bar_ndt' => $bar > 0 ? '<div class="bar" style="width: ' . ($bar * 3.5 + 4) . 'px;"><div style="width: ' . $bar * 3.5 . 'px;"></div></div>' : '', |
||
221 | 'bar_width' => $barWide, |
||
222 | 'option' => parse_bbc($option['label']), |
||
223 | 'vote_button' => '<input type="' . ($pollinfo['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '">' |
||
224 | ); |
||
225 | } |
||
226 | } |
||
227 | |||
228 | // Lets "output" all that info. |
||
229 | loadTemplate('Printpage'); |
||
230 | $context['template_layers'] = array('print'); |
||
231 | $context['board_name'] = $board_info['name']; |
||
232 | $context['category_name'] = $board_info['cat']['name']; |
||
233 | $context['poster_name'] = $row['poster_name']; |
||
234 | $context['post_time'] = timeformat($row['poster_time'], false); |
||
235 | $context['parent_boards'] = array(); |
||
236 | foreach ($board_info['parent_boards'] as $parent) |
||
237 | $context['parent_boards'][] = $parent['name']; |
||
238 | |||
239 | // Split the topics up so we can print them. |
||
240 | $request = $smcFunc['db_query']('', ' |
||
241 | SELECT subject, poster_time, body, COALESCE(mem.real_name, poster_name) AS poster_name, id_msg |
||
242 | FROM {db_prefix}messages AS m |
||
243 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||
244 | WHERE m.id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && !allowedTo('approve_posts') ? ' |
||
245 | AND (m.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR m.id_member = {int:current_member}') . ')' : '') . ' |
||
246 | ORDER BY m.id_msg', |
||
247 | array( |
||
248 | 'current_topic' => $topic, |
||
249 | 'is_approved' => 1, |
||
250 | 'current_member' => $user_info['id'], |
||
251 | ) |
||
252 | ); |
||
253 | $context['posts'] = array(); |
||
254 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
255 | { |
||
256 | // Censor the subject and message. |
||
257 | censorText($row['subject']); |
||
258 | censorText($row['body']); |
||
259 | |||
260 | $context['posts'][] = array( |
||
261 | 'subject' => $row['subject'], |
||
262 | 'member' => $row['poster_name'], |
||
263 | 'time' => timeformat($row['poster_time'], false), |
||
264 | 'timestamp' => $row['poster_time'], |
||
265 | 'body' => parse_bbc($row['body'], 'print'), |
||
266 | 'id_msg' => $row['id_msg'], |
||
267 | ); |
||
268 | |||
269 | if (!isset($context['topic_subject'])) |
||
270 | $context['topic_subject'] = $row['subject']; |
||
271 | } |
||
272 | $smcFunc['db_free_result']($request); |
||
273 | |||
274 | // Fetch attachments so we can print them if asked, enabled and allowed |
||
275 | if (isset($_REQUEST['images']) && !empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) |
||
276 | { |
||
277 | $messages = array(); |
||
278 | foreach ($context['posts'] as $temp) |
||
279 | $messages[] = $temp['id_msg']; |
||
280 | |||
281 | // build the request |
||
282 | $request = $smcFunc['db_query']('', ' |
||
283 | SELECT |
||
284 | a.id_attach, a.id_msg, a.approved, a.width, a.height, a.file_hash, a.filename, a.id_folder, a.mime_type |
||
285 | FROM {db_prefix}attachments AS a |
||
286 | WHERE a.id_msg IN ({array_int:message_list}) |
||
287 | AND a.attachment_type = {int:attachment_type}', |
||
288 | array( |
||
289 | 'message_list' => $messages, |
||
290 | 'attachment_type' => 0, |
||
291 | 'is_approved' => 1, |
||
292 | ) |
||
293 | ); |
||
294 | $temp = array(); |
||
295 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
296 | { |
||
297 | $temp[$row['id_attach']] = $row; |
||
298 | if (!isset($context['printattach'][$row['id_msg']])) |
||
299 | $context['printattach'][$row['id_msg']] = array(); |
||
300 | } |
||
301 | $smcFunc['db_free_result']($request); |
||
302 | ksort($temp); |
||
303 | |||
304 | // load them into $context so the template can use them |
||
305 | foreach ($temp as $row) |
||
306 | { |
||
307 | if (!empty($modSettings['dont_show_attach_under_post']) && !empty($context['show_attach_under_post'][$row['id_attach']])) |
||
308 | continue; |
||
309 | |||
310 | if (!empty($row['width']) && !empty($row['height'])) |
||
311 | { |
||
312 | if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $row['height'] * ($modSettings['max_image_width'] / $row['width']) <= $modSettings['max_image_height'])) |
||
313 | { |
||
314 | if ($row['width'] > $modSettings['max_image_width']) |
||
315 | { |
||
316 | $row['height'] = floor($row['height'] * ($modSettings['max_image_width'] / $row['width'])); |
||
317 | $row['width'] = $modSettings['max_image_width']; |
||
318 | } |
||
319 | } |
||
320 | elseif (!empty($modSettings['max_image_width'])) |
||
321 | { |
||
322 | if ($row['height'] > $modSettings['max_image_height']) |
||
323 | { |
||
324 | $row['width'] = floor($row['width'] * $modSettings['max_image_height'] / $row['height']); |
||
325 | $row['height'] = $modSettings['max_image_height']; |
||
326 | } |
||
327 | } |
||
328 | |||
329 | $row['filename'] = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); |
||
330 | |||
331 | // save for the template |
||
332 | $context['printattach'][$row['id_msg']][] = $row; |
||
333 | } |
||
334 | } |
||
335 | } |
||
336 | |||
337 | // Set a canonical URL for this page. |
||
338 | $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.0'; |
||
339 | } |
||
340 | |||
341 | ?> |