Issues (371)

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.

admin/main.php (4 issues)

1
<?php declare(strict_types=1);
2
/*
3
               XOOPS - PHP Content Management System
4
                   Copyright (c) 2000-2020 XOOPS.org
5
                      <https://xoops.org>
6
 This program is free software; you can redistribute it and/or modify
7
 it under the terms of the GNU General Public License as published by
8
 the Free Software Foundation; either version 2 of the License, or
9
 (at your option) any later version.
10
11
 You may not change or alter any portion of this comment or credits
12
 of supporting developers from this source code or any supporting
13
 source code which is considered copyrighted (c) material of the
14
 original comment or credit authors.
15
16
 This program is distributed in the hope that it will be useful,
17
 but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 GNU General Public License for more details.
20
21
 You should have received a copy of the GNU General Public License
22
 along with this program; if not, write to the Free Software
23
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
24
 */
25
26
/**
27
 * XOOPS Poll Administration
28
 * Routines to manage administration of CRUD and display of polls
29
 *
30
 * @copyright ::  {@link https://xoops.org/ XOOPS Project}
31
 * @license   ::    {@link https://www.gnu.org/licenses/gpl-2.0.html GNU GPL 2.0 or later}
32
 * @subpackage::    admin
33
 * @author    ::    Xoops Module Team
34
 * @since     ::    1.0
35
 *
36
 * @uses      xoops_load() to instantiate needed classes
37
 * @uses      XoopsFormloader
38
 * @uses      Xoopslists
39
 * @uses      CriteriaCompo
40
 * @uses      Criteria
41
 * @uses      xoops_getModuleHandler() to load this modules class handlers
42
 * @uses      ModuleAdmin class to display module administration page navigation
43
 * @uses      $GLOBALS['xoopsSecurity']::getTokenHTML() used for security on input of form data
44
 * @uses      $GLOBALS['xoops'] class::methods used to get general information about XOOPS
45
 * @uses      XoopsPageNav class to display page navigation links for multiple pages of data
46
 * @uses      xoops_template_clear_module_cache() function used to clear cache after data has been updated
47
 * @uses      redirect_header() function to send user to page after completing task(s)
48
 */
