Issues (17)

Security Analysis    no request data  

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

  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.
  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.
  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.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  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.
  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.
  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.
  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.
  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.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  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.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
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.

lib/Vote.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
    Condorcet PHP - Election manager and results calculator.
4
    Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
5
6
    By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
7
    https://github.com/julien-boudry/Condorcet
8
*/
9
declare(strict_types=1);
10
11
namespace CondorcetPHP\Condorcet;
12
13
use CondorcetPHP\Condorcet\ElectionProcess\VoteUtil;
14
use CondorcetPHP\Condorcet\Throwable\CondorcetException;
15
16
class Vote implements \Iterator
17
{
18
    use Linkable, CondorcetVersion;
19
20
    // Implement Iterator
21
22
        private $position = 1;
23
24 146
        public function rewind() : void {
25 146
            $this->position = 1;
26 146
        }
27
28 3
        public function current() : array {
29 3
            return $this->getRanking()[$this->position];
30
        }
31
32 4
        public function key() : int {
33 4
            return $this->position;
34
        }
35
36 4
        public function next() : void {
37 4
            ++$this->position;
38 4
        }
39
40 4
        public function valid() : bool {
41 4
            return isset($this->getRanking()[$this->position]);
42
        }
43
44
    // Vote
45
46
    private $_ranking;
47
48
    private $_lastTimestamp;
49
50
    private $_counter;
51
52
    private $_ranking_history = [];
53
54
    private $_weight = 1;
55
56
    private $_tags = [];
57
58
    private $_hashCode;
59
60
    private $_electionContext = null;
61
62
        ///
63
64 146
    public function __construct ($ranking, $tags = null, ?float $ownTimestamp = null, ?Election $electionContext = null)
65
    {
66 146
        $this->_electionContext = $electionContext;
67 146
        $tagsFromString = null;
68
69
        // Vote Weight
70 146
        if (is_string($ranking)) :
71 119
            $is_voteWeight = mb_strpos($ranking, '^');
72 119
            if ($is_voteWeight !== false) :
73 3
                $weight = trim( substr($ranking, $is_voteWeight + 1) );
74
75
                // Errors
76 3
                if ( !is_numeric($weight) ) :
77 1
                    throw new CondorcetException(13);
78
                endif;
79
80 3
                $weight = intval($weight);
81
82 3
                $ranking = substr($ranking, 0,$is_voteWeight);
83
84
            endif;
85
86 119
            $is_voteTags = mb_strpos($ranking, '||');
87 119
            if ($is_voteTags !== false) :
88 4
                $tagsFromString = explode(',', trim( substr($ranking, 0, $is_voteTags) ));
89 4
                $ranking = substr($ranking, $is_voteTags + 2);
90
            endif;
91
        endif;
92
93 146
        $this->setRanking($ranking, $ownTimestamp);
94 146
        $this->addTags($tags);
95 146
        $this->addTags($tagsFromString);
96
97 146
        if (isset($weight)) :
98 3
            $this->setWeight($weight);
99
        endif;
100
101 146
        $this->_electionContext = null;
102 146
    }
103
104 2
    public function __sleep () : array
105
    {
106 2
        $this->position = 1;
107
108 2
        return array_keys(get_object_vars($this));
109
    }
110
111 76
    public function __clone ()
112
    {
113 76
        $this->destroyAllLink();
114 76
        $this->setHashCode();
115 76
    }
116
117 146
    public function __toString () : string {
118
        
119 146
        if (empty($this->getTags())) :
120 146
            return $this->getSimpleRanking();
121
        else :
122 17
            return $this->getTagsAsString().' || '.$this->getSimpleRanking();
123
        endif;
124
    }
125
126 1
    public function getHashCode () : string {
127 1
        return $this->_hashCode;
128
    }
129
130
        ///
131
132
    // GETTERS
133
134 146
    public function getRanking () : array
135
    {
136 146
        return $this->_ranking;
137
    }
138
139 4
    public function getHistory () : array
140
    {
141 4
        return $this->_ranking_history;
142
    }
143
144
145 146
    public function getTags () : array
146
    {
147 146
        return $this->_tags;
148
    }
149
150 17
    public function getTagsAsString () : string
151
    {
152 17
        return implode(',',$this->getTags());
153
    }
154
155 2
    public function getCreateTimestamp () : float
156
    {
157 2
        return $this->_ranking_history[0]['timestamp'];
158
    }
159
160 19
    public function getTimestamp () : float
161
    {
162 19
        return $this->_lastTimestamp;
163
    }
164
165 1
    public function countRankingCandidates () : int
166
    {
167 1
        return $this->_counter;
168
    }
169
170 127
    public function getAllCandidates () : array
171
    {
172 127
        $list = [];
173
174 127
        foreach ($this->getRanking() as $rank) :
175 127
            foreach ($rank as $oneCandidate) :
176 127
                $list[] = $oneCandidate;
177
            endforeach;
178
        endforeach;
179
180 127
        return $list;
181
    }
182
183 102
    public function getContextualRanking (Election $election) : array
184
    {
185 102
        if (!$this->haveLink($election)) :
186
            throw new CondorcetException(22);
187
        endif;
188
189 102
        $countContextualCandidate = 0;
190
191 102
        $present = $this->getAllCandidates();
192 102
        $candidates_list = $election->getCandidatesList();
193
194 102
        $newRanking = $this->computeContextualRankingWithoutImplicit($this->getRanking(), $election, $countContextualCandidate);
195
196 102
        if ($election->getImplicitRankingRule() && $countContextualCandidate < $election->countCandidates()) :
197 46
            $last_rank = [];
198 46
            foreach ($candidates_list as $oneCandidate) :
199 46
                if (!in_array($oneCandidate, $present, true)) :
200 46
                    $last_rank[] = $oneCandidate;
201
                endif;
202
            endforeach;
203
204 46
            $newRanking[] = $last_rank;
205
        endif;
206
207 102
        return $newRanking;
208
    }
209
210 102
        protected function computeContextualRankingWithoutImplicit (array $ranking, Election $election, int &$countContextualCandidate = 0) : array
211
        {
212 102
            $newRanking = [];
213 102
            $nextRank = 1;
214 102
            $rankChange = false;
215
216 102
            foreach ($ranking as $CandidatesInRanks) :
217 102
                foreach ($CandidatesInRanks as $candidate) :
218 102
                    if ( $election->isRegisteredCandidate($candidate, true) ) :
219 102
                        $newRanking[$nextRank][] = $candidate;
220 102
                        $countContextualCandidate++;
221 102
                        $rankChange = true;
222
                    endif;
223
                endforeach;
224
225 102
                if ($rankChange) :
226 102
                    $nextRank++;
227 102
                    $rankChange = false;
228
                endif;
229
            endforeach;
230
231 102
            return $newRanking;
232
        }
233
234 1
    public function getContextualRankingAsString (Election $election) : array
235
    {
236 1
        return CondorcetUtil::format($this->getContextualRanking($election),true);
237
    }
238
239 146
    public function getSimpleRanking (?Election $context = null) : string
240
    {
241 146
        $ranking = $context ? $this->getContextualRanking($context) : $this->getRanking();
242
243 146
        $simpleRanking = VoteUtil::getRankingAsString($ranking);
244
245 146
        if ($this->_weight > 1 && ( ($context && $context->isVoteWeightAllowed()) || $context === null )  ) :
246 8
            $simpleRanking .= " ^".$this->getWeight();
247
        endif;
248
249 146
        return $simpleRanking;
250
    }
251
252
253
    // SETTERS
254
255 146
    public function setRanking ($ranking, ?float $ownTimestamp = null) : bool
256
    {
257
        // Timestamp
258 146
        if ($ownTimestamp !== null) :
259 1
            if (!empty($this->_ranking_history) && $this->getTimestamp() >= $ownTimestamp) :
260
                throw new CondorcetException(21);
261
            endif;
262
        endif;
263
264
        // Ranking
265 146
        $candidateCounter = $this->formatRanking($ranking);
266
267 146
        if ($this->_electionContext !== null) :
268 102
            $this->_electionContext->convertRankingCandidates($ranking);
0 ignored issues
show
The method convertRankingCandidates cannot be called on $this->_electionContext (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
269
        endif;
270
271 146
        foreach ($this->_link as $link) :
272 7
            $link->prepareUpdateVote($this);
273
        endforeach;
274
275 146
        $this->_ranking = $ranking;
276 146
        $this->_lastTimestamp = $ownTimestamp ?? microtime(true);
277 146
        $this->_counter = $candidateCounter;
278
279 146
        $this->archiveRanking();
280
281 146
        if (!empty($this->_link)) :
282
283
            try {
284 7
                foreach ($this->_link as $link) :
285 7
                    if (!$link->checkVoteCandidate($this)) :
286 7
                        throw new CondorcetException(18);
287
                    endif;
288
                endforeach;
289
            } catch (CondorcetException $e) {
290
                foreach ($this->_link as $link) :
291
                    $link->setStateToVote();
292
                endforeach;
293
294
                throw $e;
295
            }
296
297 7
            foreach ($this->_link as $link) :
298 7
                $link->finishUpdateVote($this);
299
            endforeach;
300
        endif;
301
302 146
        $this->setHashCode();
303 146
        return true;
304
    }
305
306 146
        private function formatRanking (&$ranking) : int
307
        {
308 146
            if (is_string($ranking)) :
309 120
                $ranking = VoteUtil::convertVoteInput($ranking);
310
            endif;
311
312 146
            if (!is_array($ranking)) :
313
                throw new CondorcetException(5);
314
            endif;
315
316
            $ranking = array_filter($ranking, function ($key) {
317 143
                return is_numeric($key);
318 146
            }, ARRAY_FILTER_USE_KEY);
319
320 146
            ksort($ranking);
321
            
322 146
            $i = 1; $vote_r = [];
323 146
            foreach ($ranking as &$value) :
324 143
                if ( !is_array($value) ) :
325 38
                    $vote_r[$i] = [$value];
326
                else :
327 122
                    $vote_r[$i] = $value;
328
                endif;
329
330 143
                $i++;
331
            endforeach;
332
333 146
            $ranking = $vote_r;
334
335 146
            $counter = 0;
336 146
            $list_candidate = [];
337 146
            foreach ($ranking as &$line) :
338 143
                foreach ($line as &$Candidate) :
339 143
                    if ( !($Candidate instanceof Candidate) ) :
340 122
                        $Candidate = new Candidate ($Candidate);
341 122
                        $Candidate->setProvisionalState(true);
342
                    endif;
343
344 143
                    $counter++;
345
346
                // Check Duplicate
347
348
                    // Check objet reference AND check candidates name
349 143
                    if (!in_array($Candidate, $list_candidate)) :
350 143
                        $list_candidate[] = $Candidate;
351
                    else : 
352 143
                        throw new CondorcetException(5);
353
                    endif;
354
355
                endforeach;
356
            endforeach;
357
358 146
            return $counter;
359
        }
360
361
362 3
    public function removeCandidate ($candidate) : bool
363
    {
364 3
        if ($candidate instanceof Candidate) :
365 1
            $strict = true;
366 3
        elseif (is_string($candidate)) :
367 2
            $strict = false;
368
        else :
369 1
            throw new CondorcetException (32);
370
        endif;
371
372 2
        $ranking = $this->getRanking();
373
374 2
        $rankingCandidate = $this->getAllCandidates();
375
376 2
        if (!in_array($candidate, $rankingCandidate, $strict)) :
377 1
            throw new CondorcetException (32);
378
        endif;
379
380 2
        foreach ($ranking as $rankingKey => &$rank) :
381 2
            foreach ($rank as $oneRankKey => $oneRankValue) :
382 2
                if ( $strict ? $oneRankValue === $candidate : $oneRankValue == $candidate ) :
383 2
                    unset($rank[$oneRankKey]);
384
                endif;
385
            endforeach;
386
387 2
            if (empty($rank)) :
388 2
                unset($ranking[$rankingKey]);
389
            endif;
390
        endforeach;
391
392 2
        $this->setRanking($ranking);
393
394 2
        return true;
395
    }
396
397
398 146
    public function addTags ($tags) : bool
399
    {
400 146
        $tags = VoteUtil::tagsConvert($tags);
401
402 146
        if (empty($tags)) :
403 146
            return false;
404
        endif;
405
406 17
        foreach ($tags as $key => $tag) :
407 17
            if (is_numeric($tag)) :
408
                throw new CondorcetException(17);
409 17
            elseif (in_array($tag, $this->_tags, true)) :
410 17
                unset($tags[$key]);
411
            endif;
412
        endforeach;
413
414 17
        foreach ($tags as $tag) :
415 17
            $this->_tags[] = $tag;
416
        endforeach;
417
418 17
        $this->setHashCode();
419
420 17
        return true;
421
    }
422
423 2
    public function removeTags ($tags) : array
424
    {
425 2
        $tags = VoteUtil::tagsConvert($tags);
426
427 2
        if (empty($tags)) :
428 2
            return [];
429
        endif;
430
431 2
        $rm = [];
432 2
        foreach ($tags as $key => $tag) :
433 2
            $tagK = array_search($tag, $this->_tags, true);
434
435 2
            if ($tagK === false) :
436 1
                unset($tags[$key]);
437
            else :
438 2
                $rm[] = $this->_tags[$tagK];
439 2
                unset($this->_tags[$tagK]);
440
            endif;
441
        endforeach;
442
443 2
        $this->setHashCode();
444 2
        return $rm;
445
    }
446
447 2
    public function removeAllTags () : bool
448
    {
449 2
        $this->removeTags($this->getTags());
450 2
        return true;
451
    }
452
453 93
    public function getWeight () : int
454
    {
455 93
        return $this->_weight;
456
    }
457
458 94
    public function setWeight (int $newWeight) : int
459
    {
460 94
        if ($newWeight < 1) :
461 1
            throw new CondorcetException(26);
462
        endif;
463
464 93
        if ($newWeight !== $this->_weight) :
465
466 8
            $this->_weight = $newWeight;
467
468 8
            if (!empty($this->_link)) :
469 1
                foreach ($this->_link as &$link) :
470 1
                    $link->setStateToVote();
471
                endforeach;
472
            endif;
473
        endif;
474
475 93
        $this->setHashCode();
476
477 93
        return $this->getWeight();
478
    }
479
480
/////////// INTERNAL ///////////
481
482 146
    private function archiveRanking () : void
483
    {
484 146
        $this->_ranking_history[] = [   'ranking' => $this->_ranking,
485 146
                                        'timestamp' => $this->_lastTimestamp,
486 146
                                        'counter' => $this->_counter   ];
487
488 146
        $this->rewind();
489 146
    }
490
491 146
    private function setHashCode () : string
492
    {
493 146
        return $this->_hashCode = hash('sha224', ((string) $this) . microtime(false));
494
    }
495
}
496