From 0895cd163934b2770ba75e29de573bbcf941fd8f Mon Sep 17 00:00:00 2001 From: Denis Chenu Date: Tue, 2 Apr 2019 18:55:59 +0200 Subject: [PATCH] Fixed issue #14649: CDbException when a "default answer" option is not compatible with a question type (#1252) Dev: Add an option to set or not the invalid answer string Dev: show the error for admin with surveycontent update right Dev: log it if server admin want to track hack on server --- .../helpers/expressions/em_manager_helper.php | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/application/helpers/expressions/em_manager_helper.php b/application/helpers/expressions/em_manager_helper.php index 5d9a3437e73..d3d10e1b092 100644 --- a/application/helpers/expressions/em_manager_helper.php +++ b/application/helpers/expressions/em_manager_helper.php @@ -6936,10 +6936,24 @@ public function _ValidateQuestion($questionSeq,$force=false) $allSQs = explode('|',$LEM->qid2code[$qid]); foreach ($allSQs as $sgqa) { - if (!isset($_SESSION[$LEM->sessid][$sgqa]) && !is_null($LEM->knownVars[$sgqa]['default'])) - { + if (!isset($_SESSION[$LEM->sessid][$sgqa]) && !is_null($LEM->knownVars[$sgqa]['default'])) { $_SESSION[$LEM->sessid][$sgqa]=$LEM->ProcessString($LEM->knownVars[$sgqa]['default'], $qInfo['qid'], NULL, 1, 1, false, false, true);// Fill the $_SESSION to don't do it again a second time - $LEM->updatedValues[$sgqa] = $updatedValues[$sgqa] = array('type'=>$qInfo['type'],'value'=>$_SESSION[$LEM->sessid][$sgqa]); + if(self::checkValidityAnswer($qInfo['type'],$_SESSION[$LEM->sessid][$sgqa],$sgqa,$qInfo,Permission::model()->hasSurveyPermission($LEM->sid, 'surveycontent', 'update'))) { + $LEM->updatedValues[$sgqa] = $updatedValues[$sgqa] = array('type'=>$qInfo['type'],'value'=>$_SESSION[$LEM->sessid][$sgqa]); + } + /* cleanup $LEM->validityString[$sgqa] */ + $validityString = self::getValidityString($sgqa); + /* Add it in view for user with Permission surveycontent update right (double check, but I think it's more clear)*/ + if( $validityString && Permission::model()->hasSurveyPermission($LEM->sid, 'surveycontent', 'update') ) + { + $validTip .= Yii::app()->getController()->renderPartial('//survey/questions/question_help/error-tip', array( + 'qid'=>$qid, + 'coreId' =>"vmsg_{$qid}_defaultvalueerror", + 'vclass'=>'defaultvalueerror', + 'coreClass'=>'ls-em-tip em_defaultvalueerror', + 'vtip' => sprintf(gT("Error in default value : %s"),$validityString) + ), true); + } } } } @@ -10136,12 +10150,13 @@ public static function convertNonLatinNumerics($str, $lang) * @param string $value : the value * @param string $sgq : the sgqa * @param array $qinfo : an array with information from question - * + * @param boolean $set : update the invalid string or not. Used for #14649 (invalid default value) + * * @return boolean true : if question is OK to be put in session, false if must be set to null */ - private static function checkValidityAnswer($type,$value,$sgq,$qinfo) + private static function checkValidityAnswer($type,$value,$sgq,$qinfo,$set = true) { - if(isset($value) && $value!=="") + if(!empty($value)) { /* This function is called by a static function , then set it to static .... */ $LEM =& LimeExpressionManager::singleton(); @@ -10153,19 +10168,19 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case '5': // 5 point choice if(!in_array($value,array("1","2","3","4","5"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case '!': //List - dropdown case 'L': //LIST drop-down/radio-button list - if(substr($sgq,-5)!='other')// We must validate $value==="0", then don't use empty. $value is not set if irrelevant , then don't use $value!==null + if(substr($sgq,-5)!='other') { if($value=="-oth-") { if($qinfo['info']['other']!='Y') { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } } @@ -10173,7 +10188,7 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) { if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } } @@ -10184,7 +10199,7 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) { if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } } @@ -10192,28 +10207,28 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'F': // Array if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'B': // Array 10 point if(!in_array($value,array("1","2","3","4","5","6","7","8","9","10"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'A': // Array 5 point if(!in_array($value,array("1","2","3","4","5"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'E': // Array increase decrease same if(!in_array($value,array("I","D","S"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10226,14 +10241,14 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'C': // Array Yes No Uncertain if(!in_array($value,array("Y","N","U"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'H': // Array by column if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10241,7 +10256,7 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) $scale=intval(substr($sgq,-1)); // Get the scale {SGQ}#0 or {SGQ}#1 actually if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language,$scale)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10257,14 +10272,14 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'G': // Gender if(!in_array($value,array("M","F"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'I': // Language switch if(!in_array($value,Survey::model()->findByPk($LEM->sid)->getAllLanguages())) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10272,14 +10287,14 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'N': // Numerical if(!preg_match("/^[-]?(\d{1,20}\.\d{0,10}|\d{1,20})$/",$value)) // DECIMAL(30,10) { - $LEM->invalidAnswerString[$sgq]=gT("This question only accept 30 digits including 10 decimals."); + $LEM->addValidityString($sgq,$value,gT("This question only accept 30 digits including 10 decimals."),$set); /* Show an error but don't unset value : this can happen without hack */ } break; case 'R': // Ranking if(!Answer::model()->getAnswerFromCode($qinfo['info']['qid'],$value,$language)) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10289,7 +10304,7 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'Y': // Gender if(!in_array($value,array("Y","N"))) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10302,14 +10317,14 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) case 'M': if($value!="Y" && (substr($sgq,-5)!='other' && $qinfo['info']['other']=='Y')) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; case 'P': if(substr($sgq,-7)!='comment' && $value!="Y" && (substr($sgq,-5)!='other' && $qinfo['info']['other']=='Y')) { - $LEM->invalidAnswerString[$sgq]=sprintf(gT("%s is an invalid value for this question"),htmlspecialchars($value)); + $LEM->addValidityString($sgq,$value,gT("%s is an invalid value for this question"),$set); return false; } break; @@ -10320,6 +10335,21 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) return true; } + /** + * Set or log an invalid answer string + * @param string $sgqa : the SGQ (answer column / SGQA) + * @param string $message : the message + * @param boolean $add : add it to current validity or only og it + * @return void + */ + public function addValidityString($sgqa,$value,$message,$add = true ) + { + $sid = intval($this->sid); // Show 0 for null, more clear + Yii::log(sprintf("Survey %s invalid value %s for %s : %s (%s)",$sid,$value,$sgqa,$message,($add ? "added":"silently")),'error','application.LimeExpressionManager.invalidAnswerString.addValidityString'); + if($add) { + $this->invalidAnswerString[$sgqa]=sprintf($message,Chtml::encode($value)); + } + } /** * return the actual validity string , and reset the variable used ($_SESSION) * @param string $sgqa : the SGQ (answer name)