Issues (4)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

services/poll.php (2 issues)

Labels
Severity
1
<?php
2
3
/**
4
 *
5
 * @package sitemaker
6
 * @copyright (c) 2013 Daniel A. (blitze)
7
 * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
8
 *
9
 */
10
11
namespace blitze\sitemaker\services;
12
13
class poll
14
{
15
	/** @var \phpbb\auth\auth */
16
	protected $auth;
17
18
	/** @var \phpbb\config\config */
19
	protected $config;
20
21
	/** @var \phpbb\db\driver\driver_interface */
22
	protected $db;
23
24
	/** @var \phpbb\request\request_interface */
25
	protected $request;
26
27
	/** @var \phpbb\language\language */
28
	protected $translator;
29
30
	/** @var \phpbb\user */
31
	protected $user;
32
33
	/** @var \blitze\sitemaker\services\util */
34
	protected $sitemaker;
35
36
	/** @var string */
37
	protected $phpbb_root_path;
38
39
	/** @var string */
40
	protected $php_ext;
41
42
	/**
43
	 * Constructor
44
	 *
45
	 * @param \phpbb\auth\auth						$auth				Permission object
46
	 * @param \phpbb\config\config					$config				Config object
47
	 * @param \phpbb\db\driver\driver_interface		$db	 				Database connection
48
	 * @param \phpbb\request\request_interface		$request			Request object
49
	 * @param \phpbb\language\language				$translator			Language object
50
	 * @param \phpbb\user							$user				User object
51
	 * @param \blitze\sitemaker\services\util		$sitemaker			Sitemaker Object
52
	 * @param string								$phpbb_root_path	Path to the phpbb includes directory.
53
	 * @param string								$php_ext			php file extension
54 4
	 */
55
	public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\request\request_interface $request, \phpbb\language\language $translator, \phpbb\user $user, \blitze\sitemaker\services\util $sitemaker, $phpbb_root_path, $php_ext)
56 4
	{
57 4
		$this->auth = $auth;
58 4
		$this->config = $config;
59 4
		$this->db = $db;
60 4
		$this->request = $request;
61 4
		$this->translator = $translator;
62 4
		$this->user = $user;
63 4
		$this->sitemaker = $sitemaker;
64 4
		$this->phpbb_root_path = $phpbb_root_path;
65 4
		$this->php_ext = $php_ext;
66
	}
67
68
	/**
69
	 * @param array $topic_data
70
	 * @return array
71 2
	 */
72
	public function build(array $topic_data)
73 2
	{
74
		$this->translator->add_lang('viewtopic');
75 2
76 2
		$forum_id = (int) $topic_data['forum_id'];
77
		$topic_id = (int) $topic_data['topic_id'];
78 2
79 2
		$cur_voted_id = $this->get_users_votes($topic_id);
80 2
		$s_can_vote = $this->user_can_vote($forum_id, $topic_data, $cur_voted_id);
81
		$viewtopic_url = append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", "f=$forum_id&amp;t=$topic_id");
82 2
83 2
		$poll_total = $poll_most = 0;
84 2
		$poll_info = $this->get_poll_info($topic_data, $poll_total, $poll_most);
85
		$poll_end = $topic_data['poll_length'] + $topic_data['poll_start'];
86 2
87
		return array(
88 2
			'POLL_QUESTION'		=> $topic_data['poll_title'],
89 2
			'TOTAL_VOTES' 		=> $poll_total,
90 2
			'POLL_LEFT_CAP_IMG'	=> $this->user->img('poll_left'),
91 2
			'POLL_RIGHT_CAP_IMG' => $this->user->img('poll_right'),
92 2
93
			'MAX_VOTES'			=> $this->translator->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']),
94 2
			'POLL_LENGTH'		=> $this->get_poll_length_lang($topic_data['poll_length'], $poll_end),
95 2
			'POLL_OPTIONS'		=> $this->get_poll_options($cur_voted_id, $poll_info, $poll_total, $poll_most),
96
97 2
			'S_CAN_VOTE'		=> $s_can_vote,
98 2
			'S_DISPLAY_RESULTS'	=> $this->show_results($s_can_vote, $cur_voted_id),
99 2
			'S_IS_MULTI_CHOICE'	=> $this->poll_is_multiple_choice($topic_data['poll_max_options']),
100 2
			'S_POLL_ACTION'		=> $viewtopic_url,
101 2
			'S_FORM_TOKEN'		=> $this->sitemaker->get_form_key('posting'),
102
103 2
			'U_VIEW_RESULTS'	=> $viewtopic_url . '&amp;view=viewpoll',
104 2
		);
105 2
	}
106
107
	/**
108
	 * @param int $forum_id
109
	 * @param array $topic_data
110
	 * @param array $cur_voted_id
111
	 * @return bool
112
	 */
113 2
	private function user_can_vote($forum_id, array $topic_data, array $cur_voted_id)
