View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
15465 | Bug reports | Survey taking | public | 2019-10-28 10:49 | 2021-09-07 09:19 |
Reporter | ancosema | Assigned To | galads | ||
Priority | none | Severity | partial_block | ||
Status | closed | Resolution | fixed | ||
Product Version | 3.19.2 | ||||
Summary | 15465: Possible to fill in survey multiple times | ||||
Description | It is possible to fill in a token-based survey multiple times. It can be opened in several browsers at the same time and filled in in each of them. I tested this with a one-form survey and with a two-form survey, a survey with not anonymized answers and one with anonymized answers, without welcome page. I tested in the latest version of Limesurvey and in several earlier versions (e.g. 3.17.16, | ||||
Steps To Reproduce | Create a survey with one form - checkbox - obliged to fill in in - no welcome page - anonymized or not anonymized responses | ||||
Tags | No tags attached. | ||||
Attached Files | |||||
Bug heat | 8 | ||||
Complete LimeSurvey version number (& build) | 3.19.2+191023, 3.17.16+190906 | ||||
I will donate to the project if issue is resolved | No | ||||
Browser | |||||
Database type & version | MySQL + MariaDB | ||||
Server OS (if known) | |||||
Webserver software & version (if known) | |||||
PHP Version | php 5.6-40 | ||||
Can not reproduce : version tested 3.19.3 Debug set to 2 : send a PHP notice PHP notice.html (22,400 bytes)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>PHP notice</title> <style type="text/css"> /*<![CDATA[*/ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent;margin:0;padding:0;} body{line-height:1;} ol,ul{list-style:none;} blockquote,q{quotes:none;} blockquote:before,blockquote:after,q:before,q:after{content:none;} :focus{outline:0;} ins{text-decoration:none;} del{text-decoration:line-through;} table{border-collapse:collapse;border-spacing:0;} body { font: normal 9pt "Verdana"; color: #000; background: #fff; } h1 { font: normal 18pt "Verdana"; color: #f00; margin-bottom: .5em; } h2 { font: normal 14pt "Verdana"; color: #800000; margin-bottom: .5em; } h3 { font: bold 11pt "Verdana"; } pre { font: normal 11pt Menlo, Consolas, "Lucida Console", Monospace; } pre span.error { display: block; background: #fce3e3; } pre span.ln { color: #999; padding-right: 0.5em; border-right: 1px solid #ccc; } pre span.error-ln { font-weight: bold; } .container { margin: 1em 4em; } .version { color: gray; font-size: 8pt; border-top: 1px solid #aaa; padding-top: 1em; margin-bottom: 1em; } .message { color: #000; padding: 1em; font-size: 11pt; background: #f3f3f3; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; margin-bottom: 1em; line-height: 160%; } .source { margin-bottom: 1em; } .code pre { background-color: #ffe; margin: 0.5em 0; padding: 0.5em; line-height: 125%; border: 1px solid #eee; } .source .file { margin-bottom: 1em; font-weight: bold; } .traces { margin: 2em 0; } .trace { margin: 0.5em 0; padding: 0.5em; } .trace.app { border: 1px dashed #c00; } .trace .number { text-align: right; width: 2em; padding: 0.5em; } .trace .content { padding: 0.5em; } .trace .plus, .trace .minus { display:inline; vertical-align:middle; text-align:center; border:1px solid #000; color:#000; font-size:10px; line-height:10px; margin:0; padding:0 1px; width:10px; height:10px; } .trace.collapsed .minus, .trace.expanded .plus, .trace.collapsed pre { display: none; } .trace-file { cursor: pointer; padding: 0.2em; } .trace-file:hover { background: #f0ffff; } /*]]>*/ </style> </head> <body> <div class="container"> <h1>PHP notice</h1> <p class="message"> Undefined index: include_content </p> <div class="source"> <p class="file">/mnt/data/shnoulle/nginx/www/master/application/core/LSETwigViewRenderer.php(458)</p> <div class="code"><pre><span class="ln">446</span> $aDatas['aSurveyInfo']['bShowClearAll'] = false; // default to not show "Exit and clear survey" button <span class="ln">447</span> <span class="ln">448</span> if (!empty($aDatas['aSurveyInfo']['sid'])) { <span class="ln">449</span> $surveyid = $aDatas['aSurveyInfo']['sid']; <span class="ln">450</span> $event->set('surveyId', $aDatas['aSurveyInfo']['sid']); <span class="ln">451</span> <span class="ln">452</span> // show "Exit and clear survey" button whenever there is 'srid' key set, <span class="ln">453</span> // button won't be rendered on welcome and final page because 'srid' key doesn't exist on those pages <span class="ln">454</span> // additionally checks for submit page to compensate when srid is needed to render other views <span class="ln">455</span> if ( <span class="ln">456</span> isset($_SESSION['survey_' . $surveyid]['srid']) <span class="ln">457</span> && $aDatas['aSurveyInfo']['active'] == 'Y' <span class="error"><span class="ln error-ln">458</span> && $aDatas['aSurveyInfo']['include_content'] !== 'submit' </span><span class="ln">459</span> && $aDatas['aSurveyInfo']['include_content'] !== 'submit_preview' <span class="ln">460</span> ) { <span class="ln">461</span> $aDatas['aSurveyInfo']['bShowClearAll'] = true; <span class="ln">462</span> } <span class="ln">463</span> } <span class="ln">464</span> <span class="ln">465</span> if (!App()->getConfig('force_xmlsettings_for_survey_rendering')){ <span class="ln">466</span> App()->getPluginManager()->dispatchEvent($event); <span class="ln">467</span> $aPluginContent = $event->getAllContent(); <span class="ln">468</span> if (!empty($aPluginContent['sTwigBlocks'])) { <span class="ln">469</span> $sString = $sString.$aPluginContent['sTwigBlocks']; <span class="ln">470</span> } </pre></div> </div> <div class="traces"> <h2>Stack Trace</h2> <table style="width:100%;"> <tbody><tr class="trace app expanded"> <td class="number"> #0 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/application/core/LSETwigViewRenderer.php(339): <strong>LSETwigViewRenderer</strong>-><strong>getPluginsData</strong>("{# LimeSurvey Copyright (C) 2007-2017 The LimeSurvey Pro...", array("aError" => array("type" => "survey-notstart", "message" => "<p class="message-0">We are sorry but you are not allowed to ent...", "URL" => "", "title" => "<p class=' text-danger inherit-sizes' role='alert'> This inv..."), "aSurveyInfo" => array("htmlemail" => "Y", "format" => "G", "template" => "fruity", "language" => "en", ...))) </div> <div class="code"><pre><span class="ln">334</span> // Add to the loader the path of the template and its parents. <span class="ln">335</span> $this->addRecursiveTemplatesPath($oTemplate); <span class="ln">336</span> <span class="ln">337</span> // Plugin for blocks replacement <span class="ln">338</span> <span class="error"><span class="ln error-ln">339</span> list($sString, $aDatas) = $this->getPluginsData($sString, $aDatas); </span><span class="ln">340</span> <span class="ln">341</span> <span class="ln">342</span> } <span class="ln">343</span> <span class="ln">344</span> // Twig rendering </pre></div> </td> </tr> <tr class="trace app expanded"> <td class="number"> #1 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/application/core/LSETwigViewRenderer.php(42): <strong>LSETwigViewRenderer</strong>-><strong>convertTwigToHtml</strong>("{# LimeSurvey Copyright (C) 2007-2017 The LimeSurvey Pro...", array("aError" => array("type" => "survey-notstart", "message" => "<p class="message-0">We are sorry but you are not allowed to ent...", "URL" => "", "title" => "<p class=' text-danger inherit-sizes' role='alert'> This inv..."), "aSurveyInfo" => array("htmlemail" => "Y", "format" => "G", "template" => "fruity", "language" => "en", ...)), TemplateConfiguration) </div> <div class="code"><pre><span class="ln">37</span> { <span class="ln">38</span> $oTemplate = Template::getLastInstance(); <span class="ln">39</span> $oLayoutTemplate = $this->getTemplateForView($sLayout, $oTemplate); <span class="ln">40</span> if ($oLayoutTemplate) { <span class="ln">41</span> $line = file_get_contents($oLayoutTemplate->viewPath.$sLayout); <span class="error"><span class="ln error-ln">42</span> $sHtml = $this->convertTwigToHtml($line, $aDatas, $oTemplate); </span><span class="ln">43</span> $sEmHiddenInputs = LimeExpressionManager::FinishProcessPublicPage(true); <span class="ln">44</span> if($sEmHiddenInputs) { <span class="ln">45</span> $sHtml = str_replace("<!-- emScriptsAndHiddenInputs -->","<!-- emScriptsAndHiddenInputs updated -->\n".$sEmHiddenInputs,$sHtml); <span class="ln">46</span> } <span class="ln">47</span> if ($bReturn) { </pre></div> </td> </tr> <tr class="trace app expanded"> <td class="number"> #2 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/application/controllers/SurveyController.php(143): <strong>LSETwigViewRenderer</strong>-><strong>renderTemplateFromFile</strong>("layout_errors.twig", array("aError" => array("type" => "survey-notstart", "message" => "<p class="message-0">We are sorry but you are not allowed to ent...", "URL" => "", "title" => "<p class=' text-danger inherit-sizes' role='alert'> This inv..."), "aSurveyInfo" => array("htmlemail" => "Y", "format" => "G", "template" => "fruity", "language" => "en", ...)), false) </div> <div class="code"><pre><span class="ln">138</span> $oTemplate = $oSurvey->templateModel; <span class="ln">139</span> <span class="ln">140</span> $aSurveyInfo = $oSurvey->attributes; <span class="ln">141</span> $aSurveyInfo['aError'] = $aReplacementData; <span class="ln">142</span> <span class="error"><span class="ln error-ln">143</span> Yii::app()->twigRenderer->renderTemplateFromFile("layout_errors.twig", array('aError'=>$aReplacementData, 'aSurveyInfo' => $aSurveyInfo), false); </span><span class="ln">144</span> App()->end(); <span class="ln">145</span> } <span class="ln">146</span> } </pre></div> </td> </tr> <tr class="trace app collapsed"> <td class="number"> #3 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/application/controllers/survey/index.php(487): <strong>SurveyController</strong>-><strong>renderExitMessage</strong>("458789", "survey-notstart", array("We are sorry but you are not allowed to enter this survey.", "Please contact Administrator ( your-email@example.net ) for furt..."), null, ...) </div> <div class="code"><pre><span class="ln">482</span> App()->getController()->renderExitMessage( <span class="ln">483</span> $surveyid, <span class="ln">484</span> 'survey-notstart', <span class="ln">485</span> $aMessage, <span class="ln">486</span> null, <span class="error"><span class="ln error-ln">487</span> array($sError) </span><span class="ln">488</span> ); <span class="ln">489</span> } else { <span class="ln">490</span> $sError = gT("This is a controlled survey. You need a valid token to participate."); <span class="ln">491</span> } <span class="ln">492</span> } </pre></div> </td> </tr> <tr class="trace app collapsed"> <td class="number"> #4 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/application/controllers/survey/index.php(24): <strong>index</strong>-><strong>action</strong>() </div> <div class="code"><pre><span class="ln">19</span> public $oTemplate; <span class="ln">20</span> <span class="ln">21</span> public function run() <span class="ln">22</span> { <span class="ln">23</span> useFirebug(); <span class="error"><span class="ln error-ln">24</span> $this->action(); </span><span class="ln">25</span> } <span class="ln">26</span> <span class="ln">27</span> public function action() <span class="ln">28</span> { <span class="ln">29</span> global $surveyid; </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #5 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/actions/CAction.php(76): <strong>index</strong>-><strong>run</strong>() </div> <div class="code"><pre><span class="ln">71</span> { <span class="ln">72</span> $method=new ReflectionMethod($this, 'run'); <span class="ln">73</span> if($method->getNumberOfParameters()>0) <span class="ln">74</span> return $this->runWithParamsInternal($this, $method, $params); <span class="ln">75</span> <span class="error"><span class="ln error-ln">76</span> $this->run(); </span><span class="ln">77</span> return true; <span class="ln">78</span> } <span class="ln">79</span> <span class="ln">80</span> /** <span class="ln">81</span> * Executes a method of an object with the supplied named parameters. </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #6 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/CController.php(308): <strong>CAction</strong>-><strong>runWithParams</strong>(array("sid" => "458789")) </div> <div class="code"><pre><span class="ln">303</span> { <span class="ln">304</span> $priorAction=$this->_action; <span class="ln">305</span> $this->_action=$action; <span class="ln">306</span> if($this->beforeAction($action)) <span class="ln">307</span> { <span class="error"><span class="ln error-ln">308</span> if($action->runWithParams($this->getActionParams())===false) </span><span class="ln">309</span> $this->invalidActionParams($action); <span class="ln">310</span> else <span class="ln">311</span> $this->afterAction($action); <span class="ln">312</span> } <span class="ln">313</span> $this->_action=$priorAction; </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #7 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/CController.php(286): <strong>CController</strong>-><strong>runAction</strong>(index) </div> <div class="code"><pre><span class="ln">281</span> * @see runAction <span class="ln">282</span> */ <span class="ln">283</span> public function runActionWithFilters($action,$filters) <span class="ln">284</span> { <span class="ln">285</span> if(empty($filters)) <span class="error"><span class="ln error-ln">286</span> $this->runAction($action); </span><span class="ln">287</span> else <span class="ln">288</span> { <span class="ln">289</span> $priorAction=$this->_action; <span class="ln">290</span> $this->_action=$action; <span class="ln">291</span> CFilterChain::create($this,$action,$filters)->run(); </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #8 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/CController.php(265): <strong>CController</strong>-><strong>runActionWithFilters</strong>(index, array()) </div> <div class="code"><pre><span class="ln">260</span> { <span class="ln">261</span> if(($parent=$this->getModule())===null) <span class="ln">262</span> $parent=Yii::app(); <span class="ln">263</span> if($parent->beforeControllerAction($this,$action)) <span class="ln">264</span> { <span class="error"><span class="ln error-ln">265</span> $this->runActionWithFilters($action,$this->filters()); </span><span class="ln">266</span> $parent->afterControllerAction($this,$action); <span class="ln">267</span> } <span class="ln">268</span> } <span class="ln">269</span> else <span class="ln">270</span> $this->missingAction($actionID); </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #9 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/CWebApplication.php(282): <strong>CController</strong>-><strong>run</strong>("index") </div> <div class="code"><pre><span class="ln">277</span> { <span class="ln">278</span> list($controller,$actionID)=$ca; <span class="ln">279</span> $oldController=$this->_controller; <span class="ln">280</span> $this->_controller=$controller; <span class="ln">281</span> $controller->init(); <span class="error"><span class="ln error-ln">282</span> $controller->run($actionID); </span><span class="ln">283</span> $this->_controller=$oldController; <span class="ln">284</span> } <span class="ln">285</span> else <span class="ln">286</span> throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".', <span class="ln">287</span> array('{route}'=>$route===''?$this->defaultController:$route))); </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #10 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/web/CWebApplication.php(141): <strong>CWebApplication</strong>-><strong>runController</strong>("survey/index/sid/458789") </div> <div class="code"><pre><span class="ln">136</span> foreach(array_splice($this->catchAllRequest,1) as $name=>$value) <span class="ln">137</span> $_GET[$name]=$value; <span class="ln">138</span> } <span class="ln">139</span> else <span class="ln">140</span> $route=$this->getUrlManager()->parseUrl($this->getRequest()); <span class="error"><span class="ln error-ln">141</span> $this->runController($route); </span><span class="ln">142</span> } <span class="ln">143</span> <span class="ln">144</span> /** <span class="ln">145</span> * Registers the core application components. <span class="ln">146</span> * This method overrides the parent implementation by registering additional core components. </pre></div> </td> </tr> <tr class="trace core collapsed"> <td class="number"> #11 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/framework/base/CApplication.php(185): <strong>CWebApplication</strong>-><strong>processRequest</strong>() </div> <div class="code"><pre><span class="ln">180</span> public function run() <span class="ln">181</span> { <span class="ln">182</span> if($this->hasEventHandler('onBeginRequest')) <span class="ln">183</span> $this->onBeginRequest(new CEvent($this)); <span class="ln">184</span> register_shutdown_function(array($this,'end'),0,false); <span class="error"><span class="ln error-ln">185</span> $this->processRequest(); </span><span class="ln">186</span> if($this->hasEventHandler('onEndRequest')) <span class="ln">187</span> $this->onEndRequest(new CEvent($this)); <span class="ln">188</span> } <span class="ln">189</span> <span class="ln">190</span> /** </pre></div> </td> </tr> <tr class="trace app collapsed"> <td class="number"> #12 </td> <td class="content"> <div class="trace-file"> <div class="plus">+</div> <div class="minus">–</div> /mnt/data/shnoulle/nginx/www/master/index.php(194): <strong>CApplication</strong>-><strong>run</strong>() </div> <div class="code"><pre><span class="ln">189</span> require_once APPPATH . 'core/LSYii_Application' . EXT; <span class="ln">190</span> <span class="ln">191</span> $config = require_once(APPPATH . 'config/internal' . EXT); <span class="ln">192</span> <span class="ln">193</span> Yii::$enableIncludePath = false; <span class="error"><span class="ln error-ln">194</span> Yii::createApplication('LSYii_Application', $config)->run(); </span><span class="ln">195</span> <span class="ln">196</span> /* End of file index.php */ <span class="ln">197</span> /* Location: ./index.php */ </pre></div> </td> </tr> </tbody></table> </div> <div class="version"> 2019-10-28 13:39:23 nginx/1.16.1 <a href="http://www.yiiframework.com/">Yii Framework</a>/1.1.21 </div> </div> <script type="text/javascript"> /*<![CDATA[*/ var traceReg = new RegExp("(^|\\s)trace-file(\\s|$)"); var collapsedReg = new RegExp("(^|\\s)collapsed(\\s|$)"); var e = document.getElementsByTagName("div"); for(var j=0,len=e.length;j<len;j++){ if(traceReg.test(e[j].className)){ e[j].onclick = function(){ var trace = this.parentNode.parentNode; if(collapsedReg.test(trace.className)) trace.className = trace.className.replace("collapsed", "expanded"); else trace.className = trace.className.replace("expanded", "collapsed"); } } } /*]]>*/ </script> </body></html> |
|
I just pulled in the very last changes (3.19.3+191023 - Dev Fixing docblocks) and in the second browser I get now a completely white page - the information in the participant table (uses left) and the responses are correct now |
|
No, unfortunately the issue is still there. The white page seems to be a chromium issue. If I test in Firefox and Chrome, I get two responses |
|
I looked into the code and as far as I can see it's possible to avoid people submitting two (or more times) by adding 'killSurveySession($surveyid);' at line 476 in application/controllers/survey/index.php. It's very strange that you can not reproduce this issue, as I can reproduce it each time. For me it's strange that the page gets refreshed in the second browser, instead of showing the error message that the token has been used already, after the refresh some information is left in the session which makes it possible to submit again. |
|
Please update to the latest version and check if the bug can still be reproduced. Thank you. |
|
Hello ancosema, galads |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2019-10-28 10:49 | ancosema | New Issue | |
2019-10-28 10:49 | ancosema | File Added: limesurvey_survey_458789.lss | |
2019-10-28 14:43 | DenisChenu | File Added: Capture d’écran du 2019-10-28 14-41-27.png | |
2019-10-28 14:43 | DenisChenu | File Added: PHP notice.html | |
2019-10-28 14:43 | DenisChenu | Note Added: 54237 | |
2019-10-28 15:02 | ancosema | Note Added: 54238 | |
2019-10-28 15:17 | ancosema | File Added: screenshot-localhost_85-2019.10.28-15_17_17.png | |
2019-10-28 15:17 | ancosema | Note Added: 54239 | |
2019-11-20 10:34 | ancosema | Note Added: 54702 | |
2019-11-20 16:07 | cdorin | Assigned To | => cdorin |
2019-11-20 16:07 | cdorin | Status | new => assigned |
2021-02-04 21:24 | cdorin | Assigned To | cdorin => |
2021-02-04 21:24 | cdorin | Status | assigned => acknowledged |
2021-02-04 21:24 | cdorin | Description Updated | |
2021-02-04 21:24 | cdorin | Steps to Reproduce Updated | |
2021-03-10 22:16 | ollehar | Status | acknowledged => feedback |
2021-03-10 22:16 | ollehar | Note Added: 63182 | |
2021-09-07 09:19 | galads | Assigned To | => galads |
2021-09-07 09:19 | galads | Status | feedback => closed |
2021-09-07 09:19 | galads | Resolution | open => fixed |
2021-09-07 09:19 | galads | Note Added: 66369 | |
2021-09-07 09:19 | galads | Bug heat | 6 => 8 |