albertlast /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 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 http://www.simplemachines.org |
||
| 11 | * @copyright 2017 Simple Machines and individual contributors |
||
| 12 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 13 | * |
||
| 14 | * @version 2.1 Beta 4 |
||
| 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 | View Code Duplication | while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
|
0 ignored issues
–
show
|
|||
| 118 | { |
||
| 119 | censorText($row['label']); |
||
| 120 | $pollOptions[$row['id_choice']] = $row; |
||
| 121 | $realtotal += $row['votes']; |
||
| 122 | $pollinfo['has_voted'] |= $row['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 | View Code Duplication | if ($user_info['is_guest'] && $pollinfo['guest_vote'] && allowedTo('poll_vote')) |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 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 |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. Loading history...
|
|||
| 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]) |
||
| 142 | { |
||
| 143 | // Remove the poll info from the cookie to allow guest to vote again |
||
| 144 | unset($guestinfo[$i]); |
||
| 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; |
||
|
0 ignored issues
–
show
The variable
$guestvoted does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 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_options6'], 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; |
||
| 202 | |||
| 203 | // Determine if a decimal point is needed in order for the options to add to 100%. |
||
| 204 | $precision = $realtotal == 100 ? 0 : 1; |
||
| 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 . '" class="input_' . ($pollinfo['max_votes'] > 1 ? 'check' : 'radio') . '">' |
||
| 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' => forum_time(true, $row['poster_time']), |
||
| 265 | 'body' => parse_bbc($row['body'], 'print'), |
||
|
0 ignored issues
–
show
'print' is of type string, but the function expects a boolean.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 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($row['width']) && !empty($row['height'])) |
||
| 308 | { |
||
| 309 | if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $row['height'] * ($modSettings['max_image_width'] / $row['width']) <= $modSettings['max_image_height'])) |
||
| 310 | { |
||
| 311 | View Code Duplication | if ($row['width'] > $modSettings['max_image_width']) |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 312 | { |
||
| 313 | $row['height'] = floor($row['height'] * ($modSettings['max_image_width'] / $row['width'])); |
||
| 314 | $row['width'] = $modSettings['max_image_width']; |
||
| 315 | } |
||
| 316 | } |
||
| 317 | View Code Duplication | elseif (!empty($modSettings['max_image_width'])) |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 318 | { |
||
| 319 | if ($row['height'] > $modSettings['max_image_height']) |
||
| 320 | { |
||
| 321 | $row['width'] = floor($row['width'] * $modSettings['max_image_height'] / $row['height']); |
||
| 322 | $row['height'] = $modSettings['max_image_height']; |
||
| 323 | } |
||
| 324 | } |
||
| 325 | |||
| 326 | $row['filename'] = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); |
||
| 327 | |||
| 328 | // save for the template |
||
| 329 | $context['printattach'][$row['id_msg']][] = $row; |
||
| 330 | } |
||
| 331 | } |
||
| 332 | } |
||
| 333 | |||
| 334 | // Set a canonical URL for this page. |
||
| 335 | $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.0'; |
||
| 336 | } |
||
| 337 | |||
| 338 | ?> |
||
|
0 ignored issues
–
show
It is not recommended to use PHP's closing tag
?> in files other than templates.
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore. A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever. Loading history...
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.