49
50
use Xmf\Module\Admin;
51
use Xmf\Request;
52
use XoopsModules\Newbb;
53
use XoopsModules\Xoopspoll\{
54
    Common\Configurator,
55
    Constants,
56
    FormDateTimePicker,
57
    Helper,
58
    Poll,
59
    Utility
60
};
61
62
require_once __DIR__ . '/admin_header.php';
63
require_once $GLOBALS['xoops']->path('class/xoopsblock.php');
64
65
xoops_load('xoopsformloader');
66
xoops_load('xoopslists');
67
68
$helper = Helper::getInstance();
69
70
$configurator = new Configurator();
71
$icons        = $configurator->icons;
72
73
$op = Request::getString('op', Request::getCmd('op', 'list', 'POST'), 'GET');
74
switch ($op) {
75
    case 'list':
76
    default:
77
        $limit = Request::getInt('limit', Constants::DEFAULT_POLL_PAGE_LIMIT);
78
        $start = Request::getInt('start', 0);
79
80
        /** @var \XoopsPersistableObjectHandler $pollHandler */
81
        $pollHandler = $helper->getHandler('Poll');
82
        $criteria    = new \CriteriaCompo();
83
        $criteria->setLimit($limit + 1);
84
        $criteria->setStart($start);
85
        $criteria->setSort('weight ASC, start_time');  // trick criteria to allow 2 sort criteria
86
        $criteria->setOrder('ASC');
87
        $pollObjs   = $pollHandler->getAll($criteria);
88
        $pollsCount = count($pollObjs);
89
90
        xoops_cp_header();
91
        $adminObject = Admin::getInstance();
92
93
        $xoopsTpl->assign('navigation', $adminObject->displayNavigation(basename(__FILE__)));
94
        $adminObject->addItemButton(_AM_XOOPSPOLL_CREATENEWPOLL, 'main.php' . '?op=add', $icon = 'add');
95
        $xoopsTpl->assign('addPollButton', $adminObject->displayButton('left'));
96
97
        $renderedNav = '';
98
99
        if (is_array($pollObjs) && $pollsCount > 0) {
100
            /* if newbb forum module is loaded find poll/topic association */
101
            /** @var \XoopsModuleHandler $moduleHandler */
102
            $moduleHandler = xoops_getHandler('module');
103
            $newbbModule   = $moduleHandler->getByDirname('newbb');
104
            if (($newbbModule instanceof \XoopsModule) && $newbbModule->isactive()) {
105
                /** @var Newbb\TopicHandler $topicHandler */
106
                $topicHandler = Newbb\Helper::getInstance()->getHandler('Topic');
107
                $topicFields  = ['topic_id', 'topic_title', 'poll_id'];
108
                $criteria     = new \CriteriaCompo();
109
                $criteria->add(new \Criteria('topic_haspoll', 0, '>'));
110
                $pollsWithTopics = [];
111
                $topicsWithPolls = $topicHandler->getAll($criteria, $topicFields, false);
112
                foreach ($topicsWithPolls as $pollTopics) {
113
                    $pollsWithTopics[$pollTopics['poll_id']] = [
114
                        'topic_id'    => $pollTopics['topic_id'],
115
                        'topic_title' => $pollTopics['topic_title'],
116
                    ];
117
                }
118
                if (!empty($pollsWithTopics)) {
119
                    $adminObject->addInfoBox(_AM_XOOPSPOLL_NEWBB_SUPPORT);
120
                    $adminObject->addInfoBoxLine(sprintf("<img src='" . $pathIcon16 . "/forum.png' alt='" . _AM_XOOPSPOLL_NEWBB_SUPPORT . "'> " . _AM_XOOPSPOLL_NEWBB_INTRO, null, null, 'information'), '');
121
                    $newbbIntro = $adminObject->renderInfoBox();
122
                } else {
123
                    $newbbIntro = '';
124
                }
125
            } else {
126
                $pollsWithTopics = [];
127
                $newbbIntro      = '';
128
            }
129
            $xoopsTpl->assign('newbbIntro', $newbbIntro);
130
            //            $xoopsTpl->assign('securityToken', $GLOBALS['xoopsSecurity']->getTokenHTML()); //mb
131
132
            $pollItems = [];
133
            foreach ($pollObjs as $pollObj) {
134
                $pollVars = $pollObj->getValues();
135
                $id       = $pollVars['poll_id'];
136
137
                if (array_key_exists($id, $pollsWithTopics)) {
138
                    $topic_id    = $pollsWithTopics[$id]['topic_id'];
139
                    $topic_title = $pollsWithTopics[$id]['topic_title'];
140
                } else {
141
                    $topic_id    = 0;
142
                    $topic_title = '';
143
                }
144
145
                $checked = (Constants::DISPLAY_POLL_IN_BLOCK === $pollVars['display']) ? ' checked' : '';
146
147
                $xuCurrentTimestamp   = xoops_getUserTimestamp(time());
148
                $xuCurrentFormatted   = ucfirst(date(_MEDIUMDATESTRING, (int)$xuCurrentTimestamp));
149
                $xuStartTimestamp     = xoops_getUserTimestamp($pollVars['start_time']);
150
                $xuStartFormattedTime = ucfirst(date(_MEDIUMDATESTRING, (int)$xuStartTimestamp));
151
                $xuEndTimestamp       = xoops_getUserTimestamp($pollVars['end_time']);
152
153
                if ($xuEndTimestamp > $xuCurrentTimestamp) {
154
                    $end = ucfirst(date(_MEDIUMDATESTRING, (int)$xuEndTimestamp)); // formatted output for current user
155
                } else {
156
                    $end = "<span class='red'>" . _AM_XOOPSPOLL_EXPIRED . '</span><br>' . "<a href='" . $_SERVER['SCRIPT_NAME'] . "?op=restart&amp;poll_id={$id}'>" . _AM_XOOPSPOLL_RESTART . '</a>';
157
                }
158
159
                $pollItems[$id] = [
160
                    'question'             => $pollVars['question'],
161
                    'id'                   => $id,
162
                    'weight'               => $pollVars['weight'],
163
                    'topic_id'             => $topic_id,
164
                    'topic_title'          => $topic_title,
165
                    'checked'              => $checked,
166
                    'voters'               => $pollVars['voters'],
167
                    'votes'                => $pollVars['votes'],
168
                    'xuStartFormattedTime' => $xuStartFormattedTime,
169
                    'end'                  => $end,
170
                    'buttons'              => [
171
                        'edit'   => [
172
                            'href' => $_SERVER['SCRIPT_NAME'] . "?op=edit&amp;poll_id={$id}",
173
                            'file' => $pathIcon16 . '/edit.png',
174
                            'alt'  => _AM_XOOPSPOLL_EDITPOLL,
175
                        ],
176
                        'clone'  => [
177
                            'href' => $_SERVER['SCRIPT_NAME'] . "?op=clone&amp;poll_id={$id}",
178
                            'file' => $pathIcon16 . '/editcopy.png',
179
                            'alt'  => _AM_XOOPSPOLL_CLONE,
180
                        ],
181
                        'delete' => [
182
                            'href' => $_SERVER['SCRIPT_NAME'] . "?op=delete&amp;poll_id={$id}",
183
                            'file' => $pathIcon16 . '/delete.png',
184
                            'alt'  => _DELETE,
185
                        ],
186
                        'log'    => [
187
                            'href' => $_SERVER['SCRIPT_NAME'] . "?op=log&amp;poll_id={$id}",
188
                            'file' => $pathIcon16 . '/search.png',
189
                            'alt'  => _AM_XOOPSPOLL_VIEWLOG,
190
                        ],
191
                    ],
192
                ];
193
                if ($topic_id > 0) {
194
                    $pollItems[$id]['buttons']['forum'] = [
195
                        'href' => $GLOBALS['xoops']->url('modules/newbb/viewtopic.php') . "?topic_id={$topic_id}",
196
                        'file' => $pathIcon16 . '/forum.png',
197
                        'alt'  => _AM_XOOPSPOLL_NEWBB_TOPIC . '&nbsp;' . htmlspecialchars($topic_title, ENT_QUOTES | ENT_HTML5),
198
                    ];
199
                }
200
            }
201
            xoops_load('pagenav');
202
            $pageNav     = new \XoopsPageNav($pollsCount, $limit, $start);
203
            $renderedNav = $pageNav->renderNav();
204
        }
205
206
        $xoopsTpl->assign('pollItems', $pollItems);
207
        $xoopsTpl->assign('rendered_nav', $renderedNav);
208
        $xoopsTpl->assign('self', $_SERVER['SCRIPT_NAME']);
209
        $xoopsTpl->display($helper->path('templates/admin/xoopspoll_list.tpl'));
210
        require_once __DIR__ . '/admin_footer.php';
211
        exit();
212
    case 'edit':
213
    case 'add':
214
        $optionHandler = $helper->getHandler('Option');
215
        $pollHandler   = $helper->getHandler('Poll');
216
        $pollId        = Request::getInt('poll_id', 0);
217
        $pollObj       = $pollHandler->get($pollId); // will auto create object if poll_id=0
218
219
        // display the form
220
        xoops_cp_header();
221
        $adminObject = Admin::getInstance();
222
        $adminObject->displayNavigation(basename(__FILE__));
223
        $pollObj->renderForm($_SERVER['SCRIPT_NAME'], 'post');
0 ignored issues
show
The method renderForm() does not exist on XoopsObject. It seems like you code against a sub-type of XoopsObject such as XoopsModules\Xoopspoll\Poll. ( Ignorable by Annotation )

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

223
        $pollObj->/** @scrutinizer ignore-call */ 
224
                  renderForm($_SERVER['SCRIPT_NAME'], 'post');
Loading history...
224
        require_once __DIR__ . '/admin_footer.php';
225
        exit();
226
    case 'update':
227
        if (!$GLOBALS['xoopsSecurity']->check()) {
228
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_MEDIUM, implode('<br>', $GLOBALS['xoopsSecurity']->getErrors()));
229
        }