114
	{
115
		return ($this->user_is_authorized($forum_id, $topic_data, $cur_voted_id) &&
116 2
			$this->poll_is_still_open($topic_data) &&
117 2
			$this->is_topic_status_eligible($topic_data));
118 1
	}
119 2
120
	/**
121
	 * @param int $forum_id
122
	 * @param array $topic_data
123
	 * @param array $cur_voted_id
124
	 * @return bool
125
	 */
126
	private function user_is_authorized($forum_id, array $topic_data, array $cur_voted_id)
127
	{
128 2
		return ($this->auth->acl_get('f_vote', $forum_id) && $this->user_can_change_vote($forum_id, $topic_data, $cur_voted_id));
129
	}
130 2
131
	/**
132
	 * @param int $forum_id
133
	 * @param array $topic_data
134
	 * @param array $cur_voted_id
135
	 * @return bool
136
	 */
137
	private function user_can_change_vote($forum_id, array $topic_data, array $cur_voted_id)
138
	{
139 2
		return (!sizeof($cur_voted_id) || ($this->auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']));
140
	}
141 2
142
	/**
143
	 * @param array $topic_data
144
	 * @return bool
145
	 */
146
	private function poll_is_still_open(array $topic_data)
147
	{
148 1
		return (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0);
149
	}
150 1
151
	/**
152
	 * @param array $topic_data
153
	 * @return bool
154
	 */
155
	private function is_topic_status_eligible(array $topic_data)
156
	{
157 1
		return ($topic_data['topic_status'] != ITEM_LOCKED && $topic_data['forum_status'] != ITEM_LOCKED);
158
	}
159 1
160
	/**
161
	 * @param array $topic_data
162
	 * @param int $poll_total
163
	 * @param int $poll_most
164
	 * @return array
165
	 */
166
	private function get_poll_info(array $topic_data, &$poll_total, &$poll_most)
167
	{
168 2
		$topic_id = (int) $topic_data['topic_id'];
169
		$post_id = (int) $topic_data['topic_first_post_id'];
170 2
171 2
		$sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid
172
			FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p
173
			WHERE o.topic_id = $topic_id
174 2
				AND p.post_id = $post_id
175
				AND p.topic_id = o.topic_id
176 2
			ORDER BY o.poll_option_id";
177
		$result = $this->db->sql_query($sql);
178 2
179 2
		$poll_info = array();
180
		while ($row = $this->db->sql_fetchrow($result))
181 2
		{
182 2
			$poll_info[] = $row;
183
			$poll_total += $row['poll_option_total'];
184 2
			$poll_most = ($row['poll_option_total'] >= $poll_most) ? $row['poll_option_total'] : $poll_most;
185 2
		}
186 2
		$this->db->sql_freeresult($result);
187 2
188 2
		return $this->parse_poll($topic_data, $poll_info);
189
	}
190 2
191
	/**
192
	 * @param array $topic_data
193
	 * @param array $poll_info
194
	 * @return array
195
	 */
196
	private function parse_poll(array &$topic_data, array $poll_info)
197
	{
198 2
		$parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
199
200 2
		for ($i = 0, $size = sizeof($poll_info); $i < $size; $i++)
201
		{
202 2
			$poll_info[$i]['poll_option_text'] = generate_text_for_display($poll_info[$i]['poll_option_text'], $poll_info[$i]['bbcode_uid'], $poll_info[$i]['bbcode_bitfield'], $parse_flags, true);
203
		}
204 2
205 2
		$topic_data['poll_title'] = generate_text_for_display($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield'], $parse_flags, true);
206
207 2
		return $poll_info;
208
	}
209 2
210
	/**
211
	 * @param array $cur_voted_id
212
	 * @param array $poll_info
213
	 * @param int $poll_total
214
	 * @param int $poll_most
215
	 * @return array
216
	 */
217
	private function get_poll_options(array $cur_voted_id, array $poll_info, $poll_total, $poll_most)
218
	{
219 2
		$options = [];
220
		foreach ($poll_info as $poll_option)
221 2
		{
222
			$option_pct = $this->calculate_option_percent($poll_option['poll_option_total'], $poll_total);
223 2
			$option_pct_rel = $this->calculate_option_percent_rel($poll_option['poll_option_total'], $poll_most);
224 2
225
			$options[] = array(
226 2
				'POLL_OPTION_ID' 			=> $poll_option['poll_option_id'],
227 2
				'POLL_OPTION_CAPTION' 		=> $poll_option['poll_option_text'],
228 2
				'POLL_OPTION_RESULT' 		=> $poll_option['poll_option_total'],
229 2
				'POLL_OPTION_PERCENT' 		=> sprintf("%.1d%%", round($option_pct * 100)),
230 2
				'POLL_OPTION_PERCENT_REL' 	=> sprintf("%.1d%%", round($option_pct_rel * 100)),
231 2
				'POLL_OPTION_PCT'			=> round($option_pct * 100),
232 2
				'POLL_OPTION_WIDTH'     	=> round($option_pct * 250),
233 2
				'POLL_OPTION_VOTED'			=> $this->user_has_voted_option($poll_option['poll_option_id'], $cur_voted_id),
234 2
				'POLL_OPTION_MOST_VOTES'	=> $this->is_most_voted($poll_option['poll_option_total'], $poll_most),
235 2
			);
236 2
		}
237 2
238 2
		return $options;
239
	}
240
241
	/**
242
	 * @param int $topic_id
243
	 * @return array
244 2
	 */
245
	private function get_users_votes($topic_id)
246 2
	{
247 2
		$cur_voted_id = array();
248 2
		if ($this->user->data['is_registered'])
249
		{
250 1
			$sql = 'SELECT poll_option_id
251 1
			FROM ' . POLL_VOTES_TABLE . '
252 1
			WHERE topic_id = ' . (int) $topic_id . '
253 1
				AND vote_user_id = ' . (int) $this->user->data['user_id'];
254
			$result = $this->db->sql_query($sql);
255 1
256
			while ($row = $this->db->sql_fetchrow($result))
257 1
			{
258 1
				$cur_voted_id[] = $row['poll_option_id'];
259 1
			}
260 1
			$this->db->sql_freeresult($result);
261
		}
262
		else
263
		{
264
			// Cookie based guest tracking ... I don't like this but hum ho
265
			// it's oft requested. This relies on "nice" users who don't feel
266 1
			// the need to delete cookies to mess with results.
267 1
			if ($this->request->is_set($this->config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE))
0 ignored issues
show
phpbb\request\request_interface::COOKIE of type integer is incompatible with the type phpbb\request\request_interface expected by parameter $super_global of phpbb\request\request_interface::is_set(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

267
			if ($this->request->is_set($this->config['cookie_name'] . '_poll_' . $topic_id, /** @scrutinizer ignore-type */ \phpbb\request\request_interface::COOKIE))
Loading history...
268 1
			{
269 1
				$cur_voted_id = explode(',', $this->request->variable($this->config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE));
0 ignored issues
show
phpbb\request\request_interface::COOKIE of type integer is incompatible with the type phpbb\request\request_interface expected by parameter $super_global of phpbb\request\request_interface::variable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

269
				$cur_voted_id = explode(',', $this->request->variable($this->config['cookie_name'] . '_poll_' . $topic_id, '', true, /** @scrutinizer ignore-type */ \phpbb\request\request_interface::COOKIE));
Loading history...
270 1
				$cur_voted_id = array_map('intval', $cur_voted_id);
271
			}
272
		}
273 2
274
		return $cur_voted_id;
275
	}
276
277
	/**
278
	 * @param int $poll_option_id
279
	 * @param array $cur_voted_id
280
	 * @return bool
281 2
	 */
282
	private function user_has_voted_option($poll_option_id, array $cur_voted_id)
283 2
	{
284
		return (in_array($poll_option_id, $cur_voted_id)) ? true : false;
285
	}
286
287
	/**
288
	 * @param int $poll_option_total
289
	 * @param int $poll_total
290
	 * @return float|int
291 2
	 */
292
	private function calculate_option_percent($poll_option_total, $poll_total)
293 2
	{
294
		return ($poll_total > 0) ? $poll_option_total / $poll_total : 0;
295
	}
296
297
	/**
298
	 * @param int $poll_option_total
299
	 * @param int $poll_most
300
	 * @return float|int
301 2
	 */
302
	private function calculate_option_percent_rel($poll_option_total, $poll_most)
303 2
	{
304
		return ($poll_most > 0) ? $poll_option_total / $poll_most : 0;
305
	}
306
307
	/**
308
	 * @param int $poll_option_total
309
	 * @param int $poll_most
310
	 * @return bool
311 2
	 */
312
	private function is_most_voted($poll_option_total, $poll_most)
313 2
	{
314
		return ($poll_option_total > 0 && $poll_option_total == $poll_most) ? true : false;
315
	}
316
317
	/**
318
	 * @param int $poll_max_options
319
	 * @return bool
320 2
	 */
321
	private function poll_is_multiple_choice($poll_max_options)
322 2
	{
323
		return ($poll_max_options > 1) ? true : false;
324
	}
325
326
	/**
327
	 * @param int $poll_length
328
	 * @param int $poll_end
329
	 * @return string
330 2
	 */
331
	private function get_poll_length_lang($poll_length, $poll_end)
332 2
	{
333
		return ($poll_length) ? $this->translator->lang(($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT', $this->user->format_date($poll_end)) : '';
334
	}
335
336
	/**
337
	 * @param bool $s_can_vote
338
	 * @param array $cur_voted_id
339
	 * @return bool
340 2
	 */
341
	private function show_results($s_can_vote, array $cur_voted_id)
342 2
	{
343
		return (!$s_can_vote || ($s_can_vote && sizeof($cur_voted_id))) ? true : false;
344
	}
345
}
346