230
231
        $optionHandler = $helper->getHandler('Option');
232
        $logHandler    = $helper->getHandler('Log');
233
        $pollHandler   = $helper->getHandler('Poll');
234
235
        $pollId  = Request::getInt('poll_id', 0, 'POST');
236
        $pollObj = $pollHandler->get($pollId);
237
238
        $notify = Request::getInt('notify', Constants::NOTIFICATION_ENABLED, 'POST');
239
240
        $currentTimestamp = time();
241
        $xuEndTimestamp   = strtotime(Request::getString('xu_end_time', null, 'POST'));
242
        $endTimestamp     = empty($xuEndTimestamp) ? ($currentTimestamp + Constants::DEFAULT_POLL_DURATION) : userTimeToServerTime($xuEndTimestamp);
243
        $xuStartTimestamp = strtotime(Request::getString('xu_start_time', null, 'POST'));
244
        $startTimestamp   = empty($xuStartTimestamp) ? ($endTimestamp - Constants::DEFAULT_POLL_DURATION) : userTimeToServerTime($xuStartTimestamp);
245
246
        //  don't allow changing start time if there are votes in the log
247
        if (($startTimestamp < $pollObj->getVar('start_time')) && ($logHandler->getTotalVotesByPollId($pollId) > 0)) {
248
            $startTimestamp = $pollObj->getVar('start_time'); //don't change start time
249
        }
250
251
        $pollVars = [
252
            'user_id'     => Request::getInt('user_id', $GLOBALS['xoopsUser']->uid(), 'POST'),
253
            'question'    => Request::getString('question', null, 'POST'),
254
            'description' => Request::getText('description', null, 'POST'),
255
            'mail_status' => (Constants::NOTIFICATION_ENABLED === $notify) ? Constants::POLL_NOT_MAILED : Constants::POLL_MAILED,
256
            'mail_voter'  => Request::getInt('mail_voter', Constants::NOT_MAIL_POLL_TO_VOTER, 'POST'),
257
            'start_time'  => $startTimestamp,
258
            'end_time'    => $endTimestamp,
259
            'display'     => Request::getInt('display', Constants::DO_NOT_DISPLAY_POLL_IN_BLOCK, 'POST'),
260
            'visibility'  => Request::getInt('visibility', Constants::HIDE_NEVER, 'POST'),
261
            'weight'      => Request::getInt('weight', Constants::DEFAULT_WEIGHT, 'POST'),
262
            'multiple'    => Request::getInt('multiple', Constants::NOT_MULTIPLE_SELECT_POLL, 'POST'),
263
            'multilimit'  => Request::getInt('multilimit', Constants::MULTIPLE_SELECT_LIMITLESS, 'POST'),
264
            'anonymous'   => Request::getInt('anonymous', Constants::ANONYMOUS_VOTING_DISALLOWED, 'POST'),
265
        ];
266
        $pollObj->setVars($pollVars);
267
        $pollId = $pollHandler->insert($pollObj);
268
        if (!$pollId) {
269
            $err = $pollObj->getHtmlErrors();
270
            exit($err);
271
        }
272
273
        // now get the options
274
        $optionIdArray    = Request::getArray('option_id', [], 'POST');
275
        $optionIdArray    = array_map('\intval', $optionIdArray);
276
        $optionTextArray  = Request::getArray('option_text', [], 'POST');
277
        $optionColorArray = Request::getArray('option_color', [], 'POST');
278
279
        foreach ($optionIdArray as $key => $oId) {
280
            if (!empty($oId) && ($optionObj = $optionHandler->get($oId))) {
281
                // existing option object so need to update it
282
                $optionTextArray[$key] = trim($optionTextArray[$key]);
283
                if ('' === $optionTextArray[$key]) {
284
                    // want to delete this option
285
                    if (false !== $optionHandler->delete($optionObj)) {
286
                        // now remove it from the log
287
                        $logHandler->deleteByOptionId($optionObj->getVar('option_id'));
288
                    }
289
                } else {
290
                    $optionObj->setVar('option_text', $optionTextArray[$key]);
291
                    $optionObj->setVar('option_color', $optionColorArray[$key]);
292
                    $optionObj->setVar('poll_id', $pollId);
293
                    $optionHandler->insert($optionObj);
294
                }
295
            } else {
296
                // new option object
297
                $optionObj             = $optionHandler->create();
298
                $optionTextArray[$key] = trim($optionTextArray[$key]);
299
                if ('' !== $optionTextArray[$key]) { // ignore if text is empty
300
                    $optionObj->setVar('option_text', $optionTextArray[$key]);
301
                    $optionObj->setVar('option_color', $optionColorArray[$key]);
302
                    $optionObj->setVar('poll_id', $pollId);
303
                    $optionHandler->insert($optionObj);
304
                }
305
                unset($optionObj);
306
            }
307
        }
308
309
        unset($optionHandler, $logHandler, $pollObj, $pollHandler, $pollId);
310
        // clear the template cache so changes take effect immediately
311
        require_once $GLOBALS['xoops']->path('class/template.php');
312
        xoops_template_clear_module_cache($GLOBALS['xoopsModule']->getVar('mid'));
313
        redirect_header($_SERVER['SCRIPT_NAME'] . '?op=list', Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_DBUPDATED);
314
        break;
315
    case 'delete':
316
        $pollId      = Request::getInt('poll_id', 0);
317
        $pollHandler = $helper->getHandler('Poll');
318
        $pollObj     = $pollHandler->get($pollId);
319
        if (!($pollObj instanceof Poll)) {
320
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, implode('<br>', $pollHandler->getErrors()));
0 ignored issues
show
It seems like $pollHandler->getErrors() can also be of type null; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

320
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, implode('<br>', /** @scrutinizer ignore-type */ $pollHandler->getErrors()));
Loading history...
The method getErrors() does not exist on XoopsModules\Xoopspoll\PollHandler. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

320
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, implode('<br>', $pollHandler->/** @scrutinizer ignore-call */ getErrors()));
Loading history...
321
        }
322
        xoops_cp_header();
323
        $adminObject = Admin::getInstance();
324
        $adminObject->displayNavigation(basename(__FILE__));
325
        xoops_confirm(
326
            [
327
                'op'      => 'delete_ok',
328
                'poll_id' => $pollId,
329
            ],
330
            $_SERVER['SCRIPT_NAME'],
331
            sprintf(_AM_XOOPSPOLL_RUSUREDEL, htmlspecialchars($pollObj->getVar('question'), ENT_QUOTES | ENT_HTML5))
332
        );
333
        require_once __DIR__ . '/admin_footer.php';
334
        //    xoops_cp_footer();
335
        exit();
336
    case 'delete_ok':
337
        if (!$GLOBALS['xoopsSecurity']->check()) {
338
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_MEDIUM, implode('<br>', $GLOBALS['xoopsSecurity']->getErrors()));
339
        }
340
        $pollHandler = $helper->getHandler('Poll');
341
        $pollId      = Request::getInt('poll_id', 0, 'POST');
342
        if ($pollHandler->deleteAll(new \Criteria('poll_id', $pollId, '='))) {
343
            $optionHandler = $helper->getHandler('Option');
344
            $optionHandler->deleteAll(new \Criteria('poll_id', $pollId));
345
            $logHandler = $helper->getHandler('Log');
346
            $logHandler->deleteByPollId($pollId);
347
            unset($pollHandler, $optionHandler, $logHandler);
348
            // clear the template cache
349
            require_once $GLOBALS['xoops']->path('class/template.php');
350
            xoops_template_clear_module_cache($GLOBALS['xoopsModule']->getVar('mid'));
351
            // delete comments for this poll
352
            xoops_comment_delete($GLOBALS['xoopsModule']->getVar('mid'), $pollId);
353
354
            //now clear association with newbb topic if one exists
355
            /** @var \XoopsModuleHandler $moduleHandler */
356
            $moduleHandler = xoops_getHandler('module');
357
            $newbbModule   = $moduleHandler->getByDirname('newbb');
358
            if (($newbbModule instanceof XoopsModule) && $newbbModule->isactive()) {
359
                /** @var Newbb\TopicHandler $topicHandler */
360
                $topicHandler = \XoopsModules\Newbb\Helper::getInstance()->getHandler('Topic');
361
                $criteria     = new CriteriaCompo();
362
                $criteria->add(new Criteria('poll_id', $pollId, '='));
363
                /* {@internal the order of the next 2 statements is important! */
364
                $topicHandler->updateAll('topic_haspoll', 0, $criteria); // clear poll association
365
                $topicHandler->updateAll('poll_id', 0, $criteria); // clear poll_id
366
                xoops_template_clear_module_cache($newbbModule->getVar('mid')); // clear newbb template cache
367
            }
368
        }
369
        redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_DBUPDATED);
370
        break;
371
    case 'restart':
372
        $pollId      = Request::getInt('poll_id', 0);
373
        $pollHandler = $helper->getHandler('Poll');
374
        $pollObj     = $pollHandler->get($pollId);
375
        $pollForm    = new \XoopsThemeForm(_AM_XOOPSPOLL_RESTARTPOLL, 'poll_form', $_SERVER['SCRIPT_NAME'], 'post', true);
376
377
        // setup times for forms
378
        $xuCurrentTimestamp = xoops_getUserTimestamp(time());
379
        $xuCurrentFormatted = ucfirst(date(_MEDIUMDATESTRING, (int)$xuCurrentTimestamp));
380
        $xuStartTimestamp   = $xuCurrentTimestamp;
381
        $xuEndTimestamp     = $xuStartTimestamp + Constants::DEFAULT_POLL_DURATION;
382
383
        $timeTray = new \XoopsFormElementTray(_AM_XOOPSPOLL_POLL_TIMES, '&nbsp;&nbsp;', 'time_tray');
384
385
        //add start time to the form
386
        $startTimeText = new FormDateTimePicker("<div class='bold'>" . _AM_XOOPSPOLL_START_TIME . '<br>' . "<span class='x-small'>" . _AM_XOOPSPOLL_FORMAT . '<br>' . sprintf(_AM_XOOPSPOLL_CURRENTTIME, $xuCurrentFormatted) . '</span></div>', 'xu_start_time', 20, $xuStartTimestamp);
387
        $timeTray->addElement($startTimeText, true);
388
389
        // add ending date to form
390
        $endTimeText = new FormDateTimePicker("<div class='bold middle'>" . _AM_XOOPSPOLL_EXPIRATION . '</div>', 'xu_end_time', 20, $xuEndTimestamp);
391
        $timeTray->addElement($endTimeText, true);
392
        $pollForm->addElement($timeTray);
393
394
        $pollForm->addElement(new \XoopsFormRadioYN(_AM_XOOPSPOLL_NOTIFY, 'notify', Constants::POLL_MAILED));
395
        $pollForm->addElement(new \XoopsFormRadioYN(_AM_XOOPSPOLL_RESET, 'reset', 0));
396
        $pollForm->addElement(new \XoopsFormHidden('op', 'restart_ok'));
397
        $pollForm->addElement(new \XoopsFormHidden('poll_id', $pollId));
398
        $pollForm->addElement(new \XoopsFormButton('', 'poll_submit', _AM_XOOPSPOLL_RESTART, 'submit'));
399
400
        xoops_cp_header();
401
        $adminObject = Admin::getInstance();
402
        $adminObject->displayNavigation(basename(__FILE__));
403
        $pollForm->display();
404
        require_once __DIR__ . '/admin_footer.php';
405
        exit();
406
    case 'restart_ok':
407
        if (!$GLOBALS['xoopsSecurity']->check()) {
408
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_MEDIUM, implode('<br>', $GLOBALS['xoopsSecurity']->getErrors()));
409
        }
410
        $pollId = Request::getInt('poll_id', 0, 'POST');
411
        if (empty($pollId)) {
412
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_ERROR_INVALID_POLLID);
413
        }
414
415
        $pollHandler = $helper->getHandler('Poll');
416
        $pollObj     = $pollHandler->get($pollId);
417
418
        $xuEndTimestamp   = strtotime(Request::getString('xu_end_time', null, 'POST'));
419
        $xuStartTimestamp = strtotime(Request::getString('xu_start_time', null, 'POST'));
420
421
        $endTimestamp   = empty($xuEndTimestamp) ? (time() + Constants::DEFAULT_POLL_DURATION) : userTimeToServerTime($xuEndTimestamp);
422
        $startTimestamp = empty($xuStartTimestamp) ? ($xuEndTimestamp - Constants::DEFAULT_POLL_DURATION) : userTimeToServerTime($xuStartTimestamp);
423
        $pollObj->setVar('end_time', $endTimestamp);
424
        $pollObj->setVar('start_time', $startTimestamp);
425
426
        $notify = Request::getInt('notify', Constants::NOTIFICATION_DISABLED, 'POST');
427
        if (Constants::NOTIFICATION_ENABLED === $notify) {
428
            // if notify, set mail status to "not mailed"
429
            $pollObj->setVar('mail_status', Constants::POLL_NOT_MAILED);
430
        } else {
431
            // if not notify, set mail status to already "mailed"
432
            $pollObj->setVar('mail_status', Constants::POLL_MAILED);
433
        }
434
        // save the poll settings
435
        $pollHandler->insert($pollObj);
436
437
        $reset = Request::getInt('reset', Constants::DO_NOT_RESET_RESULTS, 'POST');
438
        if (Constants::RESET_RESULTS === $reset) {
439
            // reset all logs
440
            $logHandler = $helper->getHandler('Log');
441
            $logHandler->deleteByPollId($pollId);
442
            unset($logHandler);
443
            $optionHandler = $helper->getHandler('Option');
444
            $criteria      = new \Criteria('poll_id', $pollId, '=');
445
            $optionHandler->updateAll('option_count', 0, $criteria);
446
        }
447
        if (!$pollHandler->updateCount($pollObj)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $pollHandler->updateCount($pollObj) of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
448
            echo $pollObj->getHtmlErrors();
449
            exit();
450
        }
451
        require_once $GLOBALS['xoops']->path('class/template.php');
452
        xoops_template_clear_module_cache($GLOBALS['xoopsModule']->getVar('mid'));
453
        redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_DBUPDATED);
454
        break;
455
    case 'log':
456
        $pollId   = Request::getInt('poll_id', 0);
457
        $limit    = Request::getInt('limit', Constants::DEFAULT_POLL_PAGE_LIMIT);
458
        $start    = Request::getInt('start', 0);
459
        $orderby  = Request::getString('orderby', 'time');
460
        $orderdir = Request::getString('orderdir', 'ASC');
461
462
        if (empty($pollId)) {
463
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_ERROR_INVALID_POLLID);
464
        }
465
466
        $pollHandler  = $helper->getHandler('Poll');
467
        $pollObj      = $pollHandler->get($pollId);
468
        $expiredClass = ($pollObj->getVar('end_time') < time()) ? ' red' : '';
469
        xoops_cp_header();
470
        $adminObject = Admin::getInstance();
471
        $adminObject->displayNavigation(basename(__FILE__));
472
473
        $xuEndTimestamp     = userTimeToServerTime($pollObj->getVar('end_time'));
474
        $xuEndFormattedTime = ucfirst(date(_MEDIUMDATESTRING, (int)$xuEndTimestamp));
475
476
        /**
477
         * @todo need to move this html to a template and pass variables via xoopsTpl
478
         * {@internal show a brief description of the question we are focusing on}
479
         */
480
        echo "<h4 class='left'>"
481
             . _AM_XOOPSPOLL_LOGSLIST
482
             . "</h4>\n"
483
             . "<table class='outer bnone width100' style='padding: 0; margin: 0;'>\n"
484
             . "  <tr>\n"
485
             . "    <td>\n"
486
             . "      <table class='width100 bnone marg2 pad3'>\n"
487
             . "        <thead>\n"
488
             . "        <tr class='bg3'>\n"
489
             . "          <th class='center' nowrap>"
490
             . _AM_XOOPSPOLL_POLLQUESTION
491
             . "</th>\n"
492
             . "          <th class='center' nowrap>"
493
             . _AM_XOOPSPOLL_POLLDESC
494
             . "</th>\n"
495
             . '          <th nowrap>'
496
             . _AM_XOOPSPOLL_VOTERS
497
             . "</th>\n"
498
             . '          <th nowrap>'
499
             . _AM_XOOPSPOLL_VOTES
500
             . "</th>\n"
501
             . '          <th nowrap>'
502
             . _AM_XOOPSPOLL_EXPIRATION
503
             . "</th>\n"
504
             . "        </tr>\n"
505
             . "        </thead>\n"
506
             . "        <tfoot></tfoot>\n"
507
             . "        <tbody>\n"
508
             . "        <tr class='bg1'>\n"
509
             . "          <td class='center'>"
510
             . $pollObj->getVar('question')
511
             . "</td>\n"
512
             . "          <td class='center'>"
513
             . $pollObj->getVar('description')
514
             . "</td>\n"
515
             . "          <td class='center'>"
516
             . $pollObj->getVar('voters')
517
             . "</td>\n"
518
             . "          <td class='center'>"
519
             . $pollObj->getVar('votes')
520
             . "</td>\n"
521
             . "          <td class='center{$expiredClass}'>{$xuEndFormattedTime}</td>\n"
522
             . "        </tr>\n"
523
             . "        </tbody>\n"
524
             . "      </table>\n"
525
             . "    </td>\n"
526
             . "  </tr>\n"
527
             . "</table>\n";
528
        echo "<br>\n";
529
530
        if ($pollObj->getVar('votes')) {  // there are votes to show
531
            // show summary of results
532
            $optionHandler = $helper->getHandler('Option');
533
            $criteria      = new \CriteriaCompo();
534
            $criteria->add(new \Criteria('poll_id', $pollId, '='));
535
            $criteria->setGroupBy('option_id');
536
            $options = $optionHandler->getAll($criteria, null, false);
537
538
            echo "<div class='center' style='margin-bottom: 2em;'>\n"
539
                 . "<h4 class='left'>"
540
                 . _AM_XOOPSPOLL_LOGSLIST
541
                 . "</h4>\n"
542
                 . "<table class='outer bnone width100' style='padding: 0; margin: 0;'>\n"
543
                 . "<thead>\n"
544
                 . "  <tr>\n"
545
                 . "    <th class='width15'>"
546
                 . _AM_XOOPSPOLL_OPTION
547
                 . "</th>\n"
548
                 . '    <th>'
549
                 . _AM_XOOPSPOLL_LABEL
550
                 . "</th>\n"
551
                 . "    <th class='width15'>"
552
                 . _AM_XOOPSPOLL_COUNT
553
                 . "</th>\n"
554
                 . "  </tr>\n"
555
                 . "</thead>\n"
556
                 . "<tfoot></tfoot>\n"
557
                 . '<tbody>';
558
559
            $rowClass = 'even';
560
            $i        = 0;
561
            foreach ($options as $thisOption) {
562
                echo "  <tr class='{$rowClass}'><td class='center'>" . ++$i . "</td><td class='center'>{$thisOption['option_text']}</td><td class='center'>{$thisOption['option_count']}</td></tr>\n";
563
                $rowClass = ('odd' === $rowClass) ? 'even' : 'odd';
564
            }
565
            echo "</tbody>\n" . "</table>\n" . '</div>';
566
567
            // show logs
568
            echo "<h4 class='left'>" . _AM_XOOPSPOLL_POLLVOTERS . "</h4>\n";
569
570
            $logHandler = $helper->getHandler('Log');
571
            $criteria   = new \CriteriaCompo();
572
            $criteria->add(new \Criteria('poll_id', $pollId, '='));
573
            $logsCount = $logHandler->getCount($criteria);
574
            $criteria->setSort($orderby);
575
            $criteria->setOrder($orderdir);
576
            $criteria->setStart($start);
577
            $criteria->setLimit($limit);
578
            $logsArray = $logHandler->getAll($criteria);
579
580
            $arrowUp   = $pathIcon16 . '/up.gif';
581
            $arrowDown = $pathIcon16 . '/down.gif';
582
            $sorthref  = $_SERVER['SCRIPT_NAME'] . "?op=log&amp;poll_id={$pollId}&amp;orderby=";
583
            $class     = 'even';
584
585
            if (is_array($logsArray) && $logsCount > 0) {
586
                echo "<table class='outer bnone width100' style='padding: 0; margin: 0;'>\n" . "  <tr>\n" . "    <td class='bg2'>\n" . "      <table class='width100 bnone pad3 marg2'>\n" . "        <thead>\n" . "        <tr class='bg3'>\n";
587
588
                $ipLabel    = (Constants::LOOK_UP_HOST === $GLOBALS['xoopsModuleConfig']['look_up_host']) ? _AM_XOOPSPOLL_HOST_NAME : _AM_XOOPSPOLL_IP;
589
                $fieldArray = [
590
                    ['order' => 'log_id', 'label' => _AM_XOOPSPOLL_LOGID],
591
                    ['order' => 'option_id', 'label' => _AM_XOOPSPOLL_OPTIONID],
592
                    ['order' => 'ip', 'label' => $ipLabel],
593
                    ['order' => 'user_id', 'label' => _AM_XOOPSPOLL_VOTER],
594
                    ['order' => 'time', 'label' => _AM_XOOPSPOLL_VOTETIME],
595
                ];
596
597
                foreach ($fieldArray as $field) {
598
                    echo "          <th nowrap>\n"
599
                         . "            <a href='{$sorthref}{$field['order']}&amp;orderdir=ASC'><img src='{$arrowUp}' alt=''></a>\n"
600
                         . "            <a href='{$sorthref}{$field['order']}&amp;orderdir=DESC'><img src='{$arrowDown}' alt=''></a>\n"
601
                         . "            &nbsp;{$field['label']}\n"
602
                         . "          </th>\n";
603
                }
604
                echo '        </tr>' . "        </thead>\n" . "        <tbody>\n";
605
606
                $optionHandler = $helper->getHandler('Option');
607
                $luhConfig     = Constants::LOOK_UP_HOST === $GLOBALS['xoopsModuleConfig']['look_up_host'];
608
                foreach ($logsArray as $thisLog) {
609
                    $logVals  = $thisLog->getValues();
610
                    $option   = $optionHandler->get($logVals['option_id']);
611
                    $remoteIp = $luhConfig ? Utility::getHostByAddrWithCache($logVals['ip']) : $logVals['ip'];
612
                    echo "        <tr class='bg1'>\n" . "          <td class='{$class} center'>{$logVals['log_id']}</td>\n" . "          <td class='{$class}'>" . $option->getVar('option_text') . "</td>\n" . "          <td class='{$class} center'>{$remoteIp}</td>\n";
613
614
                    if (0 !== $logVals['user_id']) {
615
                        $user  = new \XoopsUser($logVals['user_id']);
616
                        $uname = $user->getVar('uname');
617
618
                        $from_userid = $GLOBALS['xoopsUser']->getVar('uid');
619
                        $to_userid   = $user->getVar('uid');
620
                        $pmLink      = $GLOBALS['xoops']->buildUrl(
621
                            $GLOBALS['xoops']->path('pmlite.php', true),
622
                            [
623
                                'send'        => 1,
624
                                'from_userid' => $from_userid,
625
                                'to_userid'   => $to_userid,
626
                            ]
627
                        );
628
629
                        echo "          <td class='{$class} center'>\n"
630
                             . '            <a href='
631
                             . $GLOBALS['xoops']->url('/userinfo.php')
632
                             . '?uid='
633
                             . $user->getVar('uid')
634
                             . ">{$uname}</a>&nbsp;\n"
635
                             . "            <a href='{$pmLink}' target='_blank'><img src='"
636
                             . $pathIcon16
637
                             . "/mail_generic.png' alt='"
638
                             . _AM_XOOPSPOLL_PM_VOTER
639
                             . "' title='"
640
                             . _AM_XOOPSPOLL_PM_VOTER
641
                             . "'>\n"
642
                             . "          </td>\n";
643
                    } else {
644
                        echo "          <td class='{$class} center'>{$GLOBALS['xoopsConfig']['anonymous']}</td>\n";
645
                    }
646
                    $xuLogTimestamp     = userTimeToServerTime($logVals['time']);
647
                    $xuLogFormattedTime = ucfirst(date(_DATESTRING, (int)$xuLogTimestamp));
648
649
                    echo "          <td class='{$class} center'>{$xuLogFormattedTime}</td>\n" . "        </tr>\n";
650
                    $class = ('odd' === $class) ? 'even' : 'odd';
651
                }
652
                echo "        </tbody>\n" . "      </table>\n" . "    </td>\n" . "  </tr>\n" . "</table>\n";
653
654
                xoops_load('pagenav');
655
                $pageNav = new \XoopsPageNav($logsCount, $limit, $start, 'start', "op=log&amp;poll_id={$pollId}");
656
                echo "<div class='right' style='margin: 2em auto;'>" . $pageNav->renderNav() . '</div>';
657
            }
658
        }
659
660
        //    echo "<div class='center' style='margin-bottom: 1em;'>[ <a href='" . $_SERVER['SCRIPT_NAME'] . "?op=list'>" . _AM_XOOPSPOLL_RETURNLIST . "</a> ]</div>\n";
661
        //    echo "<div class='center' style='margin-bottom: 1em;'>[ <a href='" . $_SERVER['SCRIPT_NAME'] . "?op=list'><img src='". $pathIcon16 ."/back.png' alt='" . _AM_XOOPSPOLL_RETURNLIST . "' title='" . _AM_XOOPSPOLL_RETURNLIST . "'>" . _AM_XOOPSPOLL_RETURNLIST . "</a> ]</div>\n";
662
        $adminObject->addItemButton(_AM_XOOPSPOLL_RETURNLIST, 'main.php' . '?op=list', $icon = '../16/back');
663
        $adminObject->displayButton('center');
664
        require_once __DIR__ . '/admin_footer.php';
665
        break;
666
    case 'quickupdate':
667
668
        $pollId = Request::getArray('poll_id', [], 'POST');
669
        $pollId = array_map('\intval', $pollId);
670
671
        $count = count($pollId);
672
673
        if ($count) {
674
            $pollHandler = $helper->getHandler('Poll');
675
            $criteria    = new \CriteriaCompo();
676
            $idString    = '(' . implode(',', $pollId) . ')';
677
            $criteria->add(new \Criteria('poll_id', $idString, 'IN'));
678
            $pollObjs = $pollHandler->getAll($criteria);
679
680
            // get display variables from form POST
681
            $display = Request::getArray('display', [], 'POST');
682
            $display = array_map('\intval', $display);
683
            $weight  = Request::getArray('weight', [], 'POST');
684
            $weight  = array_map('\intval', $weight);
685
686
            foreach ($pollObjs as $pollObj) {
687
                $thisId           = $pollObj->getVar('poll_id');
688
                $display[$thisId] = empty($display[$thisId]) ? Constants::DO_NOT_DISPLAY_POLL_IN_BLOCK : Constants::DISPLAY_POLL_IN_BLOCK;
689
                $weight[$thisId]  = empty($weight[$thisId]) ? Constants::DEFAULT_WEIGHT : $weight[$thisId];
690
                if ($display[$thisId] !== $pollObj->getVar('display') || $weight[$thisId] !== $pollObj->getVar('weight')) {
691
                    $pollObj->setVars(['display' => $display[$thisId], 'weight' => $weight[$thisId]]);
692
                    $pollHandler->insert($pollObj);
693
                }
694
                unset($pollObj);
695
            }
696
            unset($pollObjs);
697
            require_once $GLOBALS['xoops']->path('class/template.php');
698
            xoops_template_clear_module_cache($GLOBALS['xoopsModule']->getVar('mid'));
699
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_DBUPDATED);
700
        } else {
701
            redirect_header($_SERVER['SCRIPT_NAME'], Constants::REDIRECT_DELAY_SHORT, _AM_XOOPSPOLL_NOTHING_HERE);
702
        }
703
        break;
704
    // added cloning capability in v 1.40
705
    case 'clone':
706
        $pollHandler   = $helper->getHandler('Poll');
707
        $optionHandler = $helper->getHandler('Option');
708
        $pollId        = Request::getInt('poll_id', 0);
709
        $pollObj       = $pollHandler->get($pollId);
710
        $origValues    = $pollObj->getValues();
711
        unset($origValues['poll_id']);
712
        $pollDuration = $origValues['end_time'] - $origValues['start_time'];
713
        $pollDuration = ($pollDuration > 0) ? $pollDuration : Constants::DEFAULT_POLL_DURATION;
714
        $newValues    = [
715
            'votes'       => 0,
716
            'voters'      => 0,
717
            'mail_status' => Constants::POLL_NOT_MAILED,
718
            'question'    => $origValues['question'] . '(' . _AM_XOOPSPOLL_CLONE . ')',
719
            'start_time'  => time(),  //set the start time to now
720
            'end_time'    => time() + $pollDuration,
721
        ];
722
        $cloneValues  = array_merge($origValues, $newValues);
723
        $cloneObj     = $pollHandler->create();
724
        $cloneObj->setVars($cloneValues);
725
        $cloneId = $pollHandler->insert($cloneObj);
726
727
        // now set cloned options
728
        $optionObjs = $optionHandler->getAllByPollId($pollId);
729
        foreach ($optionObjs as $optionObj) {
730
            $cloneOptObj                 = $optionHandler->create();
731
            $cloneValues                 = $optionObj->getValues();
732
            $cloneValues['option_id']    = 0;
733
            $cloneValues['poll_id']      = $cloneId;
734
            $cloneValues['option_count'] = 0;
735
            $cloneOptObj->setVars($cloneValues);
736
            $optId = $optionHandler->insert($cloneOptObj);
737
            unset($cloneValues, $cloneOptObj);
738
        }
739
        unset($pollObj, $cloneObj, $origValues, $cloneValues, $newValues);
740
        redirect_header($_SERVER['SCRIPT_NAME'] . "?poll_id={$cloneId}&amp;op=edit", Constants::REDIRECT_DELAY_MEDIUM, _AM_XOOPSPOLL_CLONE_SUCCESS);
741
        break;
742
}
743