$aPermissionB['title']) { return 1; } else { return -1; } } /** * Translation helper function. * @param string $string * @param string $escapemode */ function gT($string, $escapemode = 'html') { Yii::import('application.libraries.Limesurvey_lang'); if (isset(App()->lang)) { return App()->lang->gT($string, $escapemode); } else { return $string; } } function eT($string, $escapemode = 'html') { echo gT($string, $escapemode); } function ngT($single, $plural, $number, $escapemode = 'html') { Yii::import('application.libraries.Limesurvey_lang'); return App()->lang->ngT($single, $plural, $number, $escapemode); } /** * getQuestionTypeList() Returns list of question types available in LimeSurvey. Edit this if you are adding a new * question type * * @param string $SelectedCode Value of the Question Type (defaults to "T") * @param string $ReturnType Type of output from this function (defaults to selector) * * @return depending on $ReturnType param, returns a straight "array" of question types, or an list * */ function getQuestionTypeList($SelectedCode = "T", $ReturnType = "selector") { $publicurl = Yii::app()->getConfig('publicurl'); $qtypes = Question::typeList(); if ($ReturnType == "array") return $qtypes; if ($ReturnType == "group") { foreach ($qtypes as $qkey => $qtype) { $newqType[$qtype['group']][$qkey] = $qtype; } $qtypeselecter = ""; foreach ($newqType as $group => $members) { $qtypeselecter .= ''; foreach ($members as $TypeCode => $TypeProperties) { $qtypeselecter .= " formatted list of existing surveys * */ function getSurveyList($returnarray=false, $surveyid=false) { static $cached = null; $timeadjust = getGlobalSetting('timeadjust'); $clang = new Limesurvey_lang(isset(Yii::app()->session['adminlang']) ? Yii::app()->session['adminlang'] : 'en'); if(is_null($cached)) { $args = array('order'=>'surveyls_title'); if (!Permission::model()->hasGlobalPermission('superadmin','read')) { $surveyidresult = Survey::model()->permission(Yii::app()->user->getId())->with(array('languagesettings'=>array('condition'=>'surveyls_language=language')))->findAll($args); } else { $surveyidresult = Survey::model()->with(array('languagesettings'=>array('condition'=>'surveyls_language=language')))->findAll($args); } $surveynames = array(); foreach ($surveyidresult as $result) { $surveynames[] = array_merge($result->attributes, $result->defaultlanguage->attributes); } $cached = $surveynames; } else { $surveynames = $cached; } $surveyselecter = ""; if ($returnarray===true) return $surveynames; $activesurveys=''; $inactivesurveys=''; $expiredsurveys=''; if ($surveynames) { foreach($surveynames as $sv) { $surveylstitle=flattenText($sv['surveyls_title']); if (strlen($surveylstitle)>45) { $surveylstitle = htmlspecialchars(mb_strcut(html_entity_decode($surveylstitle,ENT_QUOTES,'UTF-8'), 0, 45, 'UTF-8'))."..."; } if($sv['active']!='Y') { $inactivesurveys .= "\n"; } elseif($sv['expires']!='' && $sv['expires'] < dateShift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)) { $expiredsurveys .="\n"; } else { $activesurveys .= "\n"; } } // End Foreach } //Only show each activesurvey group if there are some if ($activesurveys!='') { $surveyselecter .= "\n"; $surveyselecter .= $activesurveys . ""; } if ($expiredsurveys!='') { $surveyselecter .= "\n"; $surveyselecter .= $expiredsurveys . ""; } if ($inactivesurveys!='') { $surveyselecter .= "\n"; $surveyselecter .= $inactivesurveys . ""; } if (!isset($svexist)) { $surveyselecter = "\n".$surveyselecter; } else { $surveyselecter = "\n".$surveyselecter; } return $surveyselecter; } function getTemplateList() { $usertemplaterootdir=Yii::app()->getConfig("usertemplaterootdir"); $standardtemplaterootdir=Yii::app()->getConfig("standardtemplaterootdir"); if (!$usertemplaterootdir) {die("getTemplateList() no template directory");} if ($handle = opendir($standardtemplaterootdir)) { while (false !== ($file = readdir($handle))) { if (!is_file("$standardtemplaterootdir/$file") && $file != "." && $file != ".." && $file!=".svn" && isStandardTemplate($file)) { $list_of_files[$file] = $standardtemplaterootdir.DIRECTORY_SEPARATOR.$file; } } closedir($handle); } if ($handle = opendir($usertemplaterootdir)) { while (false !== ($file = readdir($handle))) { if (!is_file("$usertemplaterootdir/$file") && $file != "." && $file != ".." && $file!=".svn") { $list_of_files[$file] = $usertemplaterootdir.DIRECTORY_SEPARATOR.$file; } } closedir($handle); } ksort($list_of_files); return $list_of_files; } function getAdminThemeList() { // $usertemplaterootdir=Yii::app()->getConfig("usertemplaterootdir"); $standardtemplaterootdir=Yii::app()->getConfig("styledir"); // if (!$usertemplaterootdir) {die("getTemplateList() no template directory");} if ($handle = opendir($standardtemplaterootdir)) { while (false !== ($file = readdir($handle))) { if (!is_file("$standardtemplaterootdir/$file") && $file != "." && $file != ".." && $file!=".svn") { $list_of_files[$file] = $standardtemplaterootdir.DIRECTORY_SEPARATOR.$file; } } closedir($handle); } /* if ($handle = opendir($usertemplaterootdir)) { while (false !== ($file = readdir($handle))) { if (!is_file("$usertemplaterootdir/$file") && $file != "." && $file != ".." && $file!=".svn") { $list_of_files[$file] = $usertemplaterootdir.DIRECTORY_SEPARATOR.$file; } } closedir($handle); } */ ksort($list_of_files); return $list_of_files; } /** * getQuestions() queries the database for an list of all questions matching the current survey and group id * * @return This string is returned containing formatted list of questions in the current survey and group */ function getQuestions($surveyid,$gid,$selectedqid) { $clang = Yii::app()->lang; $s_lang = Survey::model()->findByPk($surveyid)->language; $qrows = Question::model()->findAllByAttributes(array('sid' => $surveyid, 'gid' => $gid, 'language' => $s_lang, 'parent_qid' => 0),array('order'=>'question_order')); if (!isset($sQuestionselecter)) {$sQuestionselecter="";} foreach ($qrows as $qrow) { $qrow = $qrow->attributes; $qrow['title'] = strip_tags($qrow['title']); $link = Yii::app()->getController()->createUrl("/admin/survey/sa/view/surveyid/".$surveyid."/gid/".$gid."/qid/".$qrow['qid']); $sQuestionselecter .= "\n".$sQuestionselecter; } else { $link = Yii::app()->getController()->createUrl("/admin/survey/sa/view/surveyid/".$surveyid."/gid/".$gid); $sQuestionselecter = "\n".$sQuestionselecter; } return $sQuestionselecter; } /** * getGidPrevious() returns the Gid of the group prior to the current active group * * @param string $surveyid * @param string $gid * * @return The Gid of the previous group */ function getGidPrevious($surveyid, $gid) { $clang = Yii::app()->lang; if (!$surveyid) {$surveyid=returnGlobal('sid',true);} $s_lang = Survey::model()->findByPk($surveyid)->language; $qresult = QuestionGroup::model()->findAllByAttributes(array('sid' => $surveyid, 'language' => $s_lang), array('order'=>'group_order')); $i = 0; $iPrev = -1; foreach ($qresult as $qrow) { $qrow = $qrow->attributes; if ($gid == $qrow['gid']) {$iPrev = $i - 1;} $i += 1; } if ($iPrev >= 0) {$GidPrev = $qresult[$iPrev]->gid;} else {$GidPrev = "";} return $GidPrev; } /** * getQidPrevious() returns the Qid of the question prior to the current active question * * @param string $surveyid * @param string $gid * @param string $qid * * @return This Qid of the previous question */ function getQidPrevious($surveyid, $gid, $qid) { $clang = Yii::app()->lang; $s_lang = Survey::model()->findByPk($surveyid)->language; $qrows = Question::model()->findAllByAttributes(array('gid' => $gid, 'sid' => $surveyid, 'language' => $s_lang, 'parent_qid'=>0),array('order'=>'question_order')); $i = 0; $iPrev = -1; if (count($qrows) > 0) { foreach ($qrows as $qrow) { $qrow = $qrow->attributes; if ($qid == $qrow['qid']) {$iPrev = $i - 1;} $i += 1; } } if ($iPrev >= 0) {$QidPrev = $qrows[$iPrev]->qid;} else {$QidPrev = "";} return $QidPrev; } /** * getGidNext() returns the Gid of the group next to the current active group * * @param string $surveyid * @param string $gid * * @return The Gid of the next group */ function getGidNext($surveyid, $gid) { $clang = Yii::app()->lang; if (!$surveyid) {$surveyid=returnGlobal('sid',true);} $s_lang = Survey::model()->findByPk($surveyid)->language; $qresult = QuestionGroup::model()->findAllByAttributes(array('sid' => $surveyid, 'language' => $s_lang), array('order'=>'group_order')); $GidNext=""; $i = 0; $iNext = 0; foreach ($qresult as $qrow) { $qrow = $qrow->attributes; if ($gid == $qrow['gid']) {$iNext = $i + 1;} $i += 1; } if ($iNext < count($qresult)) {$GidNext = $qresult[$iNext]->gid;} else {$GidNext = "";} return $GidNext; } /** * getQidNext() returns the Qid of the question prior to the current active question * * @param string $surveyid * @param string $gid * @param string $qid * * @return This Qid of the previous question */ function getQidNext($surveyid, $gid, $qid) { $clang = Yii::app()->lang; $s_lang = Survey::model()->findByPk($surveyid)->language; $qrows = Question::model()->findAllByAttributes(array('gid' => $gid, 'sid' => $surveyid, 'language' => $s_lang, 'parent_qid' => 0), array('order'=>'question_order')); $i = 0; $iNext = 0; foreach ($qrows as $qrow) { if ($qid == $qrow->qid && $qid) {$iNext = $i + 1;} $i += 1; } if ($iNext < count($qrows)) {$QidNext = $qrows[$iNext]->qid;} else {$QidNext = "";} return $QidNext; } function convertGETtoPOST($url) { // This function must be deprecated and replaced by $.post $url = preg_replace('/&/i','&',$url); $stack = explode('?',$url); $calledscript = array_shift($stack); $query = array_shift($stack); $aqueryitems = explode('&',$query); $arrayParam = Array(); $arrayVal = Array(); foreach ($aqueryitems as $queryitem) { $stack = explode ('=', $queryitem); $paramname = array_shift($stack); $value = array_shift($stack); $arrayParam[] = "'".$paramname."'"; $arrayVal[] = substr($value, 0, 9) != "document." ? "'".$value."'" : $value; } // $Paramlist = "[" . implode(",",$arrayParam) . "]"; // $Valuelist = "[" . implode(",",$arrayVal) . "]"; $Paramlist = "new Array(" . implode(",",$arrayParam) . ")"; $Valuelist = "new Array(" . implode(",",$arrayVal) . ")"; $callscript = "sendPost('$calledscript','',$Paramlist,$Valuelist);"; return $callscript; } /** * This function calculates how much space is actually used by all files uploaded * using the File Upload question type * * @returns integer Actual space used in MB */ function calculateTotalFileUploadUsage(){ global $uploaddir; $sQuery='select sid from {{surveys}}'; $oResult = dbExecuteAssoc($sQuery); //checked $aRows = $oResult->readAll(); $iTotalSize=0.0; foreach ($aRows as $aRow) { $sFilesPath=$uploaddir.'/surveys/'.$aRow['sid'].'/files'; if (file_exists($sFilesPath)) { $iTotalSize+=(float)getDirectorySize($sFilesPath); } } return (float)$iTotalSize/1024/1024; } function getDirectorySize($directory) { $size = 0; foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) as $file){ $size+=$file->getSize(); } return $size; } /** * Gets number of groups inside a particular survey * * @param string $surveyid * @param mixed $lang */ function getGroupSum($surveyid, $lang) { //$condn = "WHERE sid=".$surveyid." AND language='".$lang."'"; //Getting a count of questions for this survey $condn = array('sid'=>$surveyid,'language'=>$lang); $sumresult3 = count(QuestionGroup::model()->findAllByAttributes($condn)); //Checked) return $sumresult3 ; } /** * getMaxGroupOrder($surveyid) queries the database for the maximum sortorder of a group and returns the next higher one. * * @param mixed $surveyid */ function getMaxGroupOrder($surveyid) { $s_lang = Survey::model()->findByPk($surveyid)->language; //$max_sql = "SELECT max( group_order ) AS max FROM ".db_table_name('groups')." WHERE sid =$surveyid AND language='{$s_lang}'" ; $query = QuestionGroup::model()->find(array('order' => 'group_order desc')); $current_max = !is_null($query) ? $query->group_order : ''; if($current_max!="") { return ++$current_max ; } else return "0" ; } /** * getGroupOrder($surveyid,$gid) queries the database for the sortorder of a group. * * @param mixed $surveyid * @param mixed $gid * @return mixed */ function getGroupOrder($surveyid,$gid) { $s_lang = Survey::model()->findByPk($surveyid)->language; //$grporder_sql = "SELECT group_order FROM ".db_table_name('groups')." WHERE sid =$surveyid AND language='{$s_lang}' AND gid=$gid" ; $grporder_result = QuestionGroup::model()->findByAttributes(array('sid' => $surveyid, 'gid' => $gid, 'language' => $s_lang)); //Checked $grporder_row = $grporder_result->attributes ; $group_order = $grporder_row['group_order']; if($group_order=="") { return "0" ; } else return $group_order ; } /** * getMaxQuestionOrder($gid) queries the database for the maximum sortorder of a question. * */ function getMaxQuestionOrder($gid,$surveyid) { $gid=sanitize_int($gid); $s_lang = Survey::model()->findByPk($surveyid)->language; $max_sql = "SELECT max( question_order ) AS max FROM {{questions}} WHERE gid='$gid' AND language='$s_lang'"; $max_result = Yii::app()->db->createCommand($max_sql)->query(); //Checked $maxrow = $max_result->read() ; $current_max = $maxrow['max']; if($current_max=="") { return "0" ; } else return $current_max ; } /** * getQuestionClass() returns a class name for a given question type to allow custom styling for each question type. * * @param string $input containing unique character representing each question type. * @return string containing the class name for a given question type. */ function getQuestionClass($input) { switch($input) { // I think this is a bad solution to adding classes to question // DIVs but I can't think of a better solution. (eric_t_cruiser) case 'X': return 'boilerplate'; // BOILERPLATE QUESTION case '5': return 'choice-5-pt-radio'; // 5 POINT CHOICE radio-buttons case 'D': return 'date'; // DATE case 'Z': return 'list-radio-flexible'; // LIST Flexible radio-button case 'L': return 'list-radio'; // LIST radio-button case 'W': return 'list-dropdown-flexible'; // LIST drop-down (flexible label) case '!': return 'list-dropdown'; // List - dropdown case 'O': return 'list-with-comment'; // LIST radio-button + textarea case 'R': return 'ranking'; // RANKING STYLE case 'M': return 'multiple-opt'; // Multiple choice checkbox case 'I': return 'language'; // Language Question case 'P': return 'multiple-opt-comments'; // Multiple choice with comments checkbox + text case 'Q': return 'multiple-short-txt'; // TEXT case 'K': return 'numeric-multi'; // MULTIPLE NUMERICAL QUESTION case 'N': return 'numeric'; // NUMERICAL QUESTION TYPE case 'S': return 'text-short'; // SHORT FREE TEXT case 'T': return 'text-long'; // LONG FREE TEXT case 'U': return 'text-huge'; // HUGE FREE TEXT case 'Y': return 'yes-no'; // YES/NO radio-buttons case 'G': return 'gender'; // GENDER drop-down list case 'A': return 'array-5-pt'; // ARRAY (5 POINT CHOICE) radio-buttons case 'B': return 'array-10-pt'; // ARRAY (10 POINT CHOICE) radio-buttons case 'C': return 'array-yes-uncertain-no'; // ARRAY (YES/UNCERTAIN/NO) radio-buttons case 'E': return 'array-increase-same-decrease'; // ARRAY (Increase/Same/Decrease) radio-buttons case 'F': return 'array-flexible-row'; // ARRAY (Flexible) - Row Format case 'H': return 'array-flexible-column'; // ARRAY (Flexible) - Column Format // case '^': return 'slider'; // SLIDER CONTROL case ':': return 'array-multi-flexi'; // ARRAY (Multi Flexi) 1 to 10 case ";": return 'array-multi-flexi-text'; case "1": return 'array-flexible-duel-scale'; // Array dual scale case "*": return 'equation'; // Equation default: return 'generic_question'; // Should have a default fallback }; }; /** * setupColumns() defines all the html tags to be wrapped around * various list type answers. * * @param integer $columns - the number of columns, usually supplied by $dcols * @param integer $answer_count - the number of answers to a question, usually supplied by $anscount * @param string $wrapperclass - a global class for the wrapper * @param string $itemclass - a class for the item * @return array with all the various opening and closing tags to generate a set of columns. * * It returns an array with the following items: * $wrapper['whole-start'] = Opening wrapper for the whole list * $wrapper['whole-end'] = closing wrapper for the whole list * $wrapper['col-devide'] = normal column devider * $wrapper['col-devide-last'] = the last column devider (to allow * for different styling of the last * column * $wrapper['item-start'] = opening wrapper tag for individual * option * $wrapper['item-start-other'] = opening wrapper tag for other * option * $wrapper['item-start-noanswer'] = opening wrapper tag for no answer * option * $wrapper['item-end'] = closing wrapper tag for individual * option * $wrapper['maxrows'] = maximum number of rows in each * column * $wrapper['cols'] = Number of columns to be inserted * (and checked against) * * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Columns are a problem. * Really there is no perfect solution to columns at the moment. * * - Using Tables is problematic semanticly. * - Using inline or float to create columns, causes the answers * flows horizontally, not vertically which is not ideal visually. * - Using CSS3 columns is also a problem because of browser support * and also because if you have answeres split across two or more * lines, and those answeres happen to fall at the bottom of a * column, the answer might be split across columns as well as * lines. * - Using nested unordered list with the first level of
  • s * floated is the same as using tables and so is bad semantically * for the same reason tables are bad. * - Breaking the unordered lists into consecutive floated unordered * lists is not great semantically but probably not as bad as * using tables. * * Because I haven't been able to decide which option is the least * bad, I have handed over that responsibility to the admin who sets * LimeSurvey up on their server. * * There are four options: * 'css' using one of the various CSS only methods for * rendering columns. * (Check the CSS file for your chosen template to see * how columns are defined.) * 'ul' using multiple floated unordered lists. (DEFAULT) * 'table' using conventional tables based layout. * NULL blocks the use of columns * * 'ul' is the default because it's the best possible compromise * between semantic markup and visual layout. */ function setupColumns($columns, $answer_count,$wrapperclass="",$itemclass="") { $column_style = Yii::app()->getConfig('column_style'); if ( !in_array($column_style,array('css','ul','table')) && !is_null($column_style) ) { $column_style = 'ul'; }; if(!is_null($column_style) && $columns!=1) // Add a global class for all column. { $wrapperclass.= " colstyle-{$column_style}"; } if($columns < 2) { $column_style = null; $columns = 1; } if(($columns > $answer_count) && $answer_count>0) { $columns = $answer_count; }; $class_first = ' class="'.$wrapperclass.'"'; if($columns > 1 && !is_null($column_style)) { if($column_style == 'ul') { $ul = '-ul'; } else { $ul = ''; } $class_first = ' class="'.$wrapperclass.' cols-'.$columns . $ul.' first"'; $class = ' class="'.$wrapperclass.' cols-'.$columns . $ul.'"'; $class_last_ul = ' class="'.$wrapperclass.' cols-'.$columns . $ul.' last"'; $class_last_table = ' class="'.$wrapperclass.' cols-'.$columns.' last"'; } else { $class = ' class="'.$wrapperclass.'"'; $class_last_ul = ' class="'.$wrapperclass.'"'; $class_last_table = ' class="'.$wrapperclass.'"'; }; $wrapper = array( 'whole-start' => "\n\n" ,'whole-end' => "\n" ,'col-devide' => '' ,'col-devide-last' => '' ,'item-start' => "\t
  • \n" ,'item-start-other' => "\t
  • \n" ,'item-start-noanswer' => "\t
  • \n" ,'item-end' => "\t
  • \n" ,'maxrows' => ceil($answer_count/$columns) //Always rounds up to nearest whole number ,'cols' => $columns ); switch($column_style) { case 'ul': if($columns > 1) { $wrapper['col-devide'] = "\n\n\n\n"; $wrapper['col-devide-last'] = "\n\n\n\n"; } break; case 'table': $table_cols = ''; for($cols = $columns ; $cols > 0 ; --$cols) { switch($cols) { case $columns: $table_cols .= "\t\n"; break; case 1: $table_cols .= "\t\n"; break; default: $table_cols .= "\t\n"; }; }; if($columns > 1) { $wrapper['col-devide'] = "\t\n\n\n\n\t
      \n"; $wrapper['col-devide-last'] = "\t
    \n\n\n\n\t
      \n"; }; $wrapper['whole-start'] = "\n\n$table_cols\n\t\n\n\n\t
        \n"; $wrapper['whole-end'] = "\t
      \n\n\n\t\n\n"; $wrapper['item-start'] = "
    • \n"; $wrapper['item-end'] = "
    • \n"; }; return $wrapper; }; function alternation($alternate = '' , $type = 'col') { /** * alternation() Returns a class identifyer for alternating between * two options. Used to style alternate elements differently. creates * or alternates between the odd string and the even string used in * as column and row classes for array type questions. * * @param string $alternate = '' (empty) (default) , 'array2' , 'array1' , 'odd' , 'even' * @param string $type = 'col' (default) or 'row' * * @return string representing either the first alternation or the opposite alternation to the one supplied.. */ /* // The following allows type to be left blank for row in subsequent // function calls. // It has been left out because 'row' must be defined the first time // alternation() is called. Since it is only ever written once for each // while statement within a function, 'row' is always defined. if(!empty($alternate) && $type != 'row') { if($alternate == ('array2' || 'array1')) { $type = 'row'; }; }; // It has been left in case it becomes useful but probably should be // removed. */ if($type == 'row') { $odd = 'array2'; // should be row_odd $even = 'array1'; // should be row_even } else { $odd = 'odd'; // should be col_odd $even = 'even'; // should be col_even }; if($alternate == $odd) { $alternate = $even; } else { $alternate = $odd; }; return $alternate; } /** * longestString() returns the length of the longest string past to it. * @peram string $new_string * @peram integer $longest_length length of the (previously) longest string passed to it. * @return integer representing the length of the longest string passed (updated if $new_string was longer than $longest_length) * * usage should look like this: $longest_length = longestString( $new_string , $longest_length ); * */ function longestString( $new_string , $longest_length ) { if($longest_length < strlen(trim(strip_tags($new_string)))) { $longest_length = strlen(trim(strip_tags($new_string))); }; return $longest_length; }; /** * getNotificationList() returns different options for notifications * * @param string $notificationcode - the currently selected one * * @return This string is returned containing formatted list of notification methods for current survey */ function getNotificationList($notificationcode) { $clang = Yii::app()->lang; $ntypes = array( "0"=>$clang->gT("No email notification"), "1"=>$clang->gT("Basic email notification"), "2"=>$clang->gT("Detailed email notification with result codes") ); if (!isset($ntypeselector)) {$ntypeselector="";} foreach($ntypes as $ntcode=>$ntdescription) { $ntypeselector .= " formatted list of groups to current survey */ function getGroupList($gid,$surveyid) { $clang = Yii::app()->lang; $groupselecter=""; $gid=sanitize_int($gid); $surveyid=sanitize_int($surveyid); if (!$surveyid) {$surveyid=returnGlobal('sid',true);} $s_lang = Survey::model()->findByPk($surveyid)->language; $gidquery = "SELECT gid, group_name FROM {{groups}} WHERE sid='{$surveyid}' AND language='{$s_lang}' ORDER BY group_order"; $gidresult = Yii::app()->db->createCommand($gidquery)->query(); //Checked foreach ($gidresult->readAll() as $gv) { $groupselecter .= "getConfig('scriptname')."?sid=$surveyid&gid=".$gv['gid']."'>".htmlspecialchars($gv['group_name'])."\n"; } if ($groupselecter) { if (!isset($gvexist)) {$groupselecter = "\n".$groupselecter;} else {$groupselecter .= "\n";} } return $groupselecter; } function getGroupList3($gid,$surveyid) { //$clang = Yii::app()->lang; $gid=sanitize_int($gid); $surveyid=sanitize_int($surveyid); if (!$surveyid) {$surveyid=returnGlobal('sid',true);} $groupselecter = ""; $s_lang = Survey::model()->findByPk($surveyid)->language; //$gidquery = "SELECT gid, group_name FROM ".db_table_name('groups')." WHERE sid=$surveyid AND language='{$s_lang}' ORDER BY group_order"; $gidresult = QuestionGroup::model()->findAllByAttributes(array('sid' => $surveyid, 'language' => $s_lang), array('order'=>'group_order')); foreach ($gidresult as $gv) { $gv = $gv->attributes; $groupselecter .= "".htmlspecialchars($gv['group_name'])."\n"; } return $groupselecter; } /** * put your comment there... * * @param mixed $gid * @param mixed $language */ function getGroupListLang($gid, $language, $surveyid) { $clang = Yii::app()->lang; $groupselecter=""; if (!$surveyid) {$surveyid=returnGlobal('sid',true);} $gidresult = QuestionGroup::model()->findAll(array('condition'=>'sid=:surveyid AND language=:language', 'order'=>'group_order', 'params'=>array(':surveyid'=>$surveyid,':language'=>$language))); //Checked) foreach ($gidresult as $gv) { $gv = $gv->attributes; $groupselecter .= "getController()->createUrl("/admin/survey/sa/view/surveyid/".$surveyid."/gid/".$gv['gid']); $groupselecter .= " value='{$link}'>"; if (strip_tags($gv['group_name'])) { $groupselecter .= htmlspecialchars(strip_tags($gv['group_name'])); } else { $groupselecter .= htmlspecialchars($gv['group_name']); } $groupselecter .= "\n"; } if ($groupselecter) { $link = Yii::app()->getController()->createUrl("/admin/survey/sa/view/surveyid/".$surveyid); if (!isset($gvexist)) {$groupselecter = "\n".$groupselecter;} else {$groupselecter .= "\n";} } return $groupselecter; } function getUserList($outputformat='fullinfoarray') { $clang = Yii::app()->lang; if (!empty(Yii::app()->session['loginID'])) { $myuid=sanitize_int(Yii::app()->session['loginID']); } $usercontrolSameGroupPolicy = Yii::app()->getConfig('usercontrolSameGroupPolicy'); if (!Permission::model()->hasGlobalPermission('superadmin','read') && isset($usercontrolSameGroupPolicy) && $usercontrolSameGroupPolicy == true) { if (isset($myuid)) { $sDatabaseType = Yii::app()->db->getDriverName(); if ($sDatabaseType=='mssql' || $sDatabaseType=="sqlsrv" || $sDatabaseType=="dblib") { $sSelectFields = 'users_name,uid,email,full_name,parent_id,CAST(password as varchar) as password'; } else { $sSelectFields = 'users_name,uid,email,full_name,parent_id,password'; } // List users from same group as me + all my childs // a subselect is used here because MSSQL does not like to group by text // also Postgres does like this one better $uquery = " SELECT {$sSelectFields} from {{users}} where uid in ( SELECT uid from {{user_in_groups}} where ugid in ( SELECT ugid from {{user_in_groups}} where uid={$myuid} ) ) UNION SELECT {$sSelectFields} from {{users}} v where v.parent_id={$myuid} UNION SELECT {$sSelectFields} from {{users}} v where uid={$myuid}"; } else { return array(); // Or die maybe } } else { $uquery = "SELECT * FROM {{users}} ORDER BY uid"; } $uresult = Yii::app()->db->createCommand($uquery)->query()->readAll(); //Checked if (count($uresult)==0) //user is not in a group and usercontrolSameGroupPolicy is activated - at least show his own userinfo { $uquery = "SELECT u.* FROM {{users}} AS u WHERE u.uid=".$myuid; $uresult = Yii::app()->db->createCommand($uquery)->query()->readAll();//Checked } $userlist = array(); $userlist[0] = "Reserved for logged in user"; foreach ($uresult as $srow) { if ($outputformat != 'onlyuidarray') { if ($srow['uid'] != Yii::app()->session['loginID']) { $userlist[] = array("user"=>$srow['users_name'], "uid"=>$srow['uid'], "email"=>$srow['email'], "password"=>$srow['password'], "full_name"=>$srow['full_name'], "parent_id"=>$srow['parent_id'] ); } else { $userlist[0] = array("user"=>$srow['users_name'], "uid"=>$srow['uid'], "email"=>$srow['email'], "password"=>$srow['password'], "full_name"=>$srow['full_name'], "parent_id"=>$srow['parent_id'] ); } } else { if ($srow['uid'] != Yii::app()->session['loginID']) { $userlist[] = $srow['uid']; } else { $userlist[0] = $srow['uid']; } } } return $userlist; } /** * Gets all survey infos in one big array including the language specific settings * * @param string $surveyid The survey ID * @param string $languagecode The language code - if not given the base language of the particular survey is used * @return array Returns array with survey info or false, if survey does not exist */ function getSurveyInfo($surveyid, $languagecode='') { static $staticSurveyInfo = array();// Use some static $surveyid=sanitize_int($surveyid); $languagecode=sanitize_languagecode($languagecode); $thissurvey=false; // Do job only if this survey exist if(!Survey::model()->findByPk($surveyid)) { return false; } // if no language code is set then get the base language one if ((!isset($languagecode) || $languagecode=='')) { $languagecode=Survey::model()->findByPk($surveyid)->language; } if(isset($staticSurveyInfo[$surveyid][$languagecode]) ) { $thissurvey=$staticSurveyInfo[$surveyid][$languagecode]; } else { $result = SurveyLanguageSetting::model()->with('survey')->findByPk(array('surveyls_survey_id' => $surveyid, 'surveyls_language' => $languagecode)); if (is_null($result)) { // When additional language was added, but not saved it does not exists // We should revert to the base language then $languagecode=Survey::model()->findByPk($surveyid)->language; $result = SurveyLanguageSetting::model()->with('survey')->findByPk(array('surveyls_survey_id' => $surveyid, 'surveyls_language' => $languagecode)); } if($result) { $thissurvey=array_merge($result->survey->attributes,$result->attributes); $thissurvey['name']=$thissurvey['surveyls_title']; $thissurvey['description']=$thissurvey['surveyls_description']; $thissurvey['welcome']=$thissurvey['surveyls_welcometext']; $thissurvey['templatedir']=$thissurvey['template']; $thissurvey['adminname']=$thissurvey['admin']; $thissurvey['tablename']='{{survey_'.$thissurvey['sid'] . '}}'; $thissurvey['urldescrip']=$thissurvey['surveyls_urldescription']; $thissurvey['url']=$thissurvey['surveyls_url']; $thissurvey['expiry']=$thissurvey['expires']; $thissurvey['email_invite_subj']=$thissurvey['surveyls_email_invite_subj']; $thissurvey['email_invite']=$thissurvey['surveyls_email_invite']; $thissurvey['email_remind_subj']=$thissurvey['surveyls_email_remind_subj']; $thissurvey['email_remind']=$thissurvey['surveyls_email_remind']; $thissurvey['email_confirm_subj']=$thissurvey['surveyls_email_confirm_subj']; $thissurvey['email_confirm']=$thissurvey['surveyls_email_confirm']; $thissurvey['email_register_subj']=$thissurvey['surveyls_email_register_subj']; $thissurvey['email_register']=$thissurvey['surveyls_email_register']; $thissurvey['attributedescriptions'] = $result->survey->tokenAttributes; $thissurvey['attributecaptions'] = $result->attributeCaptions; if (!isset($thissurvey['adminname'])) {$thissurvey['adminname']=Yii::app()->getConfig('siteadminemail');} if (!isset($thissurvey['adminemail'])) {$thissurvey['adminemail']=Yii::app()->getConfig('siteadminname');} if (!isset($thissurvey['urldescrip']) || $thissurvey['urldescrip'] == '' ) {$thissurvey['urldescrip']=$thissurvey['surveyls_url'];} $staticSurveyInfo[$surveyid][$languagecode]=$thissurvey; } } return $thissurvey; } /** * Returns the default email template texts as array * * @param mixed $oLanguage Required language translationb object * @param string $mode Escape mode for the translation function * @return array */ function templateDefaultTexts($oLanguage, $mode='html', $sNewlines='text'){ $aDefaultTexts=array( 'admin_detailed_notification_subject'=>$oLanguage->gT("Response submission for survey {SURVEYNAME} with results",$mode), 'admin_detailed_notification'=>$oLanguage->gT("Hello,\n\nA new response was submitted for your survey '{SURVEYNAME}'.\n\nClick the following link to reload the survey:\n{RELOADURL}\n\nClick the following link to see the individual response:\n{VIEWRESPONSEURL}\n\nClick the following link to edit the individual response:\n{EDITRESPONSEURL}\n\nView statistics by clicking here:\n{STATISTICSURL}\n\n\nThe following answers were given by the participant:\n{ANSWERTABLE}",$mode), 'admin_detailed_notification_css'=>'', 'admin_notification_subject'=>$oLanguage->gT("Response submission for survey {SURVEYNAME}",$mode), 'admin_notification'=>$oLanguage->gT("Hello,\n\nA new response was submitted for your survey '{SURVEYNAME}'.\n\nClick the following link to reload the survey:\n{RELOADURL}\n\nClick the following link to see the individual response:\n{VIEWRESPONSEURL}\n\nClick the following link to edit the individual response:\n{EDITRESPONSEURL}\n\nView statistics by clicking here:\n{STATISTICSURL}",$mode), 'confirmation_subject'=>$oLanguage->gT("Confirmation of your participation in our survey"), 'confirmation'=>$oLanguage->gT("Dear {FIRSTNAME},\n\nthis email is to confirm that you have completed the survey titled {SURVEYNAME} and your response has been saved. Thank you for participating.\n\nIf you have any further questions about this email, please contact {ADMINNAME} on {ADMINEMAIL}.\n\nSincerely,\n\n{ADMINNAME}",$mode), 'invitation_subject'=>$oLanguage->gT("Invitation to participate in a survey",$mode), 'invitation'=>$oLanguage->gT("Dear {FIRSTNAME},\n\nyou have been invited to participate in a survey.\n\nThe survey is titled:\n\"{SURVEYNAME}\"\n\n\"{SURVEYDESCRIPTION}\"\n\nTo participate, please click on the link below.\n\nSincerely,\n\n{ADMINNAME} ({ADMINEMAIL})\n\n----------------------------------------------\nClick here to do the survey:\n{SURVEYURL}",$mode)."\n\n".$oLanguage->gT("If you do not want to participate in this survey and don't want to receive any more invitations please click the following link:\n{OPTOUTURL}",$mode)."\n\n".$oLanguage->gT("If you are blacklisted but want to participate in this survey and want to receive invitations please click the following link:\n{OPTINURL}",$mode), 'reminder_subject'=>$oLanguage->gT("Reminder to participate in a survey",$mode), 'reminder'=>$oLanguage->gT("Dear {FIRSTNAME},\n\nRecently we invited you to participate in a survey.\n\nWe note that you have not yet completed the survey, and wish to remind you that the survey is still available should you wish to take part.\n\nThe survey is titled:\n\"{SURVEYNAME}\"\n\n\"{SURVEYDESCRIPTION}\"\n\nTo participate, please click on the link below.\n\nSincerely,\n\n{ADMINNAME} ({ADMINEMAIL})\n\n----------------------------------------------\nClick here to do the survey:\n{SURVEYURL}",$mode)."\n\n".$oLanguage->gT("If you do not want to participate in this survey and don't want to receive any more invitations please click the following link:\n{OPTOUTURL}",$mode), 'registration_subject'=>$oLanguage->gT("Survey registration confirmation",$mode), 'registration'=>$oLanguage->gT("Dear {FIRSTNAME},\n\nYou, or someone using your email address, have registered to participate in an online survey titled {SURVEYNAME}.\n\nTo complete this survey, click on the following URL:\n\n{SURVEYURL}\n\nIf you have any questions about this survey, or if you did not register to participate and believe this email is in error, please contact {ADMINNAME} at {ADMINEMAIL}.",$mode) ); if ($sNewlines=='html') { $aDefaultTexts=array_map('nl2br',$aDefaultTexts); } return $aDefaultTexts; } /** * Compares two elements from an array (passed by the usort function) * and returns -1, 0 or 1 depending on the result of the comparison of * the sort order of the group_order and question_order field * * @param mixed $a * @param mixed $b * @return int */ function groupOrderThenQuestionOrder($a, $b) { if (isset($a['group_order']) && isset($b['group_order'])) { $GroupResult = strnatcasecmp($a['group_order'], $b['group_order']); } else { $GroupResult = ""; } if ($GroupResult == 0) { $TitleResult = strnatcasecmp($a["question_order"], $b["question_order"]); return $TitleResult; } return $GroupResult; } function fixSortOrderAnswers($qid,$surveyid=null) //Function rewrites the sortorder for a group of answers { $qid=sanitize_int($qid); $baselang = Survey::model()->findByPk($surveyid)->language; Answer::model()->updateSortOrder($qid,$baselang); } /** * This function rewrites the sortorder for questions inside the named group * REMOVED the 2012-08-08 : replaced by Question::model()->updateQuestionOrder * @param integer $groupid the group id * @param integer $surveyid the survey id */ /** function fixSortOrderQuestions($groupid, $surveyid) //Function rewrites the sortorder for questions { $gid = sanitize_int($groupid); $surveyid = sanitize_int($surveyid); $baselang = Survey::model()->findByPk($surveyid)->language; $questions = Question::model()->findAllByAttributes(array('gid' => $gid, 'sid' => $surveyid, 'language' => $baselang)); $p = 0; foreach ($questions as $question) { $question->question_order = $p; $question->save(); $p++; } } */ function shiftOrderQuestions($sid,$gid,$shiftvalue) //Function shifts the sortorder for questions { $sid=sanitize_int($sid); $gid=sanitize_int($gid); $shiftvalue=sanitize_int($shiftvalue); $baselang = Survey::model()->findByPk($sid)->language; Question::model()->updateQuestionOrder($gid,$baselang,$shiftvalue); } function fixSortOrderGroups($surveyid) //Function rewrites the sortorder for groups { $baselang = Survey::model()->findByPk($surveyid)->language; QuestionGroup::model()->updateGroupOrder($surveyid,$baselang); } function fixMovedQuestionConditions($qid,$oldgid,$newgid) //Function rewrites the cfieldname for a question after group change { $surveyid = Yii::app()->getConfig('sid'); $qid=sanitize_int($qid); $oldgid=sanitize_int($oldgid); $newgid=sanitize_int($newgid); Condition::model()->updateCFieldName($surveyid,$qid,$oldgid,$newgid); // TMSW Condition->Relevance: Call LEM->ConvertConditionsToRelevance() when done } /** * This function returns POST/REQUEST vars, for some vars like SID and others they are also sanitized * * @param string $stringname * @param boolean $bRestrictToString */ function returnGlobal($stringname,$bRestrictToString=false) { $urlParam=Yii::app()->request->getParam($stringname); if(is_null($urlParam) && $aCookies=Yii::app()->request->getCookies() && $stringname!='sid') { if(isset($aCookies[$stringname])) { $urlParam = $aCookies[$stringname]; } } $bUrlParamIsArray=is_array($urlParam);// Needed to array map or if $bRestrictToString if (!is_null($urlParam) && $stringname!='' && (!$bUrlParamIsArray || !$bRestrictToString)) { if ($stringname == 'sid' || $stringname == "gid" || $stringname == "oldqid" || $stringname == "qid" || $stringname == "tid" || $stringname == "lid" || $stringname == "ugid"|| $stringname == "thisstep" || $stringname == "scenario" || $stringname == "cqid" || $stringname == "cid" || $stringname == "qaid" || $stringname == "scid" || $stringname == "loadsecurity") { if($bUrlParamIsArray){ return array_map("sanitize_int",$urlParam); }else{ return sanitize_int($urlParam); } } elseif ($stringname =="lang" || $stringname =="adminlang") { if($bUrlParamIsArray){ return array_map("sanitize_languagecode",$urlParam); }else{ return sanitize_languagecode($urlParam); } } elseif ($stringname =="htmleditormode" || $stringname =="subaction" || $stringname =="questionselectormode" || $stringname =="templateeditormode" ) { if($bUrlParamIsArray){ return array_map("sanitize_paranoid_string",$urlParam); }else{ return sanitize_paranoid_string($urlParam); } } elseif ( $stringname =="cquestions") { if($bUrlParamIsArray){ return array_map("sanitize_cquestions",$urlParam); }else{ return sanitize_cquestions($urlParam); } } return $urlParam; } else { return NULL; } } function sendCacheHeaders() { global $embedded; if ( $embedded ) return; if (!headers_sent()) { header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'); // this line lets IE7 run LimeSurvey in an iframe header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); header('Content-Type: text/html; charset=utf-8'); } } /** * @param type $iSurveyID The Survey ID * @param type $sFieldCode Field code of the particular field * @param type $sValue The stored response value * @param object $oLanguage Initialized limesurvey_lang object for the resulting response data * @return string */ function getExtendedAnswer($iSurveyID, $sFieldCode, $sValue, $oLanguage) { if ($sValue==null || $sValue=='') return ''; $sLanguage = $oLanguage->langcode; //Fieldcode used to determine question, $sValue used to match against answer code //Returns NULL if question type does not suit if (strpos($sFieldCode, "{$iSurveyID}X")===0) //Only check if it looks like a real fieldcode { $fieldmap = createFieldMap($iSurveyID,'short',false,false,$sLanguage); if (isset($fieldmap[$sFieldCode])) $fields = $fieldmap[$sFieldCode]; else return false; // If it is a comment field there is nothing to convert here if ($fields['aid']=='comment') return $sValue; //Find out the question type $this_type = $fields['type']; switch($this_type) { case 'D': if (trim($sValue)!='') { $qidattributes = getQuestionAttributeValues($fields['qid']); $dateformatdetails = getDateFormatDataForQID($qidattributes, $iSurveyID); $sValue=convertDateTimeFormat($sValue,"Y-m-d H:i:s",$dateformatdetails['phpdate']); } break; case 'N': if (trim($sValue)!='') { if(strpos($sValue,".")!==false) { $sValue=rtrim(rtrim($sValue,"0"),"."); } $qidattributes = getQuestionAttributeValues($fields['qid']); if($qidattributes['num_value_int_only']) { $sValue=number_format($sValue, 0, '', ''); } } break; case "L": case "!": case "O": case "^": case "I": case "R": $result = Answer::model()->getAnswerFromCode($fields['qid'],$sValue,$sLanguage); foreach($result as $row) { $this_answer=$row['answer']; } // while if ($sValue == "-oth-") { $this_answer=$oLanguage->gT("Other"); } break; case "M": case "J": case "P": switch($sValue) { case "Y": $this_answer=$oLanguage->gT("Yes"); break; } break; case "Y": switch($sValue) { case "Y": $this_answer=$oLanguage->gT("Yes"); break; case "N": $this_answer=$oLanguage->gT("No"); break; default: $this_answer=$oLanguage->gT("No answer"); } break; case "G": switch($sValue) { case "M": $this_answer=$oLanguage->gT("Male"); break; case "F": $this_answer=$oLanguage->gT("Female"); break; default: $this_answer=$oLanguage->gT("No answer"); } break; case "C": switch($sValue) { case "Y": $this_answer=$oLanguage->gT("Yes"); break; case "N": $this_answer=$oLanguage->gT("No"); break; case "U": $this_answer=$oLanguage->gT("Uncertain"); break; } break; case "E": switch($sValue) { case "I": $this_answer=$oLanguage->gT("Increase"); break; case "D": $this_answer=$oLanguage->gT("Decrease"); break; case "S": $this_answer=$oLanguage->gT("Same"); break; } break; case "F": case "H": case "1": $aConditions=array('qid' => $fields['qid'], 'code' => $sValue, 'language' => $sLanguage); if (isset($fields['scale_id'])) { $iScaleID=$fields['scale_id']; } else { $iScaleID=0; } $result = Answer::model()->getAnswerFromCode($fields['qid'],$sValue,$sLanguage,$iScaleID); foreach($result as $row) { $this_answer=$row['answer']; } // while if ($sValue == "-oth-") { $this_answer=$oLanguage->gT("Other"); } break; case "|": //File upload if (substr($sFieldCode, -9) != 'filecount') { //Show the filename, size, title and comment -- no link! $files = json_decode($sValue); $sValue = ''; if (is_array($files)) { foreach ($files as $file) { $sValue .= $file->name . ' (' . $file->size . 'KB) ' . strip_tags($file->title) . ' - ' . strip_tags($file->comment) . "
      "; } } } break; default: ; } // switch } switch($sFieldCode) { case 'submitdate': case 'startdate': case 'datestamp': if (trim($sValue)!='') { $dateformatdetails = getDateFormatDataForQID(null, $iSurveyID); $sValue=convertDateTimeFormat($sValue,"Y-m-d H:i:s",$dateformatdetails['phpdate'].' H:i:s'); } break; } if (isset($this_answer)) { return $this_answer." [$sValue]"; } else { return $sValue; } } /** * Validate an email address - also supports IDN email addresses * @returns True/false for valid/invalid * * @param mixed $sEmailAddress Email address to check */ function validateEmailAddress($sEmailAddress){ require_once(APPPATH.'third_party/idna-convert/idna_convert.class.php'); $oIdnConverter = new idna_convert(); $sEmailAddress=$oIdnConverter->encode($sEmailAddress); $bResult=filter_var($sEmailAddress, FILTER_VALIDATE_EMAIL); if ($bResult!==false) { return true; } return false; } function validateTemplateDir($sTemplateName) { $usertemplaterootdir = Yii::app()->getConfig('usertemplaterootdir'); $standardtemplaterootdir = Yii::app()->getConfig('standardtemplaterootdir'); $sDefaultTemplate = Yii::app()->getConfig('defaulttemplate'); if (is_dir("$usertemplaterootdir/{$sTemplateName}/")) { return $sTemplateName; } elseif (is_dir("$standardtemplaterootdir/{$sTemplateName}/")) { return $sTemplateName; } elseif (is_dir("$standardtemplaterootdir/{$sDefaultTemplate}/")) { return $sDefaultTemplate; } elseif (is_dir("$usertemplaterootdir/{$sDefaultTemplate}/")) { return $sDefaultTemplate; } else { return 'default'; } } /** *This functions generates a a summary containing the SGQA for questions of a survey, enriched with options per question * It can be used for the generation of statistics. Derived from Statistics_userController * @param int $iSurveyID Id of the Survey in question * @param array $aFilters an array which is the result of a query in Questions model * @param string $sLanguage * @return array The summary */ function createCompleteSGQA($iSurveyID,$aFilters,$sLanguage) { foreach ($aFilters as $flt) { Yii::app()->loadHelper("surveytranslator"); $myfield = "{$iSurveyID}X{$flt['gid']}X{$flt['qid']}"; $oSurvey = Survey::model()->findByPk($iSurveyID); $aAdditionalLanguages = array_filter(explode(" ", $oSurvey->additional_languages)); if (is_null($sLanguage)|| !in_array($sLanguage,$aAdditionalLanguages)) $sLanguage = $oSurvey->language; switch ($flt['type']) { case "K": // Multiple Numerical case "Q": // Multiple Short Text //get answers $result = Question::model()->getQuestionsForStatistics('title as code, question as answer', "parent_qid=$flt[qid] AND language = '{$sLanguage}'", 'question_order'); //go through all the (multiple) answers foreach($result as $row) { $myfield2=$flt['type'].$myfield.reset($row); $allfields[] = $myfield2; } break; case "A": // ARRAY OF 5 POINT CHOICE QUESTIONS case "B": // ARRAY OF 10 POINT CHOICE QUESTIONS case "C": // ARRAY OF YES\No\$clang->gT("Uncertain") QUESTIONS case "E": // ARRAY OF Increase/Same/Decrease QUESTIONS case "F": // FlEXIBLE ARRAY case "H": // ARRAY (By Column) //get answers $result = Question::model()->getQuestionsForStatistics('title, question', "parent_qid=$flt[qid] AND language = '{$sLanguage}'", 'question_order'); //go through all the (multiple) answers foreach($result as $row) { $myfield2 = $myfield.reset($row); $allfields[]=$myfield2; } break; // all "free text" types (T, U, S) get the same prefix ("T") case "T": // Long free text case "U": // Huge free text case "S": // Short free text $myfield="T$myfield"; $allfields[] = $myfield; break; case ";": //ARRAY (Multi Flex) (Text) case ":": //ARRAY (Multi Flex) (Numbers) $result = Question::model()->getQuestionsForStatistics('title, question', "parent_qid=$flt[qid] AND language = '{$sLanguage}' AND scale_id = 0", 'question_order'); foreach($result as $row) { $fresult = Question::model()->getQuestionsForStatistics('title, question', "parent_qid=$flt[qid] AND language = '{$sLanguage}' AND scale_id = 1", 'question_order'); foreach($fresult as $frow) { $myfield2 = $myfield . reset($row) . "_" . $frow['title']; $allfields[]=$myfield2; } } break; case "R": //RANKING //get some answers $result = Answer::model()->getQuestionsForStatistics('code, answer', "qid=$flt[qid] AND language = '{$sLanguage}'", 'sortorder, answer'); //get number of answers //loop through all answers. if there are 3 items to rate there will be 3 statistics $i=0; foreach($result as $row) { $i++; $myfield2 = "R" . $myfield . $i . "-" . strlen($i); $allfields[]=$myfield2; } break; //Boilerplate questions are only used to put some text between other questions -> no analysis needed case "X": //This is a boilerplate question and it has no business in this script break; case "1": // MULTI SCALE //get answers $result = Question::model()->getQuestionsForStatistics('title, question', "parent_qid=$flt[qid] AND language = '{$sLanguage}'", 'question_order'); //loop through answers foreach($result as $row) { //----------------- LABEL 1 --------------------- $myfield2 = $myfield . reset($row)."#0"; $allfields[]=$myfield2; //----------------- LABEL 2 --------------------- $myfield2 = $myfield . reset($row)."#1"; $allfields[]=$myfield2; } //end WHILE -> loop through all answers break; case "P": //P - Multiple choice with comments case "M": //M - Multiple choice case "N": //N - Numerical input case "D": //D - Date $myfield2 = $flt['type'].$myfield; $allfields[]=$myfield2; break; default: //Default settings $allfields[] = $myfield; break; } //end switch } return $allfields; } /** * This function generates an array containing the fieldcode, and matching data in the same order as the activate script * * @param string $surveyid The Survey ID * @param mixed $style 'short' (default) or 'full' - full creates extra information like default values * @param mixed $force_refresh - Forces to really refresh the array, not just take the session copy * @param int $questionid Limit to a certain qid only (for question preview) - default is false * @param string $sQuestionLanguage The language to use * @return array */ function createFieldMap($surveyid, $style='short', $force_refresh=false, $questionid=false, $sLanguage) { global $aDuplicateQIDs; $sLanguage = sanitize_languagecode($sLanguage); $surveyid = sanitize_int($surveyid); //checks to see if fieldmap has already been built for this page. if (isset(Yii::app()->session['fieldmap-' . $surveyid . $sLanguage]) && !$force_refresh && $questionid == false) { return Yii::app()->session['fieldmap-' . $surveyid . $sLanguage]; } $clang = new Limesurvey_lang($sLanguage); $fieldmap["id"]=array("fieldname"=>"id", 'sid'=>$surveyid, 'type'=>"id", "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["id"]['title']=""; $fieldmap["id"]['question']=$clang->gT("Response ID"); $fieldmap["id"]['group_name']=""; } $fieldmap["submitdate"]=array("fieldname"=>"submitdate", 'type'=>"submitdate", 'sid'=>$surveyid, "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["submitdate"]['title']=""; $fieldmap["submitdate"]['question']=$clang->gT("Date submitted"); $fieldmap["submitdate"]['group_name']=""; } $fieldmap["lastpage"]=array("fieldname"=>"lastpage", 'sid'=>$surveyid, 'type'=>"lastpage", "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["lastpage"]['title']=""; $fieldmap["lastpage"]['question']=$clang->gT("Last page"); $fieldmap["lastpage"]['group_name']=""; } $fieldmap["startlanguage"]=array("fieldname"=>"startlanguage", 'sid'=>$surveyid, 'type'=>"startlanguage", "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["startlanguage"]['title']=""; $fieldmap["startlanguage"]['question']=$clang->gT("Start language"); $fieldmap["startlanguage"]['group_name']=""; } // Select which question IDs have default values $_aDefaultValues = DefaultValue::model()->with(array('question' => array('condition' => 'question.sid=' . $surveyid)))->findAll(); $aDefaultValues = array(); foreach ($_aDefaultValues as $k => $v) $aDefaultValues[] = $v->qid; //Check for any additional fields for this survey and create necessary fields (token and datestamp and ipaddr) $prow = Survey::model()->findByPk($surveyid)->getAttributes(); //Checked if ($prow['anonymized'] == "N" && Survey::model()->hasTokens($surveyid)) { $fieldmap["token"]=array("fieldname"=>"token", 'sid'=>$surveyid, 'type'=>"token", "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["token"]['title']=""; $fieldmap["token"]['question']=$clang->gT("Token"); $fieldmap["token"]['group_name']=""; } } if ($prow['datestamp'] == "Y") { $fieldmap["startdate"]=array("fieldname"=>"startdate", 'type'=>"startdate", 'sid'=>$surveyid, "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["startdate"]['title']=""; $fieldmap["startdate"]['question']=$clang->gT("Date started"); $fieldmap["startdate"]['group_name']=""; } $fieldmap["datestamp"]=array("fieldname"=>"datestamp", 'type'=>"datestamp", 'sid'=>$surveyid, "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["datestamp"]['title']=""; $fieldmap["datestamp"]['question']=$clang->gT("Date last action"); $fieldmap["datestamp"]['group_name']=""; } } if ($prow['ipaddr'] == "Y") { $fieldmap["ipaddr"]=array("fieldname"=>"ipaddr", 'type'=>"ipaddress", 'sid'=>$surveyid, "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["ipaddr"]['title']=""; $fieldmap["ipaddr"]['question']=$clang->gT("IP address"); $fieldmap["ipaddr"]['group_name']=""; } } // Add 'refurl' to fieldmap. if ($prow['refurl'] == "Y") { $fieldmap["refurl"]=array("fieldname"=>"refurl", 'type'=>"url", 'sid'=>$surveyid, "gid"=>"", "qid"=>"", "aid"=>""); if ($style == "full") { $fieldmap["refurl"]['title']=""; $fieldmap["refurl"]['question']=$clang->gT("Referrer URL"); $fieldmap["refurl"]['group_name']=""; } } // Collect all default values once so don't need separate query for each question with defaults // First collect language specific defaults $defaultsQuery = "SELECT a.qid, a.sqid, a.scale_id, a.specialtype, a.defaultvalue" . " FROM {{defaultvalues}} as a, {{questions}} as b" . " WHERE a.qid = b.qid" . " AND a.language = b.language" . " AND a.language = '{$sLanguage}'" . " AND b.same_default=0" . " AND b.sid = ".$surveyid; $defaultResults = Yii::app()->db->createCommand($defaultsQuery)->queryAll(); $defaultValues = array(); // indexed by question then subquestion foreach($defaultResults as $dv) { if ($dv['specialtype'] != '') { $sq = $dv['specialtype']; } else { $sq = $dv['sqid']; } $defaultValues[$dv['qid'].'~'.$sq] = $dv['defaultvalue']; } // Now overwrite language-specific defaults (if any) base language values for each question that uses same_defaults=1 $baseLanguage = getBaseLanguageFromSurveyID($surveyid); $defaultsQuery = "SELECT a.qid, a.sqid, a.scale_id, a.specialtype, a.defaultvalue" . " FROM {{defaultvalues}} as a, {{questions}} as b" . " WHERE a.qid = b.qid" . " AND a.language = b.language" . " AND a.language = '{$baseLanguage}'" . " AND b.same_default=1" . " AND b.sid = ".$surveyid; $defaultResults = Yii::app()->db->createCommand($defaultsQuery)->queryAll(); foreach($defaultResults as $dv) { if ($dv['specialtype'] != '') { $sq = $dv['specialtype']; } else { $sq = $dv['sqid']; } $defaultValues[$dv['qid'].'~'.$sq] = $dv['defaultvalue']; } $qtypes=getQuestionTypeList('','array'); $aquery = "SELECT * " ." FROM {{questions}} as questions, {{groups}} as groups" ." WHERE questions.gid=groups.gid AND " ." questions.sid=$surveyid AND " ." questions.language='{$sLanguage}' AND " ." questions.parent_qid=0 AND " ." groups.language='{$sLanguage}' "; if ($questionid!==false) { $aquery.=" and questions.qid={$questionid} "; } $aquery.=" ORDER BY group_order, question_order"; $aresult = Yii::app()->db->createCommand($aquery)->queryAll(); $questionSeq=-1; // this is incremental question sequence across all groups $groupSeq=-1; $_groupOrder=-1; foreach ($aresult as $arow) //With each question, create the appropriate field(s)) { ++$questionSeq; // fix fact taht group_order may have gaps if ($_groupOrder != $arow['group_order']) { $_groupOrder = $arow['group_order']; ++$groupSeq; } // Condition indicators are obsolete with EM. However, they are so tightly coupled into LS code that easider to just set values to 'N' for now and refactor later. $conditions = 'N'; $usedinconditions = 'N'; // Field identifier // GXQXSXA // G=Group Q=Question S=Subquestion A=Answer Option // If S or A don't exist then set it to 0 // Implicit (subqestion intermal to a question type ) or explicit qubquestions/answer count starts at 1 // Types "L", "!", "O", "D", "G", "N", "X", "Y", "5", "S", "T", "U" $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}"; if ($qtypes[$arow['type']]['subquestions']==0 && $arow['type'] != "R" && $arow['type'] != "|") { if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>"{$arow['type']}", 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>""); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; if (isset($defaultValues[$arow['qid'].'~0'])) { $fieldmap[$fieldname]['defaultvalue'] = $defaultValues[$arow['qid'].'~0']; } } switch($arow['type']) { case "L": //RADIO LIST case "!": //DROPDOWN LIST if ($arow['other'] == "Y") { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}other"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>"other"); // dgk bug fix line above. aid should be set to "other" for export to append to the field name in the header line. if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$clang->gT("Other"); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; if (isset($defaultValues[$arow['qid'].'~other'])) { $fieldmap[$fieldname]['defaultvalue'] = $defaultValues[$arow['qid'].'~other']; } } } break; case "O": //DROPDOWN LIST WITH COMMENT $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}comment"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>"comment"); // dgk bug fix line below. aid should be set to "comment" for export to append to the field name in the header line. Also needed set the type element correctly. if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$clang->gT("Comment"); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } break; } } // For Multi flexi question types elseif ($qtypes[$arow['type']]['subquestions']==2 && $qtypes[$arow['type']]['answerscales']==0) { //MULTI FLEXI $abrows = getSubQuestions($surveyid,$arow['qid'],$sLanguage); //Now first process scale=1 $answerset=array(); $answerList = array(); foreach ($abrows as $key=>$abrow) { if($abrow['scale_id']==1) { $answerset[]=$abrow; $answerList[] = array( 'code'=>$abrow['title'], 'answer'=>$abrow['question'], ); unset($abrows[$key]); } } reset($abrows); foreach ($abrows as $abrow) { foreach($answerset as $answer) { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}{$abrow['title']}_{$answer['title']}"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>$abrow['title']."_".$answer['title'], "sqid"=>$abrow['qid']); if ($abrow['other']=="Y") {$alsoother="Y";} if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion1']=$abrow['question']; $fieldmap[$fieldname]['subquestion2']=$answer['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; $fieldmap[$fieldname]['preg']=$arow['preg']; $fieldmap[$fieldname]['answerList']=$answerList; } } } unset($answerset); } elseif ($arow['type'] == "1") { $abrows = getSubQuestions($surveyid,$arow['qid'],$sLanguage); foreach ($abrows as $abrow) { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}{$abrow['title']}#0"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>$abrow['title'], "scale_id"=>0); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$abrow['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['scale']=$clang->gT('Scale 1'); $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}{$abrow['title']}#1"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>$abrow['title'], "scale_id"=>1); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$abrow['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['scale']=$clang->gT('Scale 2'); $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } } } elseif ($arow['type'] == "R") { //MULTI ENTRY $data = Answer::model()->findAllByAttributes(array('qid' => $arow['qid'], 'language' => $sLanguage)); $data = count($data); $slots=$data; for ($i=1; $i<=$slots; $i++) { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}$i"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>$i); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=sprintf($clang->gT('Rank %s'),$i); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } } } elseif ($arow['type'] == "|") { $qidattributes= getQuestionAttributeValues($arow['qid']); $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}"; $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>'' ); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['max_files']=$qidattributes['max_num_of_files']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}"."_filecount"; $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>"filecount" ); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']="filecount - ".$arow['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } } else // Question types with subquestions and one answer per subquestion (M/A/B/C/E/F/H/P) { //MULTI ENTRY $abrows = getSubQuestions($surveyid,$arow['qid'],$sLanguage); foreach ($abrows as $abrow) { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}{$abrow['title']}"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, 'gid'=>$arow['gid'], 'qid'=>$arow['qid'], 'aid'=>$abrow['title'], 'sqid'=>$abrow['qid']); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$abrow['question']; $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; $fieldmap[$fieldname]['preg']=$arow['preg']; if (isset($defaultValues[$arow['qid'].'~'.$abrow['qid']])) { $fieldmap[$fieldname]['defaultvalue'] = $defaultValues[$arow['qid'].'~'.$abrow['qid']]; } } if ($arow['type'] == "P") { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}{$abrow['title']}comment"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>$abrow['title']."comment"); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$clang->gT('Comment'); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; } } } if ($arow['other']=="Y" && ($arow['type']=="M" || $arow['type']=="P")) { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}other"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>"other"); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$clang->gT('Other'); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; $fieldmap[$fieldname]['other']=$arow['other']; } if ($arow['type']=="P") { $fieldname="{$arow['sid']}X{$arow['gid']}X{$arow['qid']}othercomment"; if (isset($fieldmap[$fieldname])) $aDuplicateQIDs[$arow['qid']]=array('fieldname'=>$fieldname,'question'=>$arow['question'],'gid'=>$arow['gid']); $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>$arow['type'], 'sid'=>$surveyid, "gid"=>$arow['gid'], "qid"=>$arow['qid'], "aid"=>"othercomment"); if ($style == "full") { $fieldmap[$fieldname]['title']=$arow['title']; $fieldmap[$fieldname]['question']=$arow['question']; $fieldmap[$fieldname]['subquestion']=$clang->gT('Other comment'); $fieldmap[$fieldname]['group_name']=$arow['group_name']; $fieldmap[$fieldname]['mandatory']=$arow['mandatory']; $fieldmap[$fieldname]['hasconditions']=$conditions; $fieldmap[$fieldname]['usedinconditions']=$usedinconditions; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; $fieldmap[$fieldname]['other']=$arow['other']; } } } } if (isset($fieldmap[$fieldname])) { $fieldmap[$fieldname]['relevance']=$arow['relevance']; $fieldmap[$fieldname]['grelevance']=$arow['grelevance']; $fieldmap[$fieldname]['questionSeq']=$questionSeq; $fieldmap[$fieldname]['groupSeq']=$groupSeq; $fieldmap[$fieldname]['preg']=$arow['preg']; $fieldmap[$fieldname]['other']=$arow['other']; $fieldmap[$fieldname]['help']=$arow['help']; } else { --$questionSeq; // didn't generate a valid $fieldmap entry, so decrement the question counter to ensure they are sequential } } if (isset($fieldmap)) { if ($questionid == false) { // If the fieldmap was randomized, the master will contain the proper order. Copy that fieldmap with the new language settings. if (isset(Yii::app()->session['survey_'.$surveyid]['fieldmap-' . $surveyid . '-randMaster'])) { $masterFieldmap = Yii::app()->session['survey_'.$surveyid]['fieldmap-' . $surveyid . '-randMaster']; $mfieldmap = Yii::app()->session['survey_'.$surveyid][$masterFieldmap]; foreach ($mfieldmap as $fieldname => $mf) { if (isset($fieldmap[$fieldname])) { // This array holds the keys of translatable attributes $translatable = array_flip(array('question', 'subquestion', 'subquestion1', 'subquestion2', 'group_name', 'answerList', 'defaultValue', 'help')); // We take all translatable attributes from the new fieldmap $newText = array_intersect_key($fieldmap[$fieldname], $translatable); // And merge them with the other values from the random fieldmap like questionSeq, groupSeq etc. $mf = $newText + $mf; } $mfieldmap[$fieldname] = $mf; } $fieldmap = $mfieldmap; } Yii::app()->session['fieldmap-' . $surveyid . $sLanguage]=$fieldmap; } return $fieldmap; } } /** * Returns true if the given survey has a File Upload Question Type * @param $surveyid The survey ID * @return bool */ function hasFileUploadQuestion($iSurveyID) { $iCount = Question::model()->count( "sid=:surveyid AND parent_qid=0 AND type='|'", array(':surveyid' => $iSurveyID)); return $iCount>0 ; } /** * This function generates an array containing the fieldcode, and matching data in the same order as the activate script * * @param string $surveyid The Survey ID * @param mixed $style 'short' (default) or 'full' - full creates extra information like default values * @param mixed $force_refresh - Forces to really refresh the array, not just take the session copy * @param int $questionid Limit to a certain qid only (for question preview) - default is false * @param string $sQuestionLanguage The language to use * @return array */ function createTimingsFieldMap($surveyid, $style='full', $force_refresh=false, $questionid=false, $sQuestionLanguage=null) { global $aDuplicateQIDs; static $timingsFieldMap; $sLanguage = sanitize_languagecode($sQuestionLanguage); $surveyid = sanitize_int($surveyid); $clang = new Limesurvey_lang($sLanguage); //checks to see if fieldmap has already been built for this page. if (isset($timingsFieldMap[$surveyid][$style][$clang->langcode]) && $force_refresh==false) { return $timingsFieldMap[$surveyid][$style][$clang->langcode]; } //do something $fields = createFieldMap($surveyid, $style, $force_refresh, $questionid, $sQuestionLanguage); $fieldmap['interviewtime']=array('fieldname'=>'interviewtime','type'=>'interview_time','sid'=>$surveyid, 'gid'=>'', 'qid'=>'', 'aid'=>'', 'question'=>$clang->gT('Total time'), 'title'=>'interviewtime'); foreach ($fields as $field) { if (!empty($field['gid'])) { // field for time spent on page $fieldname="{$field['sid']}X{$field['gid']}time"; if (!isset($fieldmap[$fieldname])) { $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>"page_time", 'sid'=>$surveyid, "gid"=>$field['gid'], "group_name"=>$field['group_name'], "qid"=>'', 'aid'=>'', 'title'=>'groupTime'.$field['gid'], 'question'=>$clang->gT('Group time').": ".$field['group_name']); } // field for time spent on answering a question $fieldname="{$field['sid']}X{$field['gid']}X{$field['qid']}time"; if (!isset($fieldmap[$fieldname])) { $fieldmap[$fieldname]=array("fieldname"=>$fieldname, 'type'=>"answer_time", 'sid'=>$surveyid, "gid"=>$field['gid'], "group_name"=>$field['group_name'], "qid"=>$field['qid'], 'aid'=>'', "title"=>$field['title'].'Time', "question"=>$clang->gT('Question time').": ".$field['title']); } } } $timingsFieldMap[$surveyid][$style][$clang->langcode] = $fieldmap; return $timingsFieldMap[$surveyid][$style][$clang->langcode]; } /** * put your comment there... * * @param mixed $needle * @param mixed $haystack * @param mixed $keyname * @param mixed $maxanswers */ function arraySearchByKey($needle, $haystack, $keyname, $maxanswers="") { $output=array(); foreach($haystack as $hay) { if (array_key_exists($keyname, $hay)) { if ($hay[$keyname] == $needle) { if ($maxanswers == 1) { return $hay; } else { $output[]=$hay; } } } } return $output; } /** * set the rights of a user and his children * * @param int $uid the user id * @param mixed $rights rights array */ function setuserpermissions($uid, $rights) { $uid=sanitize_int($uid); $updates = "create_survey=".$rights['create_survey'] . ", create_user=".$rights['create_user'] . ", participant_panel=".$rights['participant_panel'] . ", delete_user=".$rights['delete_user'] . ", superadmin=".$rights['superadmin'] . ", configurator=".$rights['configurator'] . ", manage_template=".$rights['manage_template'] . ", manage_label=".$rights['manage_label']; $uquery = "UPDATE {{users}} SET ".$updates." WHERE uid = ".$uid; return dbSelectLimitAssoc($uquery); //Checked } /** * This function returns a count of the number of saved responses to a survey * * @param mixed $surveyid Survey ID */ function getSavedCount($surveyid) { $surveyid=(int)$surveyid; return SavedControl::model()->getCountOfAll($surveyid); } /** * Returns the base language from a survey id * * @deprecated Use Survey::model()->findByPk($surveyid)->language * @param int $surveyid * @return string */ function getBaseLanguageFromSurveyID($surveyid) { return Survey::model()->findByPk($surveyid)->language; } function buildLabelSetCheckSumArray() { // BUILD CHECKSUMS FOR ALL EXISTING LABEL SETS /**$query = "SELECT lid FROM ".db_table_name('labelsets')." ORDER BY lid"; */ $result = LabelSet::model()->getLID();//($query) or safeDie("safe_died collecting labelset ids
      $query
      "); //Checked) $csarray=array(); foreach($result as $row) { $thisset=""; $query2 = "SELECT code, title, sortorder, language, assessment_value FROM {{labels}} WHERE lid={$row['lid']} ORDER BY language, sortorder, code"; $result2 = Yii::app()->db->createCommand($query2)->query(); foreach ($result2->readAll() as $row2) { $thisset .= implode('.', $row2); } // while $csarray[$row['lid']]=dechex(crc32($thisset)*1); } return $csarray; } /** * Returns a flat array with all question attributes for the question only (and the qid we gave it)! * @param $iQID The question ID * @return array$bOrderByNative=>value, attribute=>value} or false if the question ID does not exist (anymore) */ function getQuestionAttributeValues($iQID) { return QuestionAttribute::model()->getQuestionAttributes($iQID); # static $cache = array(); # static $availableattributesarr = null; # $iQID = sanitize_int($iQID); # if (isset($cache[$iQID])) { # return $cache[$iQID]; # } # $oQuestion = Question::model()->find("qid=:qid",array('qid'=>$iQuestionID)); // Maybe take parent_qid attribute before this qid attribute # if (!$oQuestion) // Question was deleted while running the survey # { # $cache[$iQID] = false; # return false; # } # else # { # $type = $oQuestion->type; # $surveyid = $oQuestion->type; # $row = $oQuestion->getAttributes(); # } # $type = $row['type']; # $surveyid = $row['sid']; # $aLanguages = array_merge((array)Survey::model()->findByPk($surveyid)->language, Survey::model()->findByPk($surveyid)->additionalLanguages); //Now read available attributes, make sure we do this only once per request to save //processing cycles and memory # if (is_null($availableattributesarr)) $availableattributesarr = questionAttributes(); # if (isset($availableattributesarr[$type])) # { # $aAvailableAttributes = $availableattributesarr[$type]; # } # else # { # $cache[$iQID] = array(); # return array(); # } # $aResultAttributes = array(); # foreach($aAvailableAttributes as $attribute){ # if ($attribute['i18n']) # { # foreach ($aLanguages as $sLanguage) # { # $aResultAttributes[$attribute['name']][$sLanguage]=$attribute['default']; # } # } # else # { # $aResultAttributes[$attribute['name']]=$attribute['default']; # } # } # $result = QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQID)); # foreach ($result as $row) # { # $row = $row->attributes; # if (!isset($aAvailableAttributes[$row['attribute']])) # { # continue; // Sort out attributes not belonging to this question # } # if (!($aAvailableAttributes[$row['attribute']]['i18n'])) # { # $aResultAttributes[$row['attribute']]=$row['value']; # } # elseif(!empty($row['language'])) # { # $aResultAttributes[$row['attribute']][$row['language']]=$row['value']; # } # } # $cache[$iQID] = $aResultAttributes; # return $aResultAttributes; } /** * * Returns the questionAttribtue value set or '' if not set * @author: lemeur * @param $questionAttributeArray * @param $attributeName * @param $language string Optional: The language if the particualr attributes is localizable * @return string */ function getQuestionAttributeValue($questionAttributeArray, $attributeName, $language='') { if ($language=='' && isset($questionAttributeArray[$attributeName])) { return $questionAttributeArray[$attributeName]; } elseif ($language!='' && isset($questionAttributeArray[$attributeName][$language])) { return $questionAttributeArray[$attributeName][$language]; } else { return ''; } } /** * Returns array of question type chars with attributes * * @param mixed $returnByName If set to true the array will be by attribute name */ function questionAttributes($returnByName=false) { // Use some static static $qattributes=false; static $qat=false; $clang = Yii::app()->lang; if (!$qattributes) { //For each question attribute include a key: // name - the display name // types - a string with one character representing each question typy to which the attribute applies // help - a short explanation // If you insert a new attribute please do it in correct alphabetical order! // Please also list the new attribute in the function &TSVSurveyExport($sid) in em_manager_helper.php, // so your new attribute will not be "forgotten" when the survey is exported to Excel/CSV-format! $qattributes["alphasort"]=array( "types"=>"!LOWZ", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT("Sort the answer options alphabetically"), "caption"=>$clang->gT('Sort answers alphabetically')); $qattributes["answer_width"]=array( "types"=>"ABCEF1:;", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'integer', 'min'=>'1', 'max'=>'100', "help"=>$clang->gT('Set the percentage width of the (sub-)question column (1-100)'), "caption"=>$clang->gT('(Sub-)question width')); $qattributes["repeat_headings"]=array( "types"=>"F:1;", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'integer', 'default'=>'', "help"=>$clang->gT('Repeat headings every X subquestions (Set to 0 to deactivate heading repeat, deactivate minimum repeat headings from config).'), "caption"=>$clang->gT('Repeat headers')); $qattributes["array_filter"]=array( "types"=>"1ABCEF:;MPLKQR", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT("Enter the code(s) of Multiple choice question(s) (separated by semicolons) to only show the matching answer options in this question."), "caption"=>$clang->gT('Array filter')); $qattributes["array_filter_exclude"]=array( "types"=>"1ABCEF:;MPLKQR", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT("Enter the code(s) of Multiple choice question(s) (separated by semicolons) to exclude the matching answer options in this question."), "caption"=>$clang->gT('Array filter exclusion')); $qattributes["array_filter_style"]=array( "types"=>"1ABCEF:;MPLKQR", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Hidden'), 1=>$clang->gT('Disabled')), 'default'=>0, "help"=>$clang->gT("Specify how array-filtered sub-questions should be displayed"), "caption"=>$clang->gT('Array filter style')); $qattributes["assessment_value"]=array( "types"=>"MP", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'default'=>'1', 'inputtype'=>'integer', "help"=>$clang->gT("If one of the subquestions is marked then for each marked subquestion this value is added as assessment."), "caption"=>$clang->gT('Assessment value')); $qattributes["category_separator"]=array( "types"=>"!", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Category separator'), "caption"=>$clang->gT('Category separator')); $qattributes["code_filter"]=array( "types"=>"WZ", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Filter the available answers by this value'), "caption"=>$clang->gT('Code filter')); $qattributes["commented_checkbox"]=array( "types"=>"P", 'category'=>$clang->gT('Logic'), 'sortorder'=>110, 'inputtype'=>'singleselect', 'options'=>array( "allways"=>$clang->gT('No control on checkbox'), "checked"=>$clang->gT('Checkbox is checked'), "unchecked"=>$clang->gT('Checkbox is unchecked'), ), 'default' => "checked", 'help'=>$clang->gT('Choose when user can add a comment'), 'caption'=>$clang->gT('Comment only when')); $qattributes["commented_checkbox_auto"]=array( "types"=>"P", 'category'=>$clang->gT('Logic'), 'sortorder'=>111, 'inputtype'=>'singleselect', 'options'=>array( "0"=>$clang->gT('No'), "1"=>$clang->gT('Yes'), ), 'default' => "1", 'help'=>$clang->gT('Use javascript function to remove text and uncheck checkbox (or use Expression Manager only).'), 'caption'=>$clang->gT('Remove text or uncheck checkbox automatically')); $qattributes["display_columns"]=array( "types"=>"LM", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'integer', 'default'=>'1', 'min'=>'1', 'max'=>'100', "help"=>$clang->gT('The answer options will be distributed across the number of columns set here'), "caption"=>$clang->gT('Display columns')); $qattributes["display_rows"]=array( "types"=>"QSTU", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('How many rows to display'), "caption"=>$clang->gT('Display rows')); $qattributes["dropdown_dates"]=array( "types"=>"D", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Use accessible dropdown boxes instead of calendar popup'), "caption"=>$clang->gT('Display dropdown boxes')); $qattributes["date_min"]=array( "types"=>"D", 'category'=>$clang->gT('Display'), 'sortorder'=>110, 'inputtype'=>'text', "help"=>$clang->gT('Minimum date selectable in calendar (YYYY-MM-DD). Only the year is used if dropdown boxes are selected.'), "caption"=>$clang->gT('Minimum date')); $qattributes["date_max"]=array( "types"=>"D", 'category'=>$clang->gT('Display'), 'sortorder'=>111, 'inputtype'=>'text', "help"=>$clang->gT('Maximum date selectable in calendar (YYYY-MM-DD). Only the year is used if dropdown boxes are selected.'), "caption"=>$clang->gT('Maximum date')); $qattributes["dropdown_prepostfix"]=array( "types"=>"1", 'category'=>$clang->gT('Display'), 'sortorder'=>112, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT('Prefix|Suffix for dropdown lists'), "caption"=>$clang->gT('Dropdown prefix/suffix')); $qattributes["dropdown_separators"]=array( "types"=>"1", 'category'=>$clang->gT('Display'), 'sortorder'=>120, 'inputtype'=>'text', "help"=>$clang->gT('Text shown on each subquestion row between both scales in dropdown mode'), "caption"=>$clang->gT('Dropdown separator')); $qattributes["dualscale_headerA"]=array( "types"=>"1", 'category'=>$clang->gT('Display'), 'sortorder'=>110, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT('Enter a header text for the first scale'), "caption"=>$clang->gT('Header for first scale')); $qattributes["dualscale_headerB"]=array( "types"=>"1", 'category'=>$clang->gT('Display'), 'sortorder'=>111, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT('Enter a header text for the second scale'), "caption"=>$clang->gT('Header for second scale')); $qattributes["equals_num_value"]=array( "types"=>"K", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Multiple numeric inputs sum must equal this value'), "caption"=>$clang->gT('Equals sum value')); $qattributes["em_validation_q"]=array( "types"=>":;ABCDEFKMNPQRSTU", 'category'=>$clang->gT('Logic'), 'sortorder'=>200, 'inputtype'=>'textarea', "help"=>$clang->gT('Enter a boolean equation to validate the whole question.'), "caption"=>$clang->gT('Question validation equation')); $qattributes["em_validation_q_tip"]=array( "types"=>":;ABCDEFKMNPQRSTU", 'category'=>$clang->gT('Logic'), 'sortorder'=>210, 'inputtype'=>'textarea', "help"=>$clang->gT('This is a hint text that will be shown to the participant describing the question validation equation.'), "caption"=>$clang->gT('Question validation tip')); $qattributes["em_validation_sq"]=array( "types"=>";:KQSTUN", 'category'=>$clang->gT('Logic'), 'sortorder'=>220, 'inputtype'=>'textarea', "help"=>$clang->gT('Enter a boolean equation to validate each sub-question.'), "caption"=>$clang->gT('Sub-question validation equation')); $qattributes["em_validation_sq_tip"]=array( "types"=>";:KQSTUN", 'category'=>$clang->gT('Logic'), 'sortorder'=>230, 'inputtype'=>'textarea', "help"=>$clang->gT('This is a tip shown to the participant describing the sub-question validation equation.'), "caption"=>$clang->gT('Sub-question validation tip')); $qattributes["exclude_all_others"]=array( "types"=>":ABCEFMPKQ", 'category'=>$clang->gT('Logic'), 'sortorder'=>130, 'inputtype'=>'text', "help"=>$clang->gT('Excludes all other options if a certain answer is selected - just enter the answer code(s) separated with a semikolon.'), "caption"=>$clang->gT('Exclusive option')); $qattributes["exclude_all_others_auto"]=array( "types"=>"MP", 'category'=>$clang->gT('Logic'), 'sortorder'=>131, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('If the participant marks all options, uncheck all and check the option set in the "Exclusive option" setting'), "caption"=>$clang->gT('Auto-check exclusive option if all others are checked')); // Map Options $qattributes["location_city"]=array( "types"=>"S", 'readonly_when_active'=>true, 'category'=>$clang->gT('Location'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'default'=>0, 'options'=>array(0=>$clang->gT('Yes'), 1=>$clang->gT('No')), "help"=>$clang->gT("Store the city?"), "caption"=>$clang->gT("Save city")); $qattributes["location_state"]=array( "types"=>"S", 'readonly_when_active'=>true, 'category'=>$clang->gT('Location'), 'sortorder'=>100, 'default'=>0, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Yes'), 1=>$clang->gT('No')), "help"=>$clang->gT("Store the state?"), "caption"=>$clang->gT("Save state")); $qattributes["location_postal"]=array( "types"=>"S", 'readonly_when_active'=>true, 'category'=>$clang->gT('Location'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'default'=>0, 'options'=>array(0=>$clang->gT('Yes'), 1=>$clang->gT('No')), "help"=>$clang->gT("Store the postal code?"), "caption"=>$clang->gT("Save postal code")); $qattributes["location_country"]=array( "types"=>"S", 'readonly_when_active'=>true, 'category'=>$clang->gT('Location'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'default'=>0, 'options'=>array(0=>$clang->gT('Yes'), 1=>$clang->gT('No')), "help"=>$clang->gT("Store the country?"), "caption"=>$clang->gT("Save country")); $qattributes["statistics_showmap"]=array( "types"=>"S", 'category'=>$clang->gT('Statistics'), 'inputtype'=>'singleselect', 'sortorder'=>100, 'options'=>array(1=>$clang->gT('Yes'), 0=>$clang->gT('No')), 'help'=>$clang->gT("Show a map in the statistics?"), 'caption'=>$clang->gT("Display map"), 'default'=>1 ); $qattributes["statistics_showgraph"]=array( 'types'=>'15ABCDEFGHIKLMNOPQRSTUWXYZ!:;|*', 'category'=>$clang->gT('Statistics'), 'inputtype'=>'singleselect', 'sortorder'=>101, 'options'=>array(1=>$clang->gT('Yes'), 0=>$clang->gT('No')), 'help'=>$clang->gT("Display a chart in the statistics?"), 'caption'=>$clang->gT("Display chart"), 'default'=>1 ); $qattributes["statistics_graphtype"]=array( "types"=>'15ABCDEFGHIKLNOQRSTUWXYZ!:;|*', 'category'=>$clang->gT('Statistics'), 'inputtype'=>'singleselect', 'sortorder'=>102, 'options'=>array(0=>$clang->gT('Bar chart'), 1=>$clang->gT('Pie chart')), 'help'=>$clang->gT("Select the type of chart to be displayed"), 'caption'=>$clang->gT("Chart type"), 'default'=>0 ); $qattributes["location_mapservice"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>90, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Off'), 1=>$clang->gT('Google Maps')), 'default' => 0, "help"=>$clang->gT("Activate this to show a map above the input field where the user can select a location"), "caption"=>$clang->gT("Use mapping service")); $qattributes["location_mapwidth"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>102, 'inputtype'=>'text', 'default'=>'500', "help"=>$clang->gT("Width of the map in pixel"), "caption"=>$clang->gT("Map width")); $qattributes["location_mapheight"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>103, 'inputtype'=>'text', 'default'=>'300', "help"=>$clang->gT("Height of the map in pixel"), "caption"=>$clang->gT("Map height")); $qattributes["location_nodefaultfromip"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>91, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Yes'), 1=>$clang->gT('No')), 'default' => 0, "help"=>$clang->gT("Get the default location using the user's IP address?"), "caption"=>$clang->gT("IP as default location")); $qattributes["location_defaultcoordinates"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>101, 'inputtype'=>'text', "help"=>$clang->gT('Default coordinates of the map when the page first loads. Format: latitude [space] longtitude'), "caption"=>$clang->gT('Default position')); $qattributes["location_mapzoom"]=array( "types"=>"S", 'category'=>$clang->gT('Location'), 'sortorder'=>101, 'inputtype'=>'text', 'default'=>'11', "help"=>$clang->gT("Map zoom level"), "caption"=>$clang->gT("Zoom level")); // End Map Options $qattributes["hide_tip"]=array( "types"=>"15ABCDEFGHIKLMNOPQRSTUXY!:;|", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Hide the tip that is normally shown with a question'), "caption"=>$clang->gT('Hide tip')); $qattributes['hidden']=array( 'types'=>'15ABCDEFGHIKLMNOPQRSTUWXYZ!:;|*', 'category'=>$clang->gT('Display'), 'sortorder'=>101, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, 'help'=>$clang->gT('Hide this question at any time. This is useful for including data using answer prefilling.'), 'caption'=>$clang->gT('Always hide this question')); $qattributes["max_answers"]=array( "types"=>"MPR1:;ABCEFKQ", 'category'=>$clang->gT('Logic'), 'sortorder'=>11, 'inputtype'=>'integer', "help"=>$clang->gT('Limit the number of possible answers'), "caption"=>$clang->gT('Maximum answers')); $qattributes["max_num_value"]=array( "types"=>"K", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Maximum sum value of multiple numeric input'), "caption"=>$clang->gT('Maximum sum value')); $qattributes["max_num_value_n"]=array( "types"=>"NK", 'category'=>$clang->gT('Input'), 'sortorder'=>110, 'inputtype'=>'integer', "help"=>$clang->gT('Maximum value of the numeric input'), "caption"=>$clang->gT('Maximum value')); // $qattributes["max_num_value_sgqa"]=array( // "types"=>"K", // 'category'=>$clang->gT('Logic'), // 'sortorder'=>100, // 'inputtype'=>'text', // "help"=>$clang->gT('Enter the SGQA identifier to use the total of a previous question as the maximum for this question'), // "caption"=>$clang->gT('Max value from SGQA')); $qattributes["maximum_chars"]=array( "types"=>"STUNQK:;", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Maximum characters allowed'), "caption"=>$clang->gT('Maximum characters')); $qattributes["min_answers"]=array( "types"=>"MPR1:;ABCEFKQ", 'category'=>$clang->gT('Logic'), 'sortorder'=>10, 'inputtype'=>'integer', "help"=>$clang->gT('Ensure a minimum number of possible answers (0=No limit)'), "caption"=>$clang->gT('Minimum answers')); $qattributes["min_num_value"]=array( "types"=>"K", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('The sum of the multiple numeric inputs must be greater than this value'), "caption"=>$clang->gT('Minimum sum value')); $qattributes["min_num_value_n"]=array( "types"=>"NK", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'integer', "help"=>$clang->gT('Minimum value of the numeric input'), "caption"=>$clang->gT('Minimum value')); // $qattributes["min_num_value_sgqa"]=array( // "types"=>"K", // 'category'=>$clang->gT('Logic'), // 'sortorder'=>100, // 'inputtype'=>'text', // "help"=>$clang->gT('Enter the SGQA identifier to use the total of a previous question as the minimum for this question'), // "caption"=>$clang->gT('Minimum value from SGQA')); $qattributes["multiflexible_max"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>112, 'inputtype'=>'text', "help"=>$clang->gT('Maximum value for array(mult-flexible) question type'), "caption"=>$clang->gT('Maximum value')); $qattributes["multiflexible_min"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>110, 'inputtype'=>'text', "help"=>$clang->gT('Minimum value for array(multi-flexible) question type'), "caption"=>$clang->gT('Minimum value')); $qattributes["multiflexible_step"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>111, 'inputtype'=>'text', "help"=>$clang->gT('Step value'), "caption"=>$clang->gT('Step value')); $qattributes["multiflexible_checkbox"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Use checkbox layout'), "caption"=>$clang->gT('Checkbox layout')); $qattributes["reverse"]=array( "types"=>"D:", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Present answer options in reverse order'), "caption"=>$clang->gT('Reverse answer order')); // $qattributes["num_value_equals_sgqa"]=array( // "types"=>"K", // 'category'=>$clang->gT('Logic'), // 'sortorder'=>100, // 'inputtype'=>'text', // "help"=>$clang->gT('SGQA identifier to use total of previous question as total for this question'), // "caption"=>$clang->gT('Value equals SGQA')); $qattributes["num_value_int_only"]=array( "types"=>"N", 'category'=>$clang->gT('Input'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array( 0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Restrict input to integer values'), "caption"=>$clang->gT('Integer only')); $qattributes["numbers_only"]=array( "types"=>"Q;S*", 'category'=>$clang->gT('Other'), 'sortorder'=>150, 'inputtype'=>'singleselect', 'options'=>array( 0=>$clang->gT('No'), 1=>$clang->gT('Yes') ), 'default'=>0, "help"=>$clang->gT('Allow only numerical input'), "caption"=>$clang->gT('Numbers only') ); $qattributes['show_totals'] = array( 'types' => ';', 'category' => $clang->gT('Other'), 'sortorder' => 151, 'inputtype' => 'singleselect', 'options' => array( 'X' => $clang->gT('Off'), 'R' => $clang->gT('Rows'), 'C' => $clang->gT('Columns'), 'B' => $clang->gT('Both rows and columns') ), 'default' => 'X', 'help' => $clang->gT('Show totals for either rows, columns or both rows and columns'), 'caption' => $clang->gT('Show totals for') ); $qattributes['show_grand_total'] = array( 'types' => ';', 'category' => $clang->gT('Other'), 'sortorder' => 152, 'inputtype' => 'singleselect', 'options' => array( 0 => $clang->gT('No'), 1 => $clang->gT('Yes') ), 'default' => 0, 'help' => $clang->gT('Show grand total for either columns or rows'), 'caption' => $clang->gT('Show grand total') ); $qattributes["input_boxes"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT("Present as text input boxes instead of dropdown lists"), "caption"=>$clang->gT("Text inputs")); $qattributes["other_comment_mandatory"]=array( "types"=>"PLW!Z", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT("Make the 'Other:' comment field mandatory when the 'Other:' option is active"), "caption"=>$clang->gT("'Other:' comment mandatory")); $qattributes["other_numbers_only"]=array( "types"=>"LMP", 'category'=>$clang->gT('Logic'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT("Allow only numerical input for 'Other' text"), "caption"=>$clang->gT("Numbers only for 'Other'")); $qattributes["other_replace_text"]=array( "types"=>"LMPWZ!", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT("Replaces the label of the 'Other:' answer option with a custom text"), "caption"=>$clang->gT("Label for 'Other:' option")); $qattributes["page_break"]=array( "types"=>"15ABCDEFGHKLMNOPQRSTUWXYZ!:;|*", 'category'=>$clang->gT('Other'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Insert a page break before this question in printable view by setting this to Yes.'), "caption"=>$clang->gT('Insert page break in printable view')); $qattributes["prefix"]=array( "types"=>"KNQS", 'category'=>$clang->gT('Display'), 'sortorder'=>10, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT('Add a prefix to the answer field'), "caption"=>$clang->gT('Answer prefix')); $qattributes["printable_help"]=array( "types"=>"15ABCDEFGHKLMNOPRWYZ!:*", 'category'=>$clang->gT('Display'), 'sortorder'=>201, "inputtype"=>"text", 'i18n'=>true, 'default'=>"", "help"=>$clang->gT('In the printable version replace the relevance equation with this explanation text.'), "caption"=>$clang->gT("Relevance help for printable survey")); $qattributes["public_statistics"]=array( "types"=>"15ABCEFGHKLMNOPRWYZ!:*", 'category'=>$clang->gT('Statistics'), 'sortorder'=>80, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Show statistics of this question in the public statistics page'), "caption"=>$clang->gT('Show in public statistics')); $qattributes["random_order"]=array( "types"=>"!ABCEFHKLMOPQRWZ1:;", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Off'), 1=>$clang->gT('Randomize on each page load') //,2=>$clang->gT('Randomize once on survey start') //Mdekker: commented out as code to handle this was removed in refactoring ), 'default'=>0, "help"=>$clang->gT('Present subquestions/answer options in random order'), "caption"=>$clang->gT('Random order')); /* $qattributes['relevance']=array( 'types'=>'15ABCDEFGHIKLMNOPQRSTUWXYZ!:;|*', 'category'=>$clang->gT('Display'), 'sortorder'=>1, 'inputtype'=>'text', 'default'=>'1', 'help'=>$clang->gT('The relevance equation determines whether a question should be shown (if true) or hiddden and marked as Not Applicable (if false).' . ' The relevance equation can be as complex as you like, using any combination of mathematical operators, nested parentheses,' . ' any variable or token that has already been set, and any of more than 50 functions. It is parsed by the ExpressionManager.'), 'caption'=>$clang->gT('Relevance equation')); */ $qattributes["showpopups"]=array( "types"=>"R", 'category'=>$clang->gT('Display'), 'sortorder'=>110, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "caption"=>$clang->gT('Show javascript alert'), "help"=>$clang->gT('Show an alert if answers exceeds the number of max answers')); $qattributes["samechoiceheight"]=array( "types"=>"R", 'category'=>$clang->gT('Display'), 'sortorder'=>120, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "caption"=>$clang->gT('Same height for all answer options'), "help"=>$clang->gT('Force each answer option to have the same height')); $qattributes["samelistheight"]=array( "types"=>"R", 'category'=>$clang->gT('Display'), 'sortorder'=>121, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "caption"=>$clang->gT('Same height for lists'), "help"=>$clang->gT('Force the choice list and the rank list to have the same height')); $qattributes["parent_order"]=array( "types"=>":", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'text', "caption"=>$clang->gT('Get order from previous question'), "help"=>$clang->gT('Enter question ID to get subquestion order from a previous question')); $qattributes["slider_layout"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>1, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Use slider layout'), "caption"=>$clang->gT('Use slider layout')); $qattributes["slider_min"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>10, 'inputtype'=>'text', "help"=>$clang->gT('Slider minimum value'), "caption"=>$clang->gT('Slider minimum value')); $qattributes["slider_max"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>11, 'inputtype'=>'text', "help"=>$clang->gT('Slider maximum value'), "caption"=>$clang->gT('Slider maximum value')); $qattributes["slider_accuracy"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>30, 'inputtype'=>'text', "help"=>$clang->gT('Slider accuracy'), "caption"=>$clang->gT('Slider accuracy')); $qattributes["slider_default"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>50, 'inputtype'=>'text', "help"=>$clang->gT('Slider start as this value (this will set the initial value).'), "caption"=>$clang->gT('Slider initial value')); $qattributes["slider_middlestart"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>40, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('The handle is displayed at the middle of the slider except if Slider initial value is set (this will not set the initial value).'), "caption"=>$clang->gT('Slider starts at the middle position')); $qattributes["slider_rating"]=array( "types"=>"5", 'category'=>$clang->gT('Display'), 'sortorder'=>90, 'inputtype'=>'singleselect', 'options'=>array( 0=>$clang->gT('No'), 1=>$clang->gT('Yes - stars'), 2=>$clang->gT('Yes - slider with emoticon'), ), 'default'=>0, "help"=>$clang->gT('Use slider layout'), "caption"=>$clang->gT('Use slider layout')); $qattributes["slider_reset"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>50, 'inputtype'=>'singleselect', 'options'=>array( 0=>$clang->gT('No'), 1=>$clang->gT('Yes'), ), 'default'=>0, "help"=>$clang->gT('Add a button to reset the slider. If you choose an start value, it reset at start value, else empty the answer.'), "caption"=>$clang->gT('Allow reset the slider')); $qattributes["slider_showminmax"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Display min and max value under the slider'), "caption"=>$clang->gT('Display slider min and max value')); $qattributes["slider_separator"]=array( "types"=>"K", 'category'=>$clang->gT('Slider'), 'sortorder'=>110, 'inputtype'=>'text', "help"=>$clang->gT('Answer|Left-slider-text|Right-slider-text separator character'), "caption"=>$clang->gT('Slider left/right text separator')); $qattributes["suffix"]=array( "types"=>"KNQS", 'category'=>$clang->gT('Display'), 'sortorder'=>11, 'inputtype'=>'text', 'i18n'=>true, "help"=>$clang->gT('Add a suffix to the answer field'), "caption"=>$clang->gT('Answer suffix')); $qattributes["text_input_width"]=array( "types"=>"KNSTUQ;", 'category'=>$clang->gT('Display'), 'sortorder'=>100, 'inputtype'=>'text', "help"=>$clang->gT('Width of text input box'), "caption"=>$clang->gT('Input box width')); $qattributes["use_dropdown"]=array( "types"=>"1FO", 'category'=>$clang->gT('Display'), 'sortorder'=>112, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT('Present dropdown control(s) instead of list of radio buttons'), "caption"=>$clang->gT('Use dropdown presentation')); $qattributes["dropdown_size"]=array( "types"=>"!", // TODO add these later? "1F", 'category'=>$clang->gT('Display'), 'sortorder'=>200, 'inputtype'=>'text', 'default'=>0, "help"=>$clang->gT('For list dropdown boxes, show up to this many rows'), "caption"=>$clang->gT('Height of dropdown')); $qattributes["dropdown_prefix"]=array( "types"=>"!", // TODO add these later? "1F", 'category'=>$clang->gT('Display'), 'sortorder'=>201, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('None'), 1=>$clang->gT('Order - like 3)'), ), 'default'=>0, "help"=>$clang->gT('Accelerator keys for list items'), "caption"=>$clang->gT('Prefix for list items')); $qattributes["scale_export"]=array( "types"=>"CEFGHLMOPWYZ1!:*", 'category'=>$clang->gT('Other'), 'sortorder'=>100, 'inputtype'=>'singleselect', 'options'=>array(0=>$clang->gT('Default'), 1=>$clang->gT('Nominal'), 2=>$clang->gT('Ordinal'), 3=>$clang->gT('Scale')), 'default'=>0, "help"=>$clang->gT("Set a specific SPSS export scale type for this question"), "caption"=>$clang->gT('SPSS export scale type')); $qattributes["choice_title"]=array( "types"=>"R", 'category'=>$clang->gT('Other'), 'sortorder'=>200, "inputtype"=>"text", 'i18n'=>true, 'default'=>"", "help"=>sprintf($clang->gT("Replace choice header (default: \"%s\")",'js'),$clang->gT("Your Choices")), "caption"=>$clang->gT("Choice header")); $qattributes["rank_title"]=array( "types"=>"R", 'category'=>$clang->gT('Other'), 'sortorder'=>201, "inputtype"=>"text", 'i18n'=>true, 'default'=>"", "help"=>sprintf($clang->gT("Replace rank header (default: \"%s\")",'js'),$clang->gT("Your Ranking")), "caption"=>$clang->gT("Rank header")); //Timer attributes $qattributes["time_limit"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>90, "inputtype"=>"integer", "help"=>$clang->gT("Limit time to answer question (in seconds)"), "caption"=>$clang->gT("Time limit")); $qattributes["time_limit_action"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>92, 'inputtype'=>'singleselect', 'options'=>array(1=>$clang->gT('Warn and move on'), 2=>$clang->gT('Move on without warning'), 3=>$clang->gT('Disable only')), "default" => 1, "help"=>$clang->gT("Action to perform when time limit is up"), "caption"=>$clang->gT("Time limit action")); $qattributes["time_limit_disable_next"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>94, "inputtype"=>"singleselect", 'default'=>0, 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), "help"=>$clang->gT("Disable the next button until time limit expires"), "caption"=>$clang->gT("Time limit disable next")); $qattributes["time_limit_disable_prev"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>96, "inputtype"=>"singleselect", 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>0, "help"=>$clang->gT("Disable the prev button until the time limit expires"), "caption"=>$clang->gT("Time limit disable prev")); $qattributes["time_limit_countdown_message"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>98, "inputtype"=>"textarea", 'i18n'=>true, "help"=>$clang->gT("The text message that displays in the countdown timer during the countdown"), "caption"=>$clang->gT("Time limit countdown message")); $qattributes["time_limit_timer_style"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>100, "inputtype"=>"textarea", "help"=>$clang->gT("CSS Style for the message that displays in the countdown timer during the countdown"), "caption"=>$clang->gT("Time limit timer CSS style")); $qattributes["time_limit_message_delay"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>102, "inputtype"=>"integer", "help"=>$clang->gT("Display the 'time limit expiry message' for this many seconds before performing the 'time limit action' (defaults to 1 second if left blank)"), "caption"=>$clang->gT("Time limit expiry message display time")); $qattributes["time_limit_message"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>104, "inputtype"=>"textarea", 'i18n'=>true, "help"=>$clang->gT("The message to display when the time limit has expired (a default message will display if this setting is left blank)"), "caption"=>$clang->gT("Time limit expiry message")); $qattributes["time_limit_message_style"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>106, "inputtype"=>"textarea", "help"=>$clang->gT("CSS style for the 'time limit expiry message'"), "caption"=>$clang->gT("Time limit message CSS style")); $qattributes["time_limit_warning"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>108, "inputtype"=>"integer", "help"=>$clang->gT("Display a 'time limit warning' when there are this many seconds remaining in the countdown (warning will not display if left blank)"), "caption"=>$clang->gT("1st time limit warning message timer")); $qattributes["time_limit_warning_display_time"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>110, "inputtype"=>"integer", "help"=>$clang->gT("The 'time limit warning' will stay visible for this many seconds (will not turn off if this setting is left blank)"), "caption"=>$clang->gT("1st time limit warning message display time")); $qattributes["time_limit_warning_message"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>112, "inputtype"=>"textarea", 'i18n'=>true, "help"=>$clang->gT("The message to display as a 'time limit warning' (a default warning will display if this is left blank)"), "caption"=>$clang->gT("1st time limit warning message")); $qattributes["time_limit_warning_style"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>114, "inputtype"=>"textarea", "help"=>$clang->gT("CSS style used when the 'time limit warning' message is displayed"), "caption"=>$clang->gT("1st time limit warning CSS style")); $qattributes["time_limit_warning_2"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>116, "inputtype"=>"integer", "help"=>$clang->gT("Display the 2nd 'time limit warning' when there are this many seconds remaining in the countdown (warning will not display if left blank)"), "caption"=>$clang->gT("2nd time limit warning message timer")); $qattributes["time_limit_warning_2_display_time"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>118, "inputtype"=>"integer", "help"=>$clang->gT("The 2nd 'time limit warning' will stay visible for this many seconds (will not turn off if this setting is left blank)"), "caption"=>$clang->gT("2nd time limit warning message display time")); $qattributes["time_limit_warning_2_message"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>120, "inputtype"=>"textarea", 'i18n'=>true, "help"=>$clang->gT("The 2nd message to display as a 'time limit warning' (a default warning will display if this is left blank)"), "caption"=>$clang->gT("2nd time limit warning message")); $qattributes["time_limit_warning_2_style"]=array( "types"=>"STUXL!", 'category'=>$clang->gT('Timer'), 'sortorder'=>122, "inputtype"=>"textarea", "help"=>$clang->gT("CSS style used when the 2nd 'time limit warning' message is displayed"), "caption"=>$clang->gT("2nd time limit warning CSS style")); $qattributes["date_format"]=array( "types"=>"D", 'category'=>$clang->gT('Input'), 'sortorder'=>100, "inputtype"=>"text", "help"=>$clang->gT("Specify a custom date/time format (the d/dd m/mm yy/yyyy H/HH M/MM formats and \"-./: \" characters are allowed for day/month/year/hour/minutes without or with leading zero respectively. Defaults to survey's date format"), "caption"=>$clang->gT("Date/Time format")); $qattributes["dropdown_dates_minute_step"]=array( "types"=>"D", 'category'=>$clang->gT('Input'), 'sortorder'=>100, "inputtype"=>"integer", 'default'=>1, "help"=>$clang->gT("Minute step interval when using select boxes"), "caption"=>$clang->gT("Minute step interval")); $qattributes["dropdown_dates_month_style"]=array( "types"=>"D", 'category'=>$clang->gT('Display'), 'sortorder'=>100, "inputtype"=>"singleselect", 'options'=>array(0=>$clang->gT('Short names'), 1=>$clang->gT('Full names'), 2=>$clang->gT('Numbers')), 'default'=>0, "help"=>$clang->gT("Change the display style of the month when using select boxes"), "caption"=>$clang->gT("Month display style")); $qattributes["show_title"]=array( "types"=>"|", 'category'=>$clang->gT('File metadata'), 'sortorder'=>124, "inputtype"=>"singleselect", 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "help"=>$clang->gT("Is the participant required to give a title to the uploaded file?"), "caption"=>$clang->gT("Show title")); $qattributes["show_comment"]=array( "types"=>"|", 'category'=>$clang->gT('File metadata'), 'sortorder'=>126, "inputtype"=>"singleselect", 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "help"=>$clang->gT("Is the participant required to give a comment to the uploaded file?"), "caption"=>$clang->gT("Show comment")); $qattributes["max_filesize"]=array( "types"=>"|", 'category'=>$clang->gT('Other'), 'sortorder'=>128, "inputtype"=>"integer", 'default'=>10240, "help"=>$clang->gT("The participant cannot upload a single file larger than this size"), "caption"=>$clang->gT("Maximum file size allowed (in KB)")); $qattributes["max_num_of_files"]=array( "types"=>"|", 'category'=>$clang->gT('Other'), 'sortorder'=>130, "inputtype"=>"text", 'default'=>'1', "help"=>$clang->gT("Maximum number of files that the participant can upload for this question"), "caption"=>$clang->gT("Max number of files")); $qattributes["min_num_of_files"]=array( "types"=>"|", 'category'=>$clang->gT('Other'), 'sortorder'=>132, "inputtype"=>"text", 'default'=>'0', "help"=>$clang->gT("Minimum number of files that the participant must upload for this question"), "caption"=>$clang->gT("Min number of files")); $qattributes["allowed_filetypes"]=array( "types"=>"|", 'category'=>$clang->gT('Other'), 'sortorder'=>134, "inputtype"=>"text", 'default'=>"png, gif, doc, odt", "help"=>$clang->gT("Allowed file types in comma separated format. e.g. pdf,doc,odt"), "caption"=>$clang->gT("Allowed file types")); $qattributes["random_group"]=array( "types"=>"15ABCDEFGHIKLMNOPQRSTUWXYZ!:;|", 'category'=>$clang->gT('Logic'), 'sortorder'=>180, 'inputtype'=>'text', "help"=>$clang->gT("Place questions into a specified randomization group, all questions included in the specified group will appear in a random order"), "caption"=>$clang->gT("Randomization group name")); // This is added to support historical behavior. Early versions of 1.92 used a value of "No", so if there was a min_sum_value or equals_sum_value, the question was not valid // unless those criteria were met. In later releases of 1.92, the default was changed so that missing values were allowed even if those attributes were set // This attribute lets authors control whether missing values should be allowed in those cases without needing to set min_answers // Existing surveys will use the old behavior, but if the author edits the question, the default will be the new behavior. $qattributes["value_range_allows_missing"]=array( "types"=>"K", 'category'=>$clang->gT('Input'), 'sortorder'=>100, "inputtype"=>"singleselect", 'options'=>array(0=>$clang->gT('No'), 1=>$clang->gT('Yes')), 'default'=>1, "help"=>$clang->gT("Is no answer (missing) allowed when either 'Equals sum value' or 'Minimum sum value' are set?"), "caption"=>$clang->gT("Value range allows missing")); } //This builds a more useful array (don't modify) if ($returnByName==false) { if(!$qat) { foreach($qattributes as $qname=>$qvalue) { for ($i=0; $i<=strlen($qvalue['types'])-1; $i++) { $qat[substr($qvalue['types'], $i, 1)][$qname]=array("name"=>$qname, "inputtype"=>$qvalue['inputtype'], "category"=>$qvalue['category'], "sortorder"=>$qvalue['sortorder'], "i18n"=>isset($qvalue['i18n'])?$qvalue['i18n']:false, "readonly"=>isset($qvalue['readonly_when_active'])?$qvalue['readonly_when_active']:false, "options"=>isset($qvalue['options'])?$qvalue['options']:'', "default"=>isset($qvalue['default'])?$qvalue['default']:'', "help"=>$qvalue['help'], "caption"=>$qvalue['caption']); } } } return $qat; } else { return $qattributes; } } function categorySort($a, $b) { $result=strnatcasecmp($a['category'], $b['category']); if ($result==0) { $result=$a['sortorder']-$b['sortorder']; } return $result; } // make sure the given string (which comes from a POST or GET variable) // is safe to use in MySQL. This does nothing if gpc_magic_quotes is on. function autoEscape($str) { if (!get_magic_quotes_gpc()) { return addslashes ($str); } return $str; } // the opposite of the above: takes a POST or GET variable which may or // may not have been 'auto-quoted', and return the *unquoted* version. // this is useful when the value is destined for a web page (eg) not // a SQL query. function autoUnescape($str) { if (!isset($str)) {return null;}; if (!get_magic_quotes_gpc()) return $str; return stripslashes($str); } // make a string safe to include in an HTML 'value' attribute. function HTMLEscape($str) { // escape newline characters, too, in case we put a value from // a TEXTAREA into an value attribute. return str_replace(array("\x0A","\x0D"),array(" "," "), htmlspecialchars( $str, ENT_QUOTES )); } /** * Escapes a text value for db * * @param string $value * @return string */ function dbQuoteAll($value) { return Yii::app()->db->quoteValue($value); } // make a string safe to include in a JavaScript String parameter. function javascriptEscape($str, $strip_tags=false, $htmldecode=false) { $new_str =''; if ($htmldecode==true) { $str=html_entity_decode($str,ENT_QUOTES,'UTF-8'); } if ($strip_tags==true) { $str=strip_tags($str); } return str_replace(array('\'','"', "\n", "\r"), array("\\'",'\u0022', "\\n",'\r'), $str); } /** * This function mails a text $body to the recipient $to. * You can use more than one recipient when using a semikolon separated string with recipients. * * @param string $body Body text of the email in plain text or HTML * @param mixed $subject Email subject * @param mixed $to Array with several email addresses or single string with one email address * @param mixed $from * @param mixed $sitename * @param mixed $ishtml * @param mixed $bouncemail * @param mixed $attachment * @return bool If successful returns true */ function SendEmailMessage($body, $subject, $to, $from, $sitename, $ishtml=false, $bouncemail=null, $attachments=null, $customheaders="") { global $maildebug, $maildebugbody; $clang = Yii::app()->lang; $emailmethod = Yii::app()->getConfig('emailmethod'); $emailsmtphost = Yii::app()->getConfig("emailsmtphost"); $emailsmtpuser = Yii::app()->getConfig("emailsmtpuser"); $emailsmtppassword = Yii::app()->getConfig("emailsmtppassword"); $emailsmtpdebug = Yii::app()->getConfig("emailsmtpdebug"); $emailsmtpssl = Yii::app()->getConfig("emailsmtpssl"); $defaultlang = Yii::app()->getConfig("defaultlang"); $emailcharset = Yii::app()->getConfig("emailcharset"); if ($emailcharset!='utf-8') { $body=mb_convert_encoding($body,$emailcharset,'utf-8'); $subject=mb_convert_encoding($subject,$emailcharset,'utf-8'); $sitename=mb_convert_encoding($sitename,$emailcharset,'utf-8'); } if (!is_array($to)){ $to=array($to); } if (!is_array($customheaders) && $customheaders == '') { $customheaders=array(); } if (Yii::app()->getConfig('demoMode')) { $maildebug=$clang->gT('Email was not sent because demo-mode is activated.'); $maildebugbody=''; return false; } if (is_null($bouncemail) ) { $sender=$from; } else { $sender=$bouncemail; } require_once(APPPATH.'/third_party/phpmailer/class.phpmailer.php'); $mail = new PHPMailer; if (!$mail->SetLanguage($defaultlang,APPPATH.'/third_party/phpmailer/language/')) { $mail->SetLanguage('en',APPPATH.'/third_party/phpmailer/language/'); } $mail->CharSet = $emailcharset; if (isset($emailsmtpssl) && trim($emailsmtpssl)!=='' && $emailsmtpssl!==0) { if ($emailsmtpssl===1) {$mail->SMTPSecure = "ssl";} else {$mail->SMTPSecure = $emailsmtpssl;} } $fromname=''; $fromemail=$from; if (strpos($from,'<')) { $fromemail=substr($from,strpos($from,'<')+1,strpos($from,'>')-1-strpos($from,'<')); $fromname=trim(substr($from,0, strpos($from,'<')-1)); } $sendername=''; $senderemail=$sender; if (strpos($sender,'<')) { $senderemail=substr($sender,strpos($sender,'<')+1,strpos($sender,'>')-1-strpos($sender,'<')); $sendername=trim(substr($sender,0, strpos($sender,'<')-1)); } switch ($emailmethod) { case "qmail": $mail->IsQmail(); break; case "smtp": $mail->IsSMTP(); if ($emailsmtpdebug>0) { $mail->SMTPDebug = $emailsmtpdebug; } if (strpos($emailsmtphost,':')>0) { $mail->Host = substr($emailsmtphost,0,strpos($emailsmtphost,':')); $mail->Port = substr($emailsmtphost,strpos($emailsmtphost,':')+1); } else { $mail->Host = $emailsmtphost; } $mail->Username =$emailsmtpuser; $mail->Password =$emailsmtppassword; if (trim($emailsmtpuser)!="") { $mail->SMTPAuth = true; } break; case "sendmail": $mail->IsSendmail(); break; default: //Set to the default value to rule out incorrect settings. $emailmethod="mail"; $mail->IsMail(); } $mail->SetFrom($fromemail, $fromname); $mail->Sender = $senderemail; // Sets Return-Path for error notifications foreach ($to as $singletoemail) { if (strpos($singletoemail, '<') ) { $toemail=substr($singletoemail,strpos($singletoemail,'<')+1,strpos($singletoemail,'>')-1-strpos($singletoemail,'<')); $toname=trim(substr($singletoemail,0, strpos($singletoemail,'<')-1)); $mail->AddAddress($toemail,$toname); } else { $mail->AddAddress($singletoemail); } } if (is_array($customheaders)) { foreach ($customheaders as $key=>$val) { $mail->AddCustomHeader($val); } } $mail->AddCustomHeader("X-Surveymailer: $sitename Emailer (LimeSurvey.sourceforge.net)"); if (get_magic_quotes_gpc() != "0") {$body = stripcslashes($body);} if ($ishtml) { $mail->IsHTML(true); //$mail->AltBody = strip_tags(breakToNewline(html_entity_decode($body,ENT_QUOTES,$emailcharset))); // Use included PHPmailer system see bug #8234 } else { $mail->IsHTML(false); } $mail->Body = $body; // Add attachments if they are there. if (is_array($attachments)) { foreach ($attachments as $attachment) { // Attachment is either an array with filename and attachment name. if (is_array($attachment)) { $mail->AddAttachment($attachment[0], $attachment[1]); } else { // Or a string with the filename. $mail->AddAttachment($attachment); } } } if (trim($subject)!='') {$mail->Subject = "=?$emailcharset?B?" . base64_encode($subject) . "?=";} if ($emailsmtpdebug>0) { ob_start(); } $sent=$mail->Send(); $maildebug=$mail->ErrorInfo; if ($emailsmtpdebug>0) { $maildebug .= '
    • '. gT('SMTP debug output:').'
    • '.strip_tags(ob_get_contents()).'
      '; ob_end_clean(); } $maildebugbody=$mail->Body; //if(!$sent) var_dump($maildebug); return $sent; } /** * This functions removes all HTML tags, Javascript, CRs, linefeeds and other strange chars from a given text * * @param string $sTextToFlatten Text you want to clean * @param boolan $keepSpan set to true for keep span, used for expression manager. Default: false * @param boolan $bDecodeHTMLEntities If set to true then all HTML entities will be decoded to the specified charset. Default: false * @param string $sCharset Charset to decode to if $decodeHTMLEntities is set to true. Default: UTF-8 * @param string $bStripNewLines strip new lines if true, if false replace all new line by \r\n. Default: true * * @return string Cleaned text */ function flattenText($sTextToFlatten, $keepSpan=false, $bDecodeHTMLEntities=false, $sCharset='UTF-8', $bStripNewLines=true) { $sNicetext = stripJavaScript($sTextToFlatten); // When stripping tags, add a space before closing tags so that strings with embedded HTML tables don't get concatenated $sNicetext = str_replace(array(' so can show EM syntax-highlighting; add space before tags so that word-wrapping not destroyed when remove tags. $sNicetext = strip_tags($sNicetext,'
      '); } else { $sNicetext = strip_tags($sNicetext); } // ~\R~u : see "What \R matches" and "Newline sequences" in http://www.pcre.org/pcre.txt - only available since PCRE 7.0 if ($bStripNewLines ){ // strip new lines if (version_compare(substr(PCRE_VERSION,0,strpos(PCRE_VERSION,' ')),'7.0')>-1) { $sNicetext = preg_replace(array('~\R~u'),array(' '), $sNicetext); } else { // Poor man's replacement for line feeds $sNicetext = str_replace(array("\r\n","\n", "\r"), array(' ',' ',' '), $sNicetext); } } elseif (version_compare(substr(PCRE_VERSION,0,strpos(PCRE_VERSION,' ')),'7.0')>-1)// unify newlines to \r\n { $sNicetext = preg_replace(array('~\R~u'), array("\r\n"), $sNicetext); } if ($bDecodeHTMLEntities==true) { $sNicetext = str_replace(' ',' ', $sNicetext); // html_entity_decode does not convert   to spaces $sNicetext = html_entity_decode($sNicetext, ENT_QUOTES, $sCharset); } $sNicetext = trim($sNicetext); return $sNicetext; } /** * getArrayFilterExcludesCascadesForGroup() queries the database and produces a list of array_filter_exclude questions and targets with in the same group * @return returns a keyed nested array, keyed by the qid of the question, containing cascade information */ function getArrayFilterExcludesCascadesForGroup($surveyid, $gid="", $output="qid") { $surveyid=sanitize_int($surveyid); $gid=sanitize_int($gid); $cascaded=array(); $sources=array(); $qidtotitle=array(); $fieldmap = createFieldMap($surveyid,'full',false,false,getBaseLanguageFromSurveyID($surveyid)); if($gid != "") { $qrows = arraySearchByKey($gid, $fieldmap, 'gid'); } else { $qrows = $fieldmap; } $grows = array(); //Create an empty array in case query not return any rows // Store each result as an array with in the $grows array foreach ($qrows as $qrow) { if (isset($qrow['gid']) && !empty($qrow['gid'])) { $grows[$qrow['qid']] = array('qid' => $qrow['qid'],'type' => $qrow['type'], 'mandatory' => $qrow['mandatory'], 'title' => $qrow['title'], 'gid' => $qrow['gid']); } } $attrmach = array(); // Stores Matches of filters that have their values as questions within current group foreach ($grows as $qrow) // Cycle through questions to see if any have list_filter attributes { $qidtotitle[$qrow['qid']]=$qrow['title']; $qresult = getQuestionAttributeValues($qrow['qid'],$qrow['type']); if (isset($qresult['array_filter_exclude'])) // We Found a array_filter attribute { $val = $qresult['array_filter_exclude']; // Get the Value of the Attribute ( should be a previous question's title in same group ) foreach ($grows as $avalue) // Cycle through all the other questions in this group until we find the source question for this array_filter { if ($avalue['title'] == $val) { /* This question ($avalue) is the question that provides the source information we use * to determine which answers show up in the question we're looking at, which is $qrow['qid'] * So, in other words, we're currently working on question $qrow['qid'], trying to find out more * information about question $avalue['qid'], because that's the source */ $sources[$qrow['qid']]=$avalue['qid']; /* This question ($qrow['qid']) relies on answers in $avalue['qid'] */ if(isset($cascades)) {unset($cascades);} $cascades=array(); /* Create an empty array */ /* At this stage, we know for sure that this question relies on one other question for the filter */ /* But this function wants to send back information about questions that rely on multiple other questions for the filter */ /* So we don't want to do anything yet */ /* What we need to do now, is check whether the question this one relies on, also relies on another */ /* The question we are now checking is $avalue['qid'] */ $keepgoing=1; $questiontocheck=$avalue['qid']; /* If there is a key in the $sources array that is equal to $avalue['qid'] then we want to add that * to the $cascades array */ while($keepgoing > 0) { if(!empty($sources[$questiontocheck])) { $cascades[] = $sources[$questiontocheck]; /* Now we need to move down the chain */ /* We want to check the $sources[$questiontocheck] question */ $questiontocheck=$sources[$questiontocheck]; } else { /* Since it was empty, there must not be any more questions down the cascade */ $keepgoing=0; } } /* Now add all that info */ if(count($cascades) > 0) { $cascaded[$qrow['qid']]=$cascades; } } } } } $cascade2=array(); if($output == "title") { foreach($cascaded as $key=>$cascade) { foreach($cascade as $item) { $cascade2[$key][]=$qidtotitle[$item]; } } $cascaded=$cascade2; } return $cascaded; } /** * getArrayFiltersForQuestion($qid) finds out if a question has an array_filter attribute and what codes where selected on target question * @return returns an array of codes that were selected else returns false */ function getArrayFiltersForQuestion($qid) { static $cache = array(); // TODO: Check list_filter values to make sure questions are previous? $qid=sanitize_int($qid); if (isset($cache[$qid])) return $cache[$qid]; $attributes = getQuestionAttributeValues($qid); if (isset($attributes['array_filter']) && Yii::app()->session['fieldarray']) { $val = $attributes['array_filter']; // Get the Value of the Attribute ( should be a previous question's title in same group ) foreach (Yii::app()->session['fieldarray'] as $fields) { if ($fields[2] == $val) { // we found the target question, now we need to know what the answers where, we know its a multi! $fields[0]=sanitize_int($fields[0]); //$query = "SELECT title FROM ".db_table_name('questions')." where parent_qid='{$fields[0]}' AND language='".Yii::app()->session[$surveyid]['s_lang']."' order by question_order"; $qresult=Question::model()->findAllByAttributes(array("parent_qid"=> $fields[0], "language"=> Yii::app()->session[$surveyid]['s_lang']), array('order' => "question_order")); $selected = array(); //while ($code = $qresult->fetchRow()) foreach ($qresult->readAll() as $code) { if (Yii::app()->session[$fields[1].$code['title']] == "Y" || Yii::app()->session[$fields[1]] == $code['title']) array_push($selected,$code['title']); } //Now we also need to find out if (a) the question had "other" enabled, and (b) if that was selected //$query = "SELECT other FROM ".db_table_name('questions')." where qid='{$fields[0]}'"; $qresult=Question::model()->findAllByAttributes(array("qid"=>$fields[0])); foreach ($qresult->readAll() as $row) {$other=$row['other'];} if($other == "Y") { if(Yii::app()->session[$fields[1].'other'] && Yii::app()->session[$fields[1].'other'] !="") {array_push($selected, "other");} } $cache[$qid] = $selected; return $cache[$qid]; } } $cache[$qid] = false; return $cache[$qid]; } $cache[$qid] = false; return $cache[$qid]; } /** * getGroupsByQuestion($surveyid) * @return returns a keyed array of groups to questions ie: array([1]=>[2]) question qid 1, is in group gid 2. */ function getGroupsByQuestion($surveyid) { $output=array(); $surveyid=sanitize_int($surveyid); $result=Question::model()->findAllByAttributes(array("sid"=>$surveyid)); foreach ($qresult->readAll() as $val) { $output[$val['qid']]=$val['gid']; } return $output; } /** * getArrayFilterExcludesForQuestion($qid) finds out if a question has an array_filter_exclude attribute and what codes where selected on target question * @return returns an array of codes that were selected else returns false */ function getArrayFilterExcludesForQuestion($qid) { static $cascadesCache = array(); static $cache = array(); // TODO: Check list_filter values to make sure questions are previous? // $surveyid = Yii::app()->getConfig('sid'); $surveyid=returnGlobal('sid'); $qid=sanitize_int($qid); if (isset($cache[$qid])) return $cache[$qid]; $attributes = getQuestionAttributeValues($qid); $excludevals=array(); if (isset($attributes['array_filter_exclude'])) // We Found a array_filter_exclude attribute { $selected=array(); $excludevals[] = $attributes['array_filter_exclude']; // Get the Value of the Attribute ( should be a previous question's title in same group ) /* Find any cascades and place them in the $excludevals array*/ if (!isset($cascadesCache[$surveyid])) { $cascadesCache[$surveyid] = getArrayFilterExcludesCascadesForGroup($surveyid, "", "title"); } $array_filterXqs_cascades = $cascadesCache[$surveyid]; if(isset($array_filterXqs_cascades[$qid])) { foreach($array_filterXqs_cascades[$qid] as $afc) { $excludevals[]=array("value"=>$afc); } } /* For each $val (question title) that applies to this, check what values exist and add them to the $selected array */ foreach ($excludevals as $val) { foreach (Yii::app()->session['fieldarray'] as $fields) //iterate through every question in the survey { if ($fields[2] == $val) { // we found the target question, now we need to know what the answers were! $fields[0]=sanitize_int($fields[0]); $query = "SELECT title FROM {{questions}} where parent_qid='{$fields[0]}' AND language='".Yii::app()->session[$surveyid]['s_lang']."' order by question_order"; $qresult = dbExecuteAssoc($query); //Checked foreach ($qresult->readAll() as $code) { if (isset(Yii::app()->session[$fields[1]])) if ((isset(Yii::app()->session[$fields[1].$code['title']]) && Yii::app()->session[$fields[1].$code['title']] == "Y") || Yii::app()->session[$fields[1]] == $code['title']) array_push($selected,$code['title']); } //Now we also need to find out if (a) the question had "other" enabled, and (b) if that was selected $query = "SELECT other FROM {{questions}} where qid='{$fields[0]}'"; $qresult = dbExecuteAssoc($query); foreach ($qresult->readAll() as $row) {$other=$row['other'];} if($other == "Y") { if(Yii::app()->session[$fields[1].'other'] != "") {array_push($selected, "other");} } } } } if(count($selected) > 0) { $cache[$qid] = $selected; return $cache[$qid]; } else { $cache[$qid] = false; return $cache[$qid]; } } $cache[$qid] = false; return $cache[$qid]; } function CSVEscape($sString) { $sString = preg_replace(array('~\R~u'), array(PHP_EOL), $sString); return '"' . str_replace('"','""', $sString) . '"'; } function convertCSVRowToArray($string, $separator, $quotechar) { $fields=preg_split('/' . $separator . '(?=([^"]*"[^"]*")*(?![^"]*"))/',trim($string)); $fields=array_map('CSVUnquote',$fields); return $fields; } function createPassword() { $aCharacters = "ABCDEGHJIKLMNOPQURSTUVWXYZabcdefhjmnpqrstuvwxyz23456789"; $iPasswordLength = 12; $sPassword = ''; for ($i=0; $i<$iPasswordLength; $i++) { $sPassword .= $aCharacters[(int)floor(rand(0,strlen($aCharacters)-1))]; } return $sPassword; } function languageDropdown($surveyid,$selected) { $homeurl = Yii::app()->getConfig('homeurl'); $slangs = Survey::model()->findByPk($surveyid)->additionalLanguages; $baselang = Survey::model()->findByPk($surveyid)->language; array_unshift($slangs,$baselang); $html = ""; return $html; } function languageDropdownClean($surveyid,$selected) { $slangs = Survey::model()->findByPk($surveyid)->additionalLanguages; $baselang = Survey::model()->findByPk($surveyid)->language; array_unshift($slangs,$baselang); $html = ""; return $html; } /** * This function removes a directory recursively * * @param mixed $dirname * @return bool */ function rmdirr($dirname) { // Sanity check if (!file_exists($dirname)) { return false; } // Simple delete for a file if (is_file($dirname) || is_link($dirname)) { return @unlink($dirname); } // Loop through the folder $dir = dir($dirname); while (false !== $entry = $dir->read()) { // Skip pointers if ($entry == '.' || $entry == '..') { continue; } // Recurse rmdirr($dirname . DIRECTORY_SEPARATOR . $entry); } // Clean up $dir->close(); return @rmdir($dirname); } /** * This function removes surrounding and masking quotes from the CSV field * * @param mixed $field * @return mixed */ function CSVUnquote($field) { //print $field.":"; $field = preg_replace ("/^\040*\"/", "", $field); $field = preg_replace ("/\"\040*$/", "", $field); $field= str_replace('""','"',$field); //print $field."\n"; return $field; } /** * This function return actual completion state * * @return string (complete|incomplete|all) or false */ function incompleteAnsFilterState() { $letsfilter=''; $letsfilter = returnGlobal('completionstate'); //read get/post completionstate // first let's initialize the incompleteanswers session variable if ($letsfilter != '') { // use the read value if not empty Yii::app()->session['incompleteanswers'] = $letsfilter; } elseif (empty(Yii::app()->session['incompleteanswers'])) { // sets default variable value from config file Yii::app()->session['incompleteanswers'] = Yii::app()->getConfig('filterout_incomplete_answers'); } if (Yii::app()->session['incompleteanswers']=='complete' || Yii::app()->session['incompleteanswers']=='all' || Yii::app()->session['incompleteanswers']=='incomplete') { return Yii::app()->session['incompleteanswers']; } else { // last resort is to prevent filtering return false; } } /** * isCaptchaEnabled($screen, $usecaptchamode) * @param string $screen - the screen name for which to test captcha activation * * @return boolean - returns true if captcha must be enabled **/ function isCaptchaEnabled($screen, $captchamode='') { switch($screen) { case 'registrationscreen': if ($captchamode == 'A' || $captchamode == 'B' || $captchamode == 'D' || $captchamode == 'R') { return true; } else { return false; } break; case 'surveyaccessscreen': if ($captchamode == 'A' || $captchamode == 'B' || $captchamode == 'C' || $captchamode == 'X') { return true; } else { return false; } break; case 'saveandloadscreen': if ($captchamode == 'A' || $captchamode == 'C' || $captchamode == 'D' || $captchamode == 'S') { return true; } else { return false; } return true; break; default: return true; break; } } /** * used for import[survey|questions|groups] * * @param mixed $string * @return mixed */ function convertCSVReturnToReturn($string) { $string= str_replace('\n', "\n", $string); return str_replace('\%n', '\n', $string); } /** * Check if a table does exist in the database * * @param string $sTableName Table name to check for (without dbprefix!)) * @return boolean True or false if table exists or not */ function tableExists($sTableName) { $sTableName=Yii::app()->db->tablePrefix.str_replace(array('{','}'),array('',''),$sTableName); return in_array($sTableName,Yii::app()->db->schema->getTableNames()); } // Returns false if the survey is anonymous, // and a token table exists: in this case the completed field of a token // will contain 'Y' instead of the submitted date to ensure privacy // Returns true otherwise function isTokenCompletedDatestamped($thesurvey) { if ($thesurvey['anonymized'] == 'Y' && tableExists('tokens_'.$thesurvey['sid'])) { return false; } else { return true; } } /** * example usage * $date = "2006-12-31 21:00"; * $shift "+6 hours"; // could be days, weeks... see function strtotime() for usage * * echo sql_date_shift($date, "Y-m-d H:i:s", $shift); * * will output: 2007-01-01 03:00:00 * * @param mixed $date * @param mixed $dformat * @param mixed $shift * @return string */ function dateShift($date, $dformat, $shift) { return date($dformat, strtotime($shift, strtotime($date))); } // getBounceEmail: returns email used to receive error notifications function getBounceEmail($surveyid) { $surveyInfo=getSurveyInfo($surveyid); if ($surveyInfo['bounce_email'] == '') { return null; // will be converted to from in MailText } else { return $surveyInfo['bounce_email']; } } // getEmailFormat: returns email format for the survey // returns 'text' or 'html' function getEmailFormat($surveyid) { $surveyInfo=getSurveyInfo($surveyid); if ($surveyInfo['htmlemail'] == 'Y') { return 'html'; } else { return 'text'; } } // Check if user has manage rights for a template function hasTemplateManageRights($userid, $templatefolder) { $userid=sanitize_int($userid); $templatefolder=sanitize_paranoid_string($templatefolder); return Permission::model()->hasTemplatePermission($templatefolder, 'read', $userid); } /** * This function creates an incrementing answer code based on the previous source-code * * @param mixed $sourcecode The previous answer code */ function getNextCode($sourcecode) { $i=1; $found=true; $foundnumber=-1; while ($i<=strlen($sourcecode) && $found) { $found=is_numeric(substr($sourcecode,-$i)); if ($found) { $foundnumber=substr($sourcecode,-$i); $i++; } } if ($foundnumber==-1) { return($sourcecode); } else { $foundnumber++; $result=substr($sourcecode,0,strlen($sourcecode)-strlen($foundnumber)).$foundnumber; return($result); } } /** * Translate links which are in any answer/question/survey/email template/label set to their new counterpart * * @param mixed $sType 'survey' or 'label' * @param mixed $iOldSurveyID * @param mixed $iNewSurveyID * @param mixed $sString * @return string */ function translateLinks($sType, $iOldSurveyID, $iNewSurveyID, $sString) { if ($sType == 'survey') { $sPattern = "([^'\"]*)/upload/surveys/{$iOldSurveyID}/"; $sReplace = Yii::app()->getConfig("publicurl")."upload/surveys/{$iNewSurveyID}/"; return preg_replace('#'.$sPattern.'#', $sReplace, $sString); } elseif ($sType == 'label') { $pattern = "([^'\"]*)/upload/labels/{$iOldSurveyID}/"; $replace = Yii::app()->getConfig("publicurl")."upload/labels/{$iNewSurveyID}/"; return preg_replace('#'.$pattern.'#', $replace, $sString); } else // unkown type { return $sString; } } /** * This function creates the old fieldnames for survey import * * @param mixed $iOldSID The old survey id * @param mixed $iNewSID The new survey id * @param array $aGIDReplacements An array with group ids (oldgid=>newgid) * @param array $aQIDReplacements An array with question ids (oldqid=>newqid) */ function reverseTranslateFieldNames($iOldSID,$iNewSID,$aGIDReplacements,$aQIDReplacements) { $aGIDReplacements=array_flip($aGIDReplacements); $aQIDReplacements=array_flip($aQIDReplacements); if ($iOldSID==$iNewSID) { $forceRefresh=true; // otherwise grabs the cached copy and throws undefined index exceptions } else { $forceRefresh=false; } $aFieldMap = createFieldMap($iNewSID,'short',$forceRefresh,false,getBaseLanguageFromSurveyID($iNewSID)); $aFieldMappings=array(); foreach ($aFieldMap as $sFieldname=>$aFieldinfo) { if ($aFieldinfo['qid']!=null) { $aFieldMappings[$sFieldname]=$iOldSID.'X'.$aGIDReplacements[$aFieldinfo['gid']].'X'.$aQIDReplacements[$aFieldinfo['qid']].$aFieldinfo['aid']; if ($aFieldinfo['type']=='1') { $aFieldMappings[$sFieldname]=$aFieldMappings[$sFieldname].'#'.$aFieldinfo['scale_id']; } // now also add a shortened field mapping which is needed for certain kind of condition mappings $aFieldMappings[$iNewSID.'X'.$aFieldinfo['gid'].'X'.$aFieldinfo['qid']]=$iOldSID.'X'.$aGIDReplacements[$aFieldinfo['gid']].'X'.$aQIDReplacements[$aFieldinfo['qid']]; // Shortened field mapping for timings table $aFieldMappings[$iNewSID.'X'.$aFieldinfo['gid']]=$iOldSID.'X'.$aGIDReplacements[$aFieldinfo['gid']]; } } return array_flip($aFieldMappings); } /** * put your comment there... * * @param mixed $id * @param mixed $type */ function hasResources($id,$type='survey') { $dirname = Yii::app()->getConfig("uploaddir"); if ($type == 'survey') { $dirname .= "/surveys/$id"; } elseif ($type == 'label') { $dirname .= "/labels/$id"; } else { return false; } if (is_dir($dirname) && $dh=opendir($dirname)) { while(($entry = readdir($dh)) !== false) { if($entry !== '.' && $entry !== '..') { return true; break; } } closedir($dh); } else { return false; } return false; } /** * Creates a random sequence of characters * * @param mixed $length Length of resulting string * @param string $pattern To define which characters should be in the resulting string */ function randomChars($length,$pattern="23456789abcdefghijkmnpqrstuvwxyz") { $patternlength = strlen($pattern)-1; $key = ''; for($i=0;$i<$length;$i++) { $key .= $pattern{mt_rand(0,$patternlength)}; } return $key; } /** * used to translate simple text to html (replacing \n with
      * * @param mixed $mytext * @param mixed $ishtml * @return mixed */ function conditionalNewlineToBreak($mytext,$ishtml,$encoded='') { if ($ishtml === true) { // $mytext has been processed by clang->gT with html mode // and thus \n has already been translated to if ($encoded == '') { $mytext=str_replace(' ', '
      ',$mytext); } return str_replace("\n", '
      ',$mytext); } else { return $mytext; } } function breakToNewline( $data ) { return preg_replace( '!!iU', "\n", $data ); } function safeDie($text) { //Only allowed tag:
      $textarray=explode('
      ',$text); $textarray=array_map('htmlspecialchars',$textarray); die(implode( '
      ',$textarray)); } function fixCKeditorText($str) { $str = str_replace('
      ','',$str); if ($str == "
      " || $str == " " || $str == " ") { $str = ""; } if (preg_match("/^[\s]+$/",$str)) { $str=''; } if ($str == "\n") { $str = ""; } if (trim($str) == " " || trim($str)=='') { // chrome adds a single   element to empty fckeditor fields $str = ""; } return $str; } /** * This is a helper function for getAttributeFieldNames * * @param mixed $fieldname */ function filterForAttributes ($fieldname) { if (strpos($fieldname,'attribute_')===false) return false; else return true; } /** * Retrieves the attribute field names from the related token table * * @param mixed $iSurveyID The survey ID * @return array The fieldnames */ function GetAttributeFieldNames($iSurveyID) { if (!tableExists("{{tokens_{$iSurveyID}}}") || !$table = Yii::app()->db->schema->getTable('{{tokens_'.$iSurveyID.'}}')) return Array(); return array_filter(array_keys($table->columns), 'filterForAttributes'); } /** * Returns the full list of attribute token fields including the properties for each field * Use this instead of plain Survey::model()->findByPk($iSurveyID)->tokenAttributes calls because Survey::model()->findByPk($iSurveyID)->tokenAttributes may contain old descriptions where the fields does not physically exist * * @param integer $iSurveyID The Survey ID */ function GetParticipantAttributes($iSurveyID) { if (!tableExists("{{tokens_{$iSurveyID}}}") || !$table = Yii::app()->db->schema->getTable('{{tokens_'.$iSurveyID.'}}')) return Array(); return getTokenFieldsAndNames($iSurveyID,true); } /** * Retrieves the token field names usable for conditions from the related token table * * @param mixed $surveyid The survey ID * @return array The fieldnames */ function getTokenConditionsFieldNames($surveyid) { $extra_attrs=getAttributeFieldNames($surveyid); $basic_attrs=Array('firstname','lastname','email','token','language','sent','remindersent','remindercount'); return array_merge($basic_attrs,$extra_attrs); } /** * Retrieves the attribute names from the related token table * * @param mixed $surveyid The survey ID * @param boolean $bOnlyAttributes Set this to true if you only want the fieldnames of the additional attribue fields - defaults to false * @return array The fieldnames as key and names as value in an Array */ function getTokenFieldsAndNames($surveyid, $bOnlyAttributes = false) { $clang = Yii::app()->lang; $aBasicTokenFields=array('firstname'=>array( 'description'=>$clang->gT('First name'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'lastname'=>array( 'description'=>$clang->gT('Last name'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'email'=>array( 'description'=>$clang->gT('Email address'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'emailstatus'=>array( 'description'=>$clang->gT("Email status"), 'mandatory'=>'N', 'showregister'=>'N' ), 'token'=>array( 'description'=>$clang->gT('Token'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'language'=>array( 'description'=>$clang->gT('Language code'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'sent'=>array( 'description'=>$clang->gT('Invitation sent date'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'remindersent'=>array( 'description'=>$clang->gT('Last reminder sent date'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'remindercount'=>array( 'description'=>$clang->gT('Total numbers of sent reminders'), 'mandatory'=>'N', 'showregister'=>'Y' ), 'usesleft'=>array( 'description'=>$clang->gT('Uses left'), 'mandatory'=>'N', 'showregister'=>'Y' ), ); $aExtraTokenFields=getAttributeFieldNames($surveyid); $aSavedExtraTokenFields = Survey::model()->findByPk($surveyid)->tokenAttributes; // Drop all fields that are in the saved field description but not in the table definition $aSavedExtraTokenFields=array_intersect_key($aSavedExtraTokenFields,array_flip($aExtraTokenFields)); // Now add all fields that are in the table but not in the field description foreach ($aExtraTokenFields as $sField) { if (!isset($aSavedExtraTokenFields[$sField])) { $aSavedExtraTokenFields[$sField]=array( 'description'=>$sField, 'mandatory'=>'N', 'showregister'=>'N', 'cpdbmap'=>'' ); } elseif(empty($aSavedExtraTokenFields[$sField]['description'])) { $aSavedExtraTokenFields[$sField]['description']=$sField; } } if ($bOnlyAttributes) { return $aSavedExtraTokenFields; } else { return array_merge($aBasicTokenFields,$aSavedExtraTokenFields); } } /** * Retrieves the token attribute value from the related token table * * @param mixed $surveyid The survey ID * @param mixed $attrName The token-attribute field name * @param mixed $token The token code * @return string The token attribute value (or null on error) */ function getAttributeValue($surveyid,$attrName,$token) { $attrName=strtolower($attrName); if (!tableExists('tokens_'.$surveyid)) { return null; } $token = Token::model($surveyid)->findByAttributes(array("token"=>$token)); return isset($token->$attrName) ? $token->$attrName : null; } /** * This function strips any content between and including tags * * @param string $sContent String to clean * @return string Cleaned string */ function stripJavaScript($sContent){ $text = preg_replace('@]*?>.*?@si', '', $sContent); return $text; } /** * This function converts emebedded Javascript to Text * * @param string $sContent String to clean * @return string Cleaned string */ function showJavaScript($sContent){ $text = preg_replace_callback ('@]*?>.*?@si', create_function( // single quotes are essential here, // or alternative escape all $ as \$ '$matches', 'return htmlspecialchars($matches[0]);' ), $sContent); return $text; } /** * This function cleans files from the temporary directory being older than 1 day * @todo Make the days configurable */ function cleanTempDirectory() { $dir = Yii::app()->getConfig('tempdir').DIRECTORY_SEPARATOR; $dp = opendir($dir) or show_error('Could not open temporary directory'); while ($file = readdir($dp)) { if (is_file($dir.$file) && (filemtime($dir.$file)) < (strtotime('-1 days')) && $file!='index.html' && $file!='.gitignore' && $file!='readme.txt') { @unlink($dir.$file); } } $dir= Yii::app()->getConfig('tempdir').DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR; $dp = opendir($dir) or die ('Could not open temporary upload directory'); while ($file = readdir($dp)) { if (is_file($dir.$file) && (filemtime($dir.$file)) < (strtotime('-1 days')) && $file!='index.html' && $file!='.gitignore' && $file!='readme.txt') { @unlink($dir.$file); } } closedir($dp); } function useFirebug() { if(FIREBUG == true) { App()->getClientScript()->registerScriptFile('http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'); }; }; /** * This is a convenience function for the coversion of datetime values * * @param mixed $value * @param mixed $fromdateformat * @param mixed $todateformat * @return string */ function convertDateTimeFormat($value, $fromdateformat, $todateformat) { Yii::import('application.libraries.Date_Time_Converter', true); $date = new Date_Time_Converter($value, $fromdateformat); return $date->convert($todateformat); } /** * This function removes the UTF-8 Byte Order Mark from a string * * @param string $str * @return string */ function removeBOM($str=""){ if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) { $str=substr($str, 3); } return $str; } /** * This function requests the latest update information from the LimeSurvey.org website * * @returns array Contains update information or false if the request failed for some reason */ /**********************************************/ /* This function needs ported still. */ /**********************************************/ function getUpdateInfo() { if (getGlobalSetting('SessionName')=='') { setGlobalSetting('SessionName',randomChars(64,'ABCDEFGHIJKLMNOPQRSTUVWXYZ!"$%&/()=?`+*~#",;.:abcdefghijklmnopqrstuvwxyz123456789')); } Yii::import('application.libraries.admin.http.httpRequestIt'); $http=new httpRequestIt; $http->proxy_host_name = Yii::app()->getConfig("proxy_host_name",""); $http->proxy_host_port = Yii::app()->getConfig("proxy_host_port",80); $http->timeout=0; $http->data_timeout=0; $http->user_agent="LimeSurvey ".Yii::app()->getConfig("versionnumber")." build ".Yii::app()->getConfig("buildnumber"); $http->GetRequestArguments("http://update.limesurvey.org?build=".Yii::app()->getConfig("buildnumber").'&id='.md5(getGlobalSetting('SessionName')).'&crosscheck=true',$arguments); $updateinfo=false; $error=$http->Open($arguments); $error=$http->SendRequest($arguments); $http->ReadReplyHeaders($headers); if($error=="") { $body=''; $full_body=''; for(;;){ $error = $http->ReadReplyBody($body,10000); if($error != "" || strlen($body)==0) break; $full_body .= $body; } $updateinfo=json_decode($full_body,true); if ($http->response_status!='200') { $updateinfo['errorcode']=$http->response_status; $updateinfo['errorhtml']=$full_body; } } else { $updateinfo['errorcode']=$error; $updateinfo['errorhtml']=$error; } unset( $http ); return $updateinfo; } /** * This function updates the actual global variables if an update is available after using getUpdateInfo * @return Array with update or error information */ function updateCheck() { $aUpdateVersions=getUpdateInfo(); $clang = Yii::app()->lang; if (isset($aUpdateVersions['errorcode'])) { Yii::app()->setFlashMessage(sprintf($clang->gT("Error when checking for new version: %s"),$aUpdateVersions['errorcode']).'
      '.$aUpdateVersions['errorhtml'],'error'); $aUpdateVersions=array(); } if (count($aUpdateVersions) && trim(Yii::app()->getConfig('buildnumber'))!='') { $sUpdateNotificationType = getGlobalSetting('updatenotification'); switch ($sUpdateNotificationType) { case 'stable': // Only show update if in stable (master) branch if (isset($aUpdateVersions['master'])) { $aUpdateVersion=$aUpdateVersions['master']; $aUpdateVersions=array_intersect_key($aUpdateVersions,array('master'=>'1')); } break; case 'both': // Show first available update $aUpdateVersion=reset($aUpdateVersions); break; default: // Never show a notification $aUpdateVersions=array(); break; } } setGlobalSetting('updateversions',json_encode($aUpdateVersions)); if (isset($aUpdateVersion)) { setGlobalSetting('updateavailable',1); setGlobalSetting('updatebuild',$aUpdateVersion['build']); setGlobalSetting('updateversion',$aUpdateVersion['versionnumber']); } else { setGlobalSetting('updateavailable',0); $aUpdateVersions = array(); } setGlobalSetting('updatelastcheck',date('Y-m-d H:i:s')); return $aUpdateVersions; } /** * Return the goodchars to be used when filtering input for numbers. * * @param $lang string language used, for localisation * @param $integer bool use only integer * @param $negative bool allow negative values */ function getNumericalFormat($lang = 'en', $integer = false, $negative = true) { $goodchars = "0123456789"; if ($integer === false) $goodchars .= "."; //Todo, add localisation if ($negative === true) $goodchars .= "-"; //Todo, check databases return $goodchars; } /** * This function returns the complete directory path to a given template name * * @param mixed $sTemplateName */ function getTemplatePath($sTemplateName = false) { if (!$sTemplateName) { $sTemplateName=Yii::app()->getConfig('defaulttemplate'); // if $sTemplateName is NULL or false or "" } if (isStandardTemplate($sTemplateName)) { return Yii::app()->getConfig("standardtemplaterootdir").DIRECTORY_SEPARATOR.$sTemplateName; } else { if (is_dir(Yii::app()->getConfig("usertemplaterootdir").DIRECTORY_SEPARATOR.$sTemplateName)) { return Yii::app()->getConfig("usertemplaterootdir").DIRECTORY_SEPARATOR.$sTemplateName; } elseif (isStandardTemplate(Yii::app()->getConfig('defaulttemplate'))) { return Yii::app()->getConfig("standardtemplaterootdir").DIRECTORY_SEPARATOR.$sTemplateName; } elseif (file_exists(Yii::app()->getConfig("usertemplaterootdir").DIRECTORY_SEPARATOR.Yii::app()->getConfig('defaulttemplate'))) { return Yii::app()->getConfig("usertemplaterootdir").DIRECTORY_SEPARATOR.Yii::app()->getConfig('defaulttemplate'); } else { return Yii::app()->getConfig("standardtemplaterootdir").DIRECTORY_SEPARATOR.'default'; } } } /** * This function returns the complete URL path to a given template name * * @param mixed $sTemplateName */ function getTemplateURL($sTemplateName) { if (isStandardTemplate($sTemplateName)) { return Yii::app()->getConfig("standardtemplaterooturl").'/'.$sTemplateName; } else { if (file_exists(Yii::app()->getConfig("usertemplaterootdir").'/'.$sTemplateName)) { return Yii::app()->getConfig("usertemplaterooturl").'/'.$sTemplateName; } elseif (file_exists(Yii::app()->getConfig("usertemplaterootdir").'/'.Yii::app()->getConfig('defaulttemplate'))) { return Yii::app()->getConfig("usertemplaterooturl").'/'.Yii::app()->getConfig('defaulttemplate'); } elseif (file_exists(Yii::app()->getConfig("standardtemplaterootdir").'/'.Yii::app()->getConfig('defaulttemplate'))) { return Yii::app()->getConfig("standardtemplaterooturl").'/'.Yii::app()->getConfig('defaulttemplate'); } else { return Yii::app()->getConfig("standardtemplaterooturl").'/default'; } } } /** * Return an array of subquestions for a given sid/qid * * @param int $sid * @param int $qid * @param $sLanguage Language of the subquestion text */ function getSubQuestions($sid, $qid, $sLanguage) { static $subquestions; if (!isset($subquestions[$sid])) { $subquestions[$sid]=array(); } if (!isset($subquestions[$sid][$sLanguage])) { $query = "SELECT sq.*, q.other FROM {{questions}} as sq, {{questions}} as q" ." WHERE sq.parent_qid=q.qid AND q.sid=".$sid ." AND sq.language='".$sLanguage. "' " ." AND q.language='".$sLanguage. "' " ." ORDER BY sq.parent_qid, q.question_order,sq.scale_id , sq.question_order"; $query = Yii::app()->db->createCommand($query)->query(); $resultset=array(); //while ($row=$result->FetchRow()) foreach ($query->readAll() as $row) { $resultset[$row['parent_qid']][] = $row; } $subquestions[$sid][$sLanguage] = $resultset; } if (isset($subquestions[$sid][$sLanguage][$qid])) return $subquestions[$sid][$sLanguage][$qid]; return array(); } /** * Wrapper function to retrieve an xmlwriter object and do error handling if it is not compiled * into PHP */ function getXMLWriter() { if (!extension_loaded('xmlwriter')) { safeDie('XMLWriter class not compiled into PHP, please contact your system administrator'); } else { $xmlwriter = new XMLWriter(); } return $xmlwriter; } /** * SSLRedirect() generates a redirect URL for the appropriate SSL mode then applies it. * (Was redirect() before CodeIgniter port.) * * @param $enforceSSLMode string 's' or '' (empty). */ function SSLRedirect($enforceSSLMode) { $url = 'http'.$enforceSSLMode.'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; if (!headers_sent()) { // If headers not sent yet... then do php redirect //ob_clean(); header('Location: '.$url); //ob_flush(); exit; }; }; /** * enforceSSLMode() $force_ssl is on or off, it checks if the current * request is to HTTPS (or not). If $force_ssl is on, and the * request is not to HTTPS, it redirects the request to the HTTPS * version of the URL, if the request is to HTTPS, it rewrites all * the URL variables so they also point to HTTPS. */ function enforceSSLMode() { $bSSLActive = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off")|| (isset($_SERVER['HTTP_FORWARDED_PROTO']) && $_SERVER['HTTP_FORWARDED_PROTO']=="https")|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']=="https")); if (Yii::app()->getConfig('ssl_emergency_override') !== true ) { $force_ssl = strtolower(getGlobalSetting('force_ssl')); } else { $force_ssl = 'off'; }; if( $force_ssl == 'on' && !$bSSLActive ) { SSLRedirect('s'); } if( $force_ssl == 'off' && $bSSLActive) { SSLRedirect(''); }; }; /** * Returns the number of answers matching the quota * * @param int $iSurveyId - Survey identification number * @param int $quotaid - quota id for which you want to compute the completed field * @return mixed - Integer of matching entries in the result DB or 'N/A' */ function getQuotaCompletedCount($iSurveyId, $quotaid) { $result = "N/A"; if(!tableExists("survey_{$iSurveyId}")) // Yii::app()->db->schema->getTable('{{survey_' . $iSurveyId . '}}' are not updated even after Yii::app()->db->schema->refresh(); return $result; $quota_info = getQuotaInformation($iSurveyId, Survey::model()->findByPk($iSurveyId)->language, $quotaid); $quota = $quota_info[0]; if (Yii::app()->db->schema->getTable('{{survey_' . $iSurveyId . '}}') && count($quota['members']) > 0) { // Keep a list of fields for easy reference $fields_list = array(); // Construct an array of value for each $quota['members']['fieldnames'] $fields_query = array(); foreach ($quota['members'] as $member) { $criteria = new CDbCriteria; foreach ($member['fieldnames'] as $fieldname) { if (!in_array($fieldname, $fields_list)) $fields_list[] = $fieldname; // Yii does not quote column names (duh!) so we have to do it. $criteria->addColumnCondition(array(Yii::app()->db->quoteColumnName($fieldname) => $member['value']), 'OR'); } $fields_query[$fieldname] = $criteria; } $criteria = new CDbCriteria; foreach ($fields_list as $fieldname) $criteria->mergeWith($fields_query[$fieldname]); $criteria->mergeWith(array('condition'=>"submitdate IS NOT NULL")); $result = SurveyDynamic::model($iSurveyId)->count($criteria); } return $result; } /** * Creates an array with details on a particular response for display purposes * Used in Print answers, Detailed response view and Detailed admin notification email * * @param mixed $iSurveyID * @param mixed $iResponseID * @param mixed $sLanguageCode * @param boolean $bHonorConditions Apply conditions */ function getFullResponseTable($iSurveyID, $iResponseID, $sLanguageCode, $bHonorConditions=true) { $aFieldMap = createFieldMap($iSurveyID,'full',false,false,$sLanguageCode); $oLanguage = new Limesurvey_lang($sLanguageCode); //Get response data $idrow = SurveyDynamic::model($iSurveyID)->findByAttributes(array('id'=>$iResponseID)); // Create array of non-null values - those are the relevant ones $aRelevantFields = array(); foreach ($aFieldMap as $sKey=>$fname) { if (LimeExpressionManager::QuestionIsRelevant($fname['qid']) || $bHonorConditions==false) { $aRelevantFields[$sKey]=$fname; } } $aResultTable=array(); $oldgid = 0; $oldqid = 0; foreach ($aRelevantFields as $sKey=>$fname) { if (!empty($fname['qid'])) { $attributes = getQuestionAttributeValues($fname['qid']); if (getQuestionAttributeValue($attributes, 'hidden') == 1) { continue; } } $question = $fname['question']; $subquestion=''; if (isset($fname['gid']) && !empty($fname['gid'])) { //Check to see if gid is the same as before. if not show group name if ($oldgid !== $fname['gid']) { $oldgid = $fname['gid']; if (LimeExpressionManager::GroupIsRelevant($fname['gid']) || $bHonorConditions==false) { $aResultTable['gid_'.$fname['gid']]=array($fname['group_name']); } } } if (!empty($fname['qid'])) { if ($oldqid !== $fname['qid']) { $oldqid = $fname['qid']; if (isset($fname['subquestion']) || isset($fname['subquestion1']) || isset($fname['subquestion2'])) { $aResultTable['qid_'.$fname['sid'].'X'.$fname['gid'].'X'.$fname['qid']]=array($fname['question'],'',''); } else { $answer = getExtendedAnswer($iSurveyID,$fname['fieldname'], $idrow[$fname['fieldname']],$oLanguage); $aResultTable[$fname['fieldname']]=array($question,'',$answer); continue; } } } else { $answer=getExtendedAnswer($iSurveyID,$fname['fieldname'], $idrow[$fname['fieldname']],$oLanguage); $aResultTable[$fname['fieldname']]=array($question,'',$answer); continue; } if (isset($fname['subquestion'])) $subquestion = "{$fname['subquestion']}"; if (isset($fname['subquestion1'])) $subquestion = "{$fname['subquestion1']}"; if (isset($fname['subquestion2'])) $subquestion .= "[{$fname['subquestion2']}]"; $answer = getExtendedAnswer($iSurveyID,$fname['fieldname'], $idrow[$fname['fieldname']],$oLanguage); $aResultTable[$fname['fieldname']]=array('',$subquestion,$answer); } return $aResultTable; } /** * Check if $str is an integer, or string representation of an integer * * @param mixed $mStr */ function isNumericInt($mStr) { if(is_int($mStr)) return true; elseif(is_string($mStr)) return preg_match("/^[0-9]+$/", $mStr); return false; } /** * Include Keypad headers */ function includeKeypad() { $clang = Yii::app()->lang; Yii::app()->getClientScript()->registerScriptFile(Yii::app()->getConfig('third_party').'jquery-keypad/jquery.keypad.min.js'); $localefile = Yii::app()->getConfig('rootdir').'/third_party/jquery-keypad/jquery.keypad-'.$clang->langcode.'.js'; if ($clang->langcode != 'en' && file_exists($localefile)) { Yii::app()->getClientScript()->registerScriptFile(Yii::app()->getConfig('third_party').'jquery-keypad/jquery.keypad-'.$clang->langcode.'.js'); } Yii::app()->getClientScript()->registerCssFile(Yii::app()->getConfig('third_party') . "jquery-keypad/jquery.keypad.alt.css"); } /** * getQuotaInformation() returns quota information for the current survey * @param string $surveyid - Survey identification number * @param string $language - Language of the quota * @param string $quotaid - Optional quotaid that restricts the result to a given quota * @return array - nested array, Quotas->Members->Fields */ function getQuotaInformation($surveyid,$language,$iQuotaID='all') { Yii::log('getQuotaInformation'); global $clienttoken; $baselang = Survey::model()->findByPk($surveyid)->language; $aAttributes=array('sid' => $surveyid); if ($iQuotaID != 'all') { $aAttributes['id'] = $iQuotaID; } $result = Quota::model()->with(array('languagesettings' => array('condition' => "quotals_language='$language'")))->findAllByAttributes($aAttributes); $quota_info = array(); $x=0; $surveyinfo=getSurveyInfo($surveyid,$language); // Check all quotas for the current survey //if ($result->RecordCount() > 0) if (count($result) > 0) { //while ($survey_quotas = $result->FetchRow()) foreach ($result as $_survey_quotas) { $survey_quotas = array_merge($_survey_quotas->attributes,$_survey_quotas->languagesettings[0]->attributes);// We have only one language, then we can use first only // !!! Doubting this # foreach ($_survey_quotas->defaultlanguage as $k => $v) # $survey_quotas[$k] = $v; array_push($quota_info,array('Name' => $survey_quotas['name'], 'Limit' => $survey_quotas['qlimit'], 'Action' => $survey_quotas['action'], 'Message' => $survey_quotas['quotals_message'], 'Url' => $survey_quotas['quotals_url'], 'UrlDescrip' => $survey_quotas['quotals_urldescrip'], 'AutoloadUrl' => $survey_quotas['autoload_url'])); $result_qe = QuotaMember::model()->findAllByAttributes(array('quota_id'=>$survey_quotas['id'])); $quota_info[$x]['members'] = array(); if (count($result_qe) > 0) { foreach ($result_qe as $quota_entry) { $quota_entry = $quota_entry->attributes; $result_quest=Question::model()->findByAttributes(array('qid'=>$quota_entry['qid'], 'language'=>$baselang)); $qtype=$result_quest->attributes; $fieldnames = "0"; if ($qtype['type'] == "I" || $qtype['type'] == "G" || $qtype['type'] == "Y") { $fieldnames=array(0 => $surveyid.'X'.$qtype['gid'].'X'.$quota_entry['qid']); $value = $quota_entry['code']; } if($qtype['type'] == "L" || $qtype['type'] == "O" || $qtype['type'] =="!") { $fieldnames=array(0 => $surveyid.'X'.$qtype['gid'].'X'.$quota_entry['qid']); $value = $quota_entry['code']; } if($qtype['type'] == "M") { $fieldnames=array(0 => $surveyid.'X'.$qtype['gid'].'X'.$quota_entry['qid'].$quota_entry['code']); $value = "Y"; } if($qtype['type'] == "A" || $qtype['type'] == "B") { $temp = explode('-',$quota_entry['code']); $fieldnames=array(0 => $surveyid.'X'.$qtype['gid'].'X'.$quota_entry['qid'].$temp[0]); $value = $temp[1]; } array_push($quota_info[$x]['members'],array('Title' => $qtype['title'], 'type' => $qtype['type'], 'code' => $quota_entry['code'], 'value' => $value, 'qid' => $quota_entry['qid'], 'fieldnames' => $fieldnames)); } } $x++; } } return $quota_info; } /** * This function replaces the old insertans tags with new ones across a survey * * @param string $newsid Old SID * @param string $oldsid New SID * @param mixed $fieldnames Array array('oldfieldname'=>'newfieldname') */ function translateInsertansTags($newsid,$oldsid,$fieldnames) { uksort($fieldnames, create_function('$a,$b', 'return strlen($a) < strlen($b);')); Yii::app()->loadHelper('database'); $newsid=sanitize_int($newsid); $oldsid=sanitize_int($oldsid); # translate 'surveyls_urldescription' and 'surveyls_url' INSERTANS tags in surveyls $sql = "SELECT surveyls_survey_id, surveyls_language, surveyls_urldescription, surveyls_url from {{surveys_languagesettings}} WHERE surveyls_survey_id=".$newsid." AND (surveyls_urldescription LIKE '%{$oldsid}X%' OR surveyls_url LIKE '%{$oldsid}X%')"; $result = dbExecuteAssoc($sql) or show_error("Can't read groups table in transInsertAns "); // Checked //while ($qentry = $res->FetchRow()) foreach ($result->readAll() as $qentry) { $urldescription = $qentry['surveyls_urldescription']; $endurl = $qentry['surveyls_url']; $language = $qentry['surveyls_language']; foreach ($fieldnames as $sOldFieldname=>$sNewFieldname) { $pattern = $sOldFieldname; $replacement = $sNewFieldname; $urldescription=preg_replace('/'.$pattern.'/', $replacement, $urldescription); $endurl=preg_replace('/'.$pattern.'/', $replacement, $endurl); } if (strcmp($urldescription,$qentry['surveyls_urldescription']) !=0 || (strcmp($endurl,$qentry['surveyls_url']) !=0)) { // Update Field $data = array( 'surveyls_urldescription' => $urldescription, 'surveyls_url' => $endurl ); $where = array( 'surveyls_survey_id' => $newsid, 'surveyls_language' => $language ); SurveyLanguageSetting::model()->updateRecord($data,$where); } // Enf if modified } // end while qentry # translate 'quotals_urldescrip' and 'quotals_url' INSERTANS tags in quota_languagesettings $sql = "SELECT quotals_id, quotals_urldescrip, quotals_url from {{quota_languagesettings}} qls, {{quota}} q WHERE sid=".$newsid." AND q.id=qls.quotals_quota_id AND (quotals_urldescrip LIKE '%{$oldsid}X%' OR quotals_url LIKE '%{$oldsid}X%')"; $result = dbExecuteAssoc($sql) or safeDie("Can't read quota table in transInsertAns"); // Checked foreach ($result->readAll() as $qentry) { $urldescription = $qentry['quotals_urldescrip']; $endurl = $qentry['quotals_url']; foreach ($fieldnames as $sOldFieldname=>$sNewFieldname) { $pattern = $sOldFieldname; $replacement = $sNewFieldname; $urldescription=preg_replace('/'.$pattern.'/', $replacement, $urldescription); $endurl=preg_replace('/'.$pattern.'/', $replacement, $endurl); } if (strcmp($urldescription,$qentry['quotals_urldescrip']) !=0 || (strcmp($endurl,$qentry['quotals_url']) !=0)) { // Update Field $sqlupdate = "UPDATE {{quota_languagesettings}} SET quotals_urldescrip='".$urldescription."', quotals_url='".$endurl."' WHERE quotals_id={$qentry['quotals_id']}"; $updateres=dbExecuteAssoc($sqlupdate) or safeDie ("Couldn't update INSERTANS in quota_languagesettings
      $sqlupdate
      "); //Checked } // Enf if modified } // end while qentry # translate 'description' INSERTANS tags in groups $sql = "SELECT gid, language, group_name, description from {{groups}} WHERE sid=".$newsid." AND description LIKE '%{$oldsid}X%' OR group_name LIKE '%{$oldsid}X%'"; $res = dbExecuteAssoc($sql) or show_error("Can't read groups table in transInsertAns"); // Checked //while ($qentry = $res->FetchRow()) foreach ($res->readAll() as $qentry) { $gpname = $qentry['group_name']; $description = $qentry['description']; $gid = $qentry['gid']; $language = $qentry['language']; foreach ($fieldnames as $sOldFieldname=>$sNewFieldname) { $pattern = $sOldFieldname; $replacement = $sNewFieldname; $gpname = preg_replace('/'.$pattern.'/', $replacement, $gpname); $description=preg_replace('/'.$pattern.'/', $replacement, $description); } if (strcmp($description,$qentry['description']) !=0 || strcmp($gpname,$qentry['group_name']) !=0) { // Update Fields $where = array( 'gid' => $gid, 'language' => $language ); $oGroup = QuestionGroup::model()->findByAttributes($where); $oGroup->description= $description; $oGroup->group_name= $gpname; $oGroup->save(); } // Enf if modified } // end while qentry # translate 'question' and 'help' INSERTANS tags in questions $sql = "SELECT qid, language, question, help from {{questions}} WHERE sid=".$newsid." AND (question LIKE '%{$oldsid}X%' OR help LIKE '%{$oldsid}X%')"; $result = dbExecuteAssoc($sql) or die("Can't read question table in transInsertAns "); // Checked //while ($qentry = $res->FetchRow()) $aResultData=$result->readAll() ; foreach ($aResultData as $qentry) { $question = $qentry['question']; $help = $qentry['help']; $qid = $qentry['qid']; $language = $qentry['language']; foreach ($fieldnames as $sOldFieldname=>$sNewFieldname) { $pattern = $sOldFieldname; $replacement = $sNewFieldname; $question=preg_replace('/'.$pattern.'/', $replacement, $question); $help=preg_replace('/'.$pattern.'/', $replacement, $help); } if (strcmp($question,$qentry['question']) !=0 || strcmp($help,$qentry['help']) !=0) { // Update Field $data = array( 'question' => $question, 'help' => $help ); $where = array( 'qid' => $qid, 'language' => $language ); Question::model()->updateByPk($where,$data); } // Enf if modified } // end while qentry # translate 'answer' INSERTANS tags in answers $result=Answer::model()->oldNewInsertansTags($newsid,$oldsid); //while ($qentry = $res->FetchRow()) foreach ($result as $qentry) { $answer = $qentry['answer']; $code = $qentry['code']; $qid = $qentry['qid']; $language = $qentry['language']; foreach ($fieldnames as $sOldFieldname=>$sNewFieldname) { $pattern = $sOldFieldname; $replacement = $sNewFieldname; $answer=preg_replace('/'.$pattern.'/', $replacement, $answer); } if (strcmp($answer,$qentry['answer']) !=0) { // Update Field $data = array( 'answer' => $answer, 'qid' => $qid ); $where = array( 'code' => $code, 'language' => $language ); Answer::model()->update($data,$where); } // Enf if modified } // end while qentry } /** * Replaces EM variable codes in a current survey with a new one * * @param mixed $iSurveyID The survey ID * @param mixed $aCodeMap The codemap array (old_code=>new_code) */ function replaceExpressionCodes ($iSurveyID, $aCodeMap) { $arQuestions=Question::model()->findAll("sid=:sid",array(':sid'=>$iSurveyID)); foreach ($arQuestions as $arQuestion) { $bModified=false; foreach ($aCodeMap as $sOldCode=>$sNewCode) { // Don't search/replace old codes that are too short or were numeric (because they would not have been usable in EM expressions anyway) if (strlen($sOldCode)>1 && !is_numeric($sOldCode[0])) { $sOldCode=preg_quote($sOldCode,'/'); $arQuestion->relevance=preg_replace("/\b{$sOldCode}/",$sNewCode,$arQuestion->relevance,-1,$iCount); $bModified = $bModified || $iCount; $arQuestion->question=preg_replace("/\b{$sOldCode}/",$sNewCode,$arQuestion->question,-1,$iCount); $bModified = $bModified || $iCount; } } if ($bModified) { $arQuestion->save(); } } $arGroups=QuestionGroup::model()->findAll("sid=:sid",array(':sid'=>$iSurveyID)); foreach ($arGroups as $arGroup) { $bModified=false; foreach ($aCodeMap as $sOldCode=>$sNewCode) { $sOldCode=preg_quote($sOldCode,'/'); $arGroup->grelevance=preg_replace("/\b{$sOldCode}/",$sNewCode,$arGroup->grelevance,-1,$iCount); $bModified = $bModified || $iCount; $arGroup->description=preg_replace("/\b{$sOldCode}/",$sNewCode,$arGroup->description,-1,$iCount); $bModified = $bModified || $iCount; } if ($bModified) { $arGroup->save(); } } } /** * This function is a replacement of accessDenied.php which return appropriate error message which is then displayed. * * @params string $action - action for which acces denied error message is to be returned * @params string sid - survey id * @return $accesssummary - proper access denied error message */ function accessDenied($action,$sid='') { $clang = Yii::app()->lang; if (Yii::app()->session['loginID']) { $ugid = Yii::app()->getConfig('ugid'); $accesssummary = "

      ".$clang->gT("Access denied!")."
      \n"; $scriptname = Yii::app()->getConfig('scriptname'); //$action=returnGlobal('action'); if ( $action == "dumpdb" ) { $accesssummary .= "

      ".$clang->gT("You are not allowed dump the database!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "dumplabel") { $accesssummary .= "

      ".$clang->gT("You are not allowed export a label set!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "edituser") { $accesssummary .= "

      ".$clang->gT("You are not allowed to change user data!"); $accesssummary .= "

      ".$clang->gT("Continue")."
       \n"; } elseif($action == "newsurvey") { $accesssummary .= "

      ".$clang->gT("You are not allowed to create new surveys!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "deletesurvey") { $accesssummary .= "

      ".$clang->gT("You are not allowed to delete this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "addquestion") { $accesssummary .= "

      ".$clang->gT("You are not allowed to add new questions for this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "activate") { $accesssummary .= "

      ".$clang->gT("You are not allowed to activate this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "deactivate") { $accesssummary .= "

      ".$clang->gT("You are not allowed to stop this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "addgroup") { $accesssummary .= "

      ".$clang->gT("You are not allowed to add a group to this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "ordergroups") { $link = Yii::app()->getController()->createUrl("/admin/survey/sa/view/surveyid/$sid"); $accesssummary .= "

      ".$clang->gT("You are not allowed to order groups in this survey!")."
      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "editsurvey") { $link = Yii::app()->getController()->createUrl("/admin/survey/sa/view/surveyid/$sid"); $accesssummary .= "

      ".$clang->gT("You are not allowed to edit this survey!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "editgroup") { $accesssummary .= "

      ".$clang->gT("You are not allowed to edit groups in this survey!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "browse_response" || $action == "listcolumn" || $action == "vvexport" || $action == "vvimport") { $accesssummary .= "

      ".$clang->gT("You are not allowed to browse responses!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "assessment") { $accesssummary .= "

      ".$clang->gT("You are not allowed to set assessment rules!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "delusergroup") { $accesssummary .= "

      ".$clang->gT("You are not allowed to delete this group!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "importsurvey") { $accesssummary .= "

      ".$clang->gT("You are not allowed to import a survey!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "importgroup") { $accesssummary .= "

      ".$clang->gT("You are not allowed to import a group!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "importquestion") { $accesssummary .= "

      ".$clang->gT("You are not allowed to to import a question!")."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "CSRFwarn") //won't be used. { $sURLID=''; if (isset($sid)) { $sURLID="?sid={$sid}"; } $accesssummary .= "

      ".$clang->gT("Security alert").": ".$clang->gT("Someone may be trying to use your LimeSurvey session (CSRF attack suspected). If you just clicked on a malicious link, please report this to your system administrator.").'
      '.$clang->gT('Also this problem can occur when you are working/editing in LimeSurvey in several browser windows/tabs at the same time.')."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } elseif($action == "FakeGET") { $accesssummary .= "

      ".$clang->gT("Security alert").": ".$clang->gT("Someone may be trying to use your LimeSurvey session (CSRF attack suspected). If you just clicked on a malicious link, please report this to your system administrator.").'
      '.$clang->gT('Also this problem can occur when you are working/editing in LimeSurvey in several browser windows/tabs at the same time.')."

      "; $accesssummary .= "".$clang->gT("Continue")."
       \n"; } else { $accesssummary .= "
      ".$clang->gT("You are not allowed to perform this operation!")."
      \n"; if(!empty($sid)) { $accesssummary .= "

      ".$clang->gT("Continue")."
       \n"; } else { $accesssummary .= "

      ".$clang->gT("Continue")."
       \n"; } } return $accesssummary; } } /** * cleanLanguagesFromSurvey() removes any languages from survey tables that are not in the passed list * @param string $sid - the currently selected survey * @param string $availlangs - space separated list of additional languages in survey * @return bool - always returns true */ function cleanLanguagesFromSurvey($sid, $availlangs) { Yii::app()->loadHelper('database'); //$clang = Yii::app()->lang; $sid=sanitize_int($sid); $baselang = Survey::model()->findByPk($sid)->language; if (!empty($availlangs) && $availlangs != " ") { $availlangs=sanitize_languagecodeS($availlangs); $langs = explode(" ",$availlangs); if($langs[count($langs)-1] == "") array_pop($langs); } $sqllang = "language <> '".$baselang."' "; if (!empty($availlangs) && $availlangs != " ") { foreach ($langs as $lang) { $sqllang .= "AND language <> '".$lang."' "; } } // Remove From Answer Table $query = "SELECT qid FROM {{questions}} WHERE sid='{$sid}' AND $sqllang"; $qidresult = dbExecuteAssoc($query); foreach ($qidresult->readAll() as $qrow) { $myqid = $qrow['qid']; $query = "DELETE FROM {{answers}} WHERE qid='$myqid' AND $sqllang"; dbExecuteAssoc($query); } // Remove From Questions Table $query = "DELETE FROM {{questions}} WHERE sid='{$sid}' AND $sqllang"; dbExecuteAssoc($query); // Remove From QuestionGroup Table $query = "DELETE FROM {{groups}} WHERE sid='{$sid}' AND $sqllang"; dbExecuteAssoc($query); return true; } /** * fixLanguageConsistency() fixes missing groups, questions, answers, quotas & assessments for languages on a survey * @param string $sid - the currently selected survey * @param string $availlangs - space separated list of additional languages in survey - if empty all additional languages of a survey are checked against the base language * @return bool - always returns true */ function fixLanguageConsistency($sid, $availlangs='') { $sid=sanitize_int($sid); $clang = Yii::app()->lang; if (trim($availlangs)!='') { $availlangs=sanitize_languagecodeS($availlangs); $langs = explode(" ",$availlangs); if($langs[count($langs)-1] == "") array_pop($langs); } else { $langs=Survey::model()->findByPk($sid)->additionalLanguages; } if (count($langs)==0) return true; // Survey only has one language $baselang = Survey::model()->findByPk($sid)->language; $query = "SELECT * FROM {{groups}} WHERE sid='{$sid}' AND language='{$baselang}' ORDER BY group_order"; $result = Yii::app()->db->createCommand($query)->query(); foreach($result->readAll() as $group) { foreach ($langs as $lang) { $query = "SELECT count(gid) FROM {{groups}} WHERE sid='{$sid}' AND gid='{$group['gid']}' AND language='{$lang}'"; $gresult = Yii::app()->db->createCommand($query)->queryScalar(); if ($gresult < 1) { $data = array( 'gid' => $group['gid'], 'sid' => $group['sid'], 'group_name' => $group['group_name'], 'group_order' => $group['group_order'], 'description' => $group['description'], 'randomization_group' => $group['randomization_group'], 'grelevance' => $group['grelevance'], 'language' => $lang ); switchMSSQLIdentityInsert('groups',true); Yii::app()->db->createCommand()->insert('{{groups}}', $data); switchMSSQLIdentityInsert('groups',false); } } reset($langs); } $quests = array(); $query = "SELECT * FROM {{questions}} WHERE sid='{$sid}' AND language='{$baselang}' ORDER BY question_order"; $result = Yii::app()->db->createCommand($query)->query()->readAll(); if (count($result) > 0) { foreach($result as $question) { array_push($quests,$question['qid']); foreach ($langs as $lang) { $query = "SELECT count(qid) FROM {{questions}} WHERE sid='{$sid}' AND qid='{$question['qid']}' AND language='{$lang}' AND scale_id={$question['scale_id']}"; $gresult = Yii::app()->db->createCommand($query)->queryScalar(); if ($gresult < 1) { switchMSSQLIdentityInsert('questions',true); $data = array( 'qid' => $question['qid'], 'sid' => $question['sid'], 'gid' => $question['gid'], 'type' => $question['type'], 'title' => $question['title'], 'question' => $question['question'], 'preg' => $question['preg'], 'help' => $question['help'], 'other' => $question['other'], 'mandatory' => $question['mandatory'], 'question_order' => $question['question_order'], 'language' => $lang, 'scale_id' => $question['scale_id'], 'parent_qid' => $question['parent_qid'], 'relevance' => $question['relevance'] ); Yii::app()->db->createCommand()->insert('{{questions}}', $data); } } reset($langs); } $sqlans = ""; foreach ($quests as $quest) { $sqlans .= " OR qid = '".$quest."' "; } $query = "SELECT * FROM {{answers}} WHERE language='{$baselang}' and (".trim($sqlans,' OR').") ORDER BY qid, code"; $result = Yii::app()->db->createCommand($query)->query(); foreach($result->readAll() as $answer) { foreach ($langs as $lang) { $query = "SELECT count(qid) FROM {{answers}} WHERE code='{$answer['code']}' AND qid='{$answer['qid']}' AND language='{$lang}' AND scale_id={$answer['scale_id']}"; $gresult = Yii::app()->db->createCommand($query)->queryScalar(); if ($gresult < 1) { $data = array( 'qid' => $answer['qid'], 'code' => $answer['code'], 'answer' => $answer['answer'], 'scale_id' => $answer['scale_id'], 'sortorder' => $answer['sortorder'], 'language' => $lang, 'assessment_value' => $answer['assessment_value'] ); Yii::app()->db->createCommand()->insert('{{answers}}', $data); } } reset($langs); } } $query = "SELECT * FROM {{assessments}} WHERE sid='{$sid}' AND language='{$baselang}'"; $result = Yii::app()->db->createCommand($query)->query(); foreach($result->readAll() as $assessment) { foreach ($langs as $lang) { $query = "SELECT count(id) FROM {{assessments}} WHERE sid='{$sid}' AND id='{$assessment['id']}' AND language='{$lang}'"; $gresult = Yii::app()->db->createCommand($query)->queryScalar(); if ($gresult < 1) { $data = array( 'id' => $assessment['id'], 'sid' => $assessment['sid'], 'scope' => $assessment['scope'], 'gid' => $assessment['gid'], 'name' => $assessment['name'], 'minimum' => $assessment['minimum'], 'maximum' => $assessment['maximum'], 'message' => $assessment['message'], 'language' => $lang ); Yii::app()->db->createCommand()->insert('{{assessments}}', $data); } } reset($langs); } $query = "SELECT * FROM {{quota_languagesettings}} join {{quota}} q on quotals_quota_id=q.id WHERE q.sid='{$sid}' AND quotals_language='{$baselang}'"; $result = Yii::app()->db->createCommand($query)->query(); foreach($result->readAll() as $qls) { foreach ($langs as $lang) { $query = "SELECT count(quotals_id) FROM {{quota_languagesettings}} WHERE quotals_quota_id='{$qls['quotals_quota_id']}' AND quotals_language='{$lang}'"; $gresult = Yii::app()->db->createCommand($query)->queryScalar(); if ($gresult < 1) { $data = array( 'quotals_quota_id' => $qls['quotals_quota_id'], 'quotals_name' => $qls['quotals_name'], 'quotals_message' => $qls['quotals_message'], 'quotals_url' => $qls['quotals_url'], 'quotals_urldescrip' => $qls['quotals_urldescrip'], 'quotals_language' => $lang ); Yii::app()->db->createCommand()->insert('{{quota_languagesettings}}', $data); } } reset($langs); } return true; } /** * This function switches identity insert on/off for the MSSQL database * * @param string $table table name (without prefix) * @param mixed $state Set to true to activate ID insert, or false to deactivate */ function switchMSSQLIdentityInsert($table,$state) { if (in_array(Yii::app()->db->getDriverName(), array('mssql', 'sqlsrv', 'dblib'))) { if ($state == true) { // This needs to be done directly on the PDO object because when using CdbCommand or similar it won't have any effect Yii::app()->db->pdoInstance->exec('SET IDENTITY_INSERT '.Yii::app()->db->tablePrefix.$table.' ON'); } else { // This needs to be done directly on the PDO object because when using CdbCommand or similar it won't have any effect Yii::app()->db->pdoInstance->exec('SET IDENTITY_INSERT '.Yii::app()->db->tablePrefix.$table.' OFF'); } } } /** * Retrieves the last Insert ID realiable for cross-DB applications * * @param string $sTableName Needed for Postgres and MSSQL */ function getLastInsertID($sTableName) { $sDBDriver=Yii::app()->db->getDriverName(); if ($sDBDriver=='mysql' || $sDBDriver=='mysqli') { return Yii::app()->db->getLastInsertID(); } else { return Yii::app()->db->getCommandBuilder()->getLastInsertID($sTableName); } } // TMSW Condition->Relevance: This function is not needed? Optionally replace this with call to EM to get similar info /** * getGroupDepsForConditions() get Dependencies between groups caused by conditions * @param string $sid - the currently selected survey * @param string $depgid - (optionnal) get only the dependencies applying to the group with gid depgid * @param string $targgid - (optionnal) get only the dependencies for groups dependents on group targgid * @param string $index-by - (optionnal) "by-depgid" for result indexed with $res[$depgid][$targgid] * "by-targgid" for result indexed with $res[$targgid][$depgid] * @return array - returns an array describing the conditions or NULL if no dependecy is found * * Example outupt assumin $index-by="by-depgid": *Array *( * [125] => Array // Group Id 125 is dependent on * ( * [123] => Array // Group Id 123 * ( * [depgpname] => G3 // GID-125 has name G3 * [targetgpname] => G1 // GID-123 has name G1 * [conditions] => Array * ( * [189] => Array // Because Question Id 189 * ( * [0] => 9 // Have condition 9 set * [1] => 10 // and condition 10 set * [2] => 14 // and condition 14 set * ) * * ) * * ) * * [124] => Array // GID 125 is also dependent on GID 124 * ( * [depgpname] => G3 * [targetgpname] => G2 * [conditions] => Array * ( * [189] => Array // Because Question Id 189 have conditions set * ( * [0] => 11 * ) * * [215] => Array // And because Question Id 215 have conditions set * ( * [0] => 12 * ) * * ) * * ) * * ) * *) * * Usage example: * * Get all group dependencies for SID $sid indexed by depgid: * $result=getGroupDepsForConditions($sid); * * Get all group dependencies for GID $gid in survey $sid indexed by depgid: * $result=getGroupDepsForConditions($sid,$gid); * * Get all group dependents on group $gid in survey $sid indexed by targgid: * $result=getGroupDepsForConditions($sid,"all",$gid,"by-targgid"); */ function getGroupDepsForConditions($sid,$depgid="all",$targgid="all",$indexby="by-depgid") { $sid=sanitize_int($sid); $condarray = Array(); $sqldepgid=""; $sqltarggid=""; if ($depgid != "all") { $depgid = sanitize_int($depgid); $sqldepgid="AND tq.gid=$depgid";} if ($targgid != "all") {$targgid = sanitize_int($targgid); $sqltarggid="AND tq2.gid=$targgid";} $baselang = Survey::model()->findByPk($sid)->language; $condquery = "SELECT tg.gid as depgid, tg.group_name as depgpname, " . "tg2.gid as targgid, tg2.group_name as targgpname, tq.qid as depqid, tc.cid FROM " . "{{conditions}} AS tc, " . "{{questions}} AS tq, " . "{{questions}} AS tq2, " . "{{groups}} AS tg ," . "{{groups}} AS tg2 " . "WHERE tq.language='{$baselang}' AND tq2.language='{$baselang}' AND tg.language='{$baselang}' AND tg2.language='{$baselang}' AND tc.qid = tq.qid AND tq.sid=$sid " . "AND tq.gid = tg.gid AND tg2.gid = tq2.gid " . "AND tq2.qid=tc.cqid AND tq.gid != tg2.gid $sqldepgid $sqltarggid"; $condresult = Yii::app()->db->createCommand($condquery)->query()->readAll(); if (count($condresult) > 0) { foreach ($condresult as $condrow) { switch ($indexby) { case "by-depgid": $depgid=$condrow['depgid']; $targetgid=$condrow['targgid']; $depqid=$condrow['depqid']; $cid=$condrow['cid']; $condarray[$depgid][$targetgid]['depgpname'] = $condrow['depgpname']; $condarray[$depgid][$targetgid]['targetgpname'] = $condrow['targgpname']; $condarray[$depgid][$targetgid]['conditions'][$depqid][]=$cid; break; case "by-targgid": $depgid=$condrow['depgid']; $targetgid=$condrow['targgid']; $depqid=$condrow['depqid']; $cid=$condrow['cid']; $condarray[$targetgid][$depgid]['depgpname'] = $condrow['depgpname']; $condarray[$targetgid][$depgid]['targetgpname'] = $condrow['targgpname']; $condarray[$targetgid][$depgid]['conditions'][$depqid][] = $cid; break; } } return $condarray; } return null; } // TMSW Condition->Relevance: This function is not needed? Optionally replace this with call to EM to get similar info /** * getQuestDepsForConditions() get Dependencies between groups caused by conditions * @param string $sid - the currently selected survey * @param string $gid - (optionnal) only search dependecies inside the Group Id $gid * @param string $depqid - (optionnal) get only the dependencies applying to the question with qid depqid * @param string $targqid - (optionnal) get only the dependencies for questions dependents on question Id targqid * @param string $index-by - (optionnal) "by-depqid" for result indexed with $res[$depqid][$targqid] * "by-targqid" for result indexed with $res[$targqid][$depqid] * @return array - returns an array describing the conditions or NULL if no dependecy is found * * Example outupt assumin $index-by="by-depqid": *Array *( * [184] => Array // Question Id 184 * ( * [183] => Array // Depends on Question Id 183 * ( * [0] => 5 // Because of condition Id 5 * ) * * ) * *) * * Usage example: * * Get all questions dependencies for Survey $sid and group $gid indexed by depqid: * $result=getQuestDepsForConditions($sid,$gid); * * Get all questions dependencies for question $qid in survey/group $sid/$gid indexed by depqid: * $result=getGroupDepsForConditions($sid,$gid,$qid); * * Get all questions dependents on question $qid in survey/group $sid/$gid indexed by targqid: * $result=getGroupDepsForConditions($sid,$gid,"all",$qid,"by-targgid"); */ function getQuestDepsForConditions($sid,$gid="all",$depqid="all",$targqid="all",$indexby="by-depqid", $searchscope="samegroup") { $clang = Yii::app()->lang; $condarray = Array(); $baselang = Survey::model()->findByPk($sid)->language; $sqlgid=""; $sqldepqid=""; $sqltargqid=""; $sqlsearchscope=""; if ($gid != "all") {$gid = sanitize_int($gid); $sqlgid="AND tq.gid=$gid";} if ($depqid != "all") {$depqid = sanitize_int($depqid); $sqldepqid="AND tq.qid=$depqid";} if ($targqid != "all") {$targqid = sanitize_int($targqid); $sqltargqid="AND tq2.qid=$targqid";} if ($searchscope == "samegroup") {$sqlsearchscope="AND tq2.gid=tq.gid";} $condquery = "SELECT tq.qid as depqid, tq2.qid as targqid, tc.cid FROM {{conditions}} AS tc, {{questions}} AS tq, {{questions}} AS tq2 WHERE tq.language='{$baselang}' AND tq2.language='{$baselang}' AND tc.qid = tq.qid AND tq.sid='$sid' AND tq2.qid=tc.cqid $sqlsearchscope $sqlgid $sqldepqid $sqltargqid"; $condresult=Yii::app()->db->createCommand($condquery)->query()->readAll(); if (count($condresult) > 0) { foreach ($condresult as $condrow) { $depqid=$condrow['depqid']; $targetqid=$condrow['targqid']; $condid=$condrow['cid']; switch ($indexby) { case "by-depqid": $condarray[$depqid][$targetqid][] = $condid; break; case "by-targqid": $condarray[$targetqid][$depqid][] = $condid; break; } } return $condarray; } return null; } // TMSW Condition->Relevance: This function is not needed - could replace with a message from EM output. /** * checkMoveQuestionConstraintsForConditions() * @param string $sid - the currently selected survey * @param string $qid - qid of the question you want to check possible moves * @param string $newgid - (optionnal) get only constraints when trying to move to this particular GroupId * otherwise, get all moves constraints for this question * * @return array - returns an array describing the conditions * Array * ( * ['notAbove'] = null | Array * ( * Array ( gid1, group_order1, qid1, cid1 ) * ) * ['notBelow'] = null | Array * ( * Array ( gid2, group_order2, qid2, cid2 ) * ) * ) * * This should be read as: * - this question can't be move above group gid1 in position group_order1 because of the condition cid1 on question qid1 * - this question can't be move below group gid2 in position group_order2 because of the condition cid2 on question qid2 * */ function checkMoveQuestionConstraintsForConditions($sid,$qid,$newgid="all") { $clang = Yii::app()->lang; $resarray=Array(); $resarray['notAbove']=null; // defaults to no constraint $resarray['notBelow']=null; // defaults to no constraint $sid=sanitize_int($sid); $qid=sanitize_int($qid); if ($newgid != "all") { $newgid=sanitize_int($newgid); $newgorder=getGroupOrder($sid,$newgid); } else { $neworder=""; // Not used in this case } $baselang = Survey::model()->findByPk($sid)->language; // First look for 'my dependencies': questions on which I have set conditions $condquery = "SELECT tq.qid as depqid, tq.gid as depgid, tg.group_order as depgorder, " . "tq2.qid as targqid, tq2.gid as targgid, tg2.group_order as targgorder, " . "tc.cid FROM " . "{{conditions}} AS tc, " . "{{questions}} AS tq, " . "{{questions}} AS tq2, " . "{{groups}} AS tg, " . "{{groups}} AS tg2 " . "WHERE tq.language='{$baselang}' AND tq2.language='{$baselang}' AND tc.qid = tq.qid AND tq.sid=$sid " . "AND tq2.qid=tc.cqid AND tg.gid=tq.gid AND tg2.gid=tq2.gid AND tq.qid=$qid ORDER BY tg2.group_order DESC"; $condresult=Yii::app()->db->createCommand($condquery)->query(); foreach ($condresult->readAll() as $condrow ) { // This Question can go up to the minimum GID on the 1st row $depqid=$condrow['depqid']; $depgid=$condrow['depgid']; $depgorder=$condrow['depgorder']; $targetqid=$condrow['targqid']; $targetgid=$condrow['targgid']; $targetgorder=$condrow['targgorder']; $condid=$condrow['cid']; //echo "This question can't go above to GID=$targetgid/order=$targetgorder because of CID=$condid"; if ($newgid != "all") { // Get only constraints when trying to move to this group if ($newgorder < $targetgorder) { $resarray['notAbove'][]=Array($targetgid,$targetgorder,$depqid,$condid); } } else { // get all moves constraints $resarray['notAbove'][]=Array($targetgid,$targetgorder,$depqid,$condid); } } // Secondly look for 'questions dependent on me': questions that have conditions on my answers $condquery = "SELECT tq.qid as depqid, tq.gid as depgid, tg.group_order as depgorder, " . "tq2.qid as targqid, tq2.gid as targgid, tg2.group_order as targgorder, " . "tc.cid FROM {{conditions}} AS tc, " . "{{questions}} AS tq, " . "{{questions}} AS tq2, " . "{{groups}} AS tg, " . "{{groups}} AS tg2 " . "WHERE tq.language='{$baselang}' AND tq2.language='{$baselang}' AND tc.qid = tq.qid AND tq.sid=$sid " . "AND tq2.qid=tc.cqid AND tg.gid=tq.gid AND tg2.gid=tq2.gid AND tq2.qid=$qid ORDER BY tg.group_order"; $condresult=Yii::app()->db->createCommand($condquery)->query(); foreach ($condresult->readAll() as $condrow) { // This Question can go down to the maximum GID on the 1st row $depqid=$condrow['depqid']; $depgid=$condrow['depgid']; $depgorder=$condrow['depgorder']; $targetqid=$condrow['targqid']; $targetgid=$condrow['targgid']; $targetgorder=$condrow['targgorder']; $condid=$condrow['cid']; //echo "This question can't go below to GID=$depgid/order=$depgorder because of CID=$condid"; if ($newgid != "all") { // Get only constraints when trying to move to this group if ($newgorder > $depgorder) { $resarray['notBelow'][]=Array($depgid,$depgorder,$depqid,$condid); } } else { // get all moves constraints $resarray['notBelow'][]=Array($depgid,$depgorder,$depqid,$condid); } } return $resarray; } function getUserGroupList($ugid=NULL,$outputformat='optionlist') { $clang = Yii::app()->lang; //$squery = "SELECT ugid, name FROM ".db_table_name('user_groups') ." WHERE owner_id = {Yii::app()->session['loginID']} ORDER BY name"; $sQuery = "SELECT distinct a.ugid, a.name, a.owner_id FROM {{user_groups}} AS a LEFT JOIN {{user_in_groups}} AS b ON a.ugid = b.ugid WHERE 1=1 "; if (!Permission::model()->hasGlobalPermission('superadmin','read')) { $sQuery .="AND uid = ".Yii::app()->session['loginID']; } $sQuery .= " ORDER BY name"; $sresult = Yii::app()->db->createCommand($sQuery)->query(); //Checked if (!$sresult) {return "Database Error";} $selecter = ""; foreach ($sresult->readAll() as $row) { $groupnames[] = $row; } //$groupnames = $sresult->GetRows(); $simplegidarray=array(); if (isset($groupnames)) { foreach($groupnames as $gn) { $selecter .= "\n"; $simplegidarray[] = $gn['ugid']; } } if (!isset($svexist)) {$selecter = "\n".$selecter;} //else {$selecter = "\n".$selecter;} if ($outputformat == 'simplegidarray') { return $simplegidarray; } else { return $selecter; } } function getGroupUserList($ugid) { Yii::app()->loadHelper('database'); $clang = Yii::app()->lang; $ugid=sanitize_int($ugid); $surveyidquery = "SELECT a.uid, a.users_name, a.full_name FROM {{users}} AS a LEFT JOIN (SELECT uid AS id FROM {{user_in_groups}} WHERE ugid = {$ugid}) AS b ON a.uid = b.id WHERE id IS NULL ORDER BY a.users_name"; $surveyidresult = dbExecuteAssoc($surveyidquery); //Checked if (!$surveyidresult) {return "Database Error";} $surveyselecter = ""; foreach ($surveyidresult->readAll() as $row) { $surveynames[] = $row; } //$surveynames = $surveyidresult->GetRows(); if (isset($surveynames)) { foreach($surveynames as $sv) { $surveyselecter .= "gT("Please choose...")."\n".$surveyselecter; return $surveyselecter; } /** * Run an arbitrary sequence of semicolon-delimited SQL commands * * Assumes that the input text (file or string) consists of * a number of SQL statements ENDING WITH SEMICOLONS. The * semicolons MUST be the last character in a line. * Lines that are blank or that start with "#" or "--" (postgres) are ignored. * Only tested with mysql dump files (mysqldump -p -d limesurvey) * Function kindly borrowed by Moodle * @param string $sqlfile The path where a file with sql commands can be found on the server. * @param string $sqlstring If no path is supplied then a string with semicolon delimited sql * commands can be supplied in this argument. * @return bool Returns true if database was modified successfully. */ function modifyDatabase($sqlfile='', $sqlstring='') { Yii::app()->loadHelper('database'); $clang = Yii::app()->lang; global $siteadminemail; global $siteadminname; global $codeString; global $modifyoutput; $success = true; // Let's be optimistic $modifyoutput=''; if (!empty($sqlfile)) { if (!is_readable($sqlfile)) { $success = false; echo '

      Tried to modify database, but "'. $sqlfile .'" doesn\'t exist!

      '; return $success; } else { $lines = file($sqlfile); } } else { $sqlstring = trim($sqlstring); if ($sqlstring{strlen($sqlstring)-1} != ";") { $sqlstring .= ";"; // add it in if it's not there. } $lines[] = $sqlstring; } $command = ''; foreach ($lines as $line) { $line = rtrim($line); $length = strlen($line); if ($length and $line[0] <> '#' and substr($line,0,2) <> '--') { if (substr($line, $length-1, 1) == ';') { $line = substr($line, 0, $length-1); // strip ; $command .= $line; $command = str_replace('prefix_', Yii::app()->db->tablePrefix, $command); // Table prefixes $command = str_replace('$defaultuser', Yii::app()->getConfig('defaultuser'), $command); $command = str_replace('$defaultpass', hash('sha256',Yii::app()->getConfig('defaultpass')), $command); $command = str_replace('$siteadminname', $siteadminname, $command); $command = str_replace('$siteadminemail', $siteadminemail, $command); $command = str_replace('$defaultlang', Yii::app()->getConfig('defaultlang'), $command); $command = str_replace('$databasetabletype', Yii::app()->db->getDriverName(), $command); try { Yii::app()->db->createCommand($command)->query(); //Checked $command=htmlspecialchars($command); $modifyoutput .=". "; } catch(CDbException $e) { $command=htmlspecialchars($command); $modifyoutput .="
      ".sprintf($clang->gT("SQL command failed: %s"),"".$command."","
      "); $success = false; } $command = ''; } else { $command .= $line; } } } return $success; } /** * Returns labelsets for given language(s), or for all if null * * @param string $languages * @return array */ function getLabelSets($languages = null) { $clang = Yii::app()->lang; $languagesarray = array(); if ($languages) { $languages=sanitize_languagecodeS($languages); $languagesarray=explode(' ',trim($languages)); } $criteria = new CDbCriteria; $criteria->order = "label_name"; foreach ($languagesarray as $k => $item) { $criteria->params[':lang_like1_' . $k] = "% $item %"; $criteria->params[':lang_' . $k] = $item; $criteria->params[':lang_like2_' . $k] = "% $item"; $criteria->params[':lang_like3_' . $k] = "$item %"; $criteria->addCondition(" ((languages like :lang_like1_$k) or (languages = :lang_$k) or (languages like :lang_like2_$k) or (languages like :lang_like3_$k))"); } $result = LabelSet::model()->findAll($criteria); $labelsets=array(); foreach ($result as $row) $labelsets[] = array($row->lid, $row->label_name); return $labelsets; } function getHeader($meta = false) { global $embedded,$surveyid ; Yii::app()->loadHelper('surveytranslator'); // Set Langage // TODO remove one of the Yii::app()->session see bug #5901 if (Yii::app()->session['survey_'.$surveyid]['s_lang'] ) { $languagecode = Yii::app()->session['survey_'.$surveyid]['s_lang']; } elseif (isset($surveyid) && $surveyid && Survey::model()->findByPk($surveyid)) { $languagecode=Survey::model()->findByPk($surveyid)->language; } else { $languagecode = Yii::app()->getConfig('defaultlang'); } $header= "\n" . "getConfig('adminscripts').'printablesurvey.js"> '; return $headelements; } // This function returns the Footer as result string // If you want to echo the Footer use doFooter() ! function getFooter() { global $embedded; if ( !$embedded ) { return "\n\n\t\n\n"; } global $embedded_footerfunc; if ( function_exists( $embedded_footerfunc ) ) return $embedded_footerfunc(); } function doFooter() { echo getFooter(); } function getDBTableUsage($surveyid){ Yii::app()->loadHelper('admin/activate'); $arrCols = activateSurvey($surveyid,$surveyid,'admin.php',true); $length = 1; foreach ($arrCols['fields'] as $col){ switch ($col[0]){ case 'C': $length = $length + ($col[1]*3) + 1; break; case 'X': case 'B': $length = $length + 12; break; case 'D': $length = $length + 3; break; case 'T': case 'TS': case 'N': $length = $length + 8; break; case 'L': $legth++; break; case 'I': case 'I4': case 'F': $length = $length + 4; break; case 'I1': $length = $length + 1; break; case 'I2': $length = $length + 2; break; case 'I8': $length = $length + 8; break; } } if ($arrCols['dbtype'] == 'mysql' || $arrCols['dbtype'] == 'mysqli'){ if ($arrCols['dbengine']=='myISAM'){ $hard_limit = 4096; } elseif ($arrCols['dbengine'] == "InnoDB"){ $hard_limit = 1000; } else{ return false; } $size_limit = 65535; } elseif ($arrCols['dbtype'] == 'postgre'){ $hard_limit = 1600; $size_limit = 0; } elseif ($arrCols['dbtype'] == 'mssql' || $arrCols['dbtype'] == 'dblib'){ $hard_limit = 1024; $size_limit = 0; } else{ return false; } $columns_used = count($arrCols['fields']); return (array( 'dbtype'=>$arrCols['dbtype'], 'column'=>array($columns_used,$hard_limit) , 'size' => array($length, $size_limit) )); } /** * Checks that each object from an array of CSV data [question-rows,answer-rows,labelsets-row] supports at least a given language * * @param mixed $csvarray array with a line of csv data per row * @param mixed $idkeysarray array of integers giving the csv-row numbers of the object keys * @param mixed $langfieldnum integer giving the csv-row number of the language(s) filed * ==> the language field can be a single language code or a * space separated language code list * @param mixed $langcode the language code to be tested * @param mixed $hasheader if we should strip off the first line (if it contains headers) */ function doesImportArraySupportLanguage($csvarray,$idkeysarray,$langfieldnum,$langcode, $hasheader = false) { // An array with one row per object id and langsupport status as value $objlangsupportarray=Array(); if ($hasheader === true ) { // stripping first row to skip headers if any array_shift($csvarray); } foreach ($csvarray as $csvrow) { $rowcontents = convertCSVRowToArray($csvrow,',','"'); $rowid = ""; foreach ($idkeysarray as $idfieldnum) { $rowid .= $rowcontents[$idfieldnum]."-"; } $rowlangarray = explode (" ", @$rowcontents[$langfieldnum]); if (!isset($objlangsupportarray[$rowid])) { if (array_search($langcode,$rowlangarray)!== false) { $objlangsupportarray[$rowid] = "true"; } else { $objlangsupportarray[$rowid] = "false"; } } else { if ($objlangsupportarray[$rowid] == "false" && array_search($langcode,$rowlangarray) !== false) { $objlangsupportarray[$rowid] = "true"; } } } // end foreach rown // If any of the object doesn't support the given language, return false if (array_search("false",$objlangsupportarray) === false) { return true; } else { return false; } } /** * Retrieve a HTML \n".$surveyselecter;} else {$surveyselecter = "\n".$surveyselecter;} return $surveyselecter; } function getSurveyUserGroupList($outputformat='htmloptions',$surveyid) { $clang = Yii::app()->lang; $surveyid=sanitize_int($surveyid); $surveyidquery = "SELECT a.ugid, a.name, MAX(d.ugid) AS da FROM {{user_groups}} AS a LEFT JOIN ( SELECT b.ugid FROM {{user_in_groups}} AS b LEFT JOIN (SELECT * FROM {{permissions}} WHERE entity_id = {$surveyid} and entity='survey') AS c ON b.uid = c.uid WHERE c.uid IS NULL ) AS d ON a.ugid = d.ugid GROUP BY a.ugid, a.name HAVING MAX(d.ugid) IS NOT NULL"; $surveyidresult = Yii::app()->db->createCommand($surveyidquery)->query(); //Checked $aResult=$surveyidresult->readAll(); $surveyselecter = ""; if (Yii::app()->getConfig('usercontrolSameGroupPolicy') == true) { $authorizedGroupsList=getUserGroupList(NULL, 'simplegidarray'); } foreach($aResult as $sv) { if (Yii::app()->getConfig('usercontrolSameGroupPolicy') == false || in_array($sv['ugid'],$authorizedGroupsList)) { $surveyselecter .= "gT("Please choose...")."\n".$surveyselecter;} else {$surveyselecter = "\n".$surveyselecter;} if ($outputformat == 'simpleugidarray') { return $simpleugidarray; } else { return $surveyselecter; } } /** * This function fixes the group ID and type on all subquestions * */ function fixSubquestions() { $surveyidresult=Yii::app()->db->createCommand("select sq.qid, sq.parent_qid, sq.gid as sqgid, q.gid, sq.type as sqtype, q.type from {{questions}} sq JOIN {{questions}} q on sq.parent_qid=q.qid where sq.parent_qid>0 and (sq.gid!=q.gid or sq.type!=q.type)")->query(); foreach($surveyidresult->readAll() as $sv) { Yii::app()->db->createCommand("update {{questions}} set type='{$sv['type']}', gid={$sv['gid']} where qid={$sv['qid']}")->query(); } } /** * Must use ls_json_encode to json_encode content, otherwise LimeExpressionManager will think that the associative arrays are expressions and try to parse them. */ function ls_json_encode($content) { $ans = json_encode($content); $ans = str_replace(array('{','}'),array('{ ',' }'), $ans); return $ans; } /** * Decode a json string, sometimes needs stripslashes * * @param type $jsonString * @return type */ function json_decode_ls($jsonString) { $decoded = json_decode($jsonString, true); if (is_null($decoded) && !empty($jsonString)) { // probably we need stipslahes $decoded = json_decode(stripslashes($jsonString), true); } return $decoded; } /** * Return accepted codingsArray for importing files * * Used in vvimport * TODO : use in token and * @return array */ function aEncodingsArray() { $clang = Yii::app()->lang; return array( "armscii8" => $clang->gT("ARMSCII-8 Armenian"), "ascii" => $clang->gT("US ASCII"), "auto" => $clang->gT("Automatic"), "big5" => $clang->gT("Big5 Traditional Chinese"), "binary" => $clang->gT("Binary pseudo charset"), "cp1250" => $clang->gT("Windows Central European (Windows-1250)"), "cp1251" => $clang->gT("Windows Cyrillic (Windows-1251)"), "cp1256" => $clang->gT("Windows Arabic (Windows-1256)"), "cp1257" => $clang->gT("Windows Baltic (Windows-1257)"), "cp850" => $clang->gT("DOS West European (cp850)"), "cp852" => $clang->gT("DOS Central European (cp852)"), "cp866" => $clang->gT("DOS Cyrillic (cp866)"), "cp932" => $clang->gT("Windows-31J - SJIS for Windows Japanese (cp932)"), "dec8" => $clang->gT("DEC West European"), "eucjpms" => $clang->gT("UJIS for Windows Japanese"), "euckr" => $clang->gT("EUC-KR Korean"), "gb2312" => $clang->gT("GB2312 Simplified Chinese"), "gbk" => $clang->gT("GBK Simplified Chinese"), "geostd8" => $clang->gT("GEOSTD8 Georgian"), "greek" => $clang->gT("ISO 8859-7 Greek"), "hebrew" => $clang->gT("ISO 8859-8 Hebrew"), "hp8" => $clang->gT("HP West European"), "keybcs2" => $clang->gT("DOS Kamenicky Czech-Slovak (cp895)"), "koi8r" => $clang->gT("KOI8-R Relcom Russian"), "koi8u" => $clang->gT("KOI8-U Ukrainian"), "latin1" => $clang->gT("ISO 8859-1 West European (latin1)"), "latin2" => $clang->gT("ISO 8859-2 Central European (latin2)"), "latin5" => $clang->gT("ISO 8859-9 Turkish (latin5)"), "latin7" => $clang->gT("ISO 8859-13 Baltic (latin7)"), "macce" => $clang->gT("Mac Central European"), "macroman" => $clang->gT("Mac West European"), "sjis" => $clang->gT("Shift-JIS Japanese"), "swe7" => $clang->gT("7bit Swedish"), "tis620" => $clang->gT("TIS620 Thai"), "ucs2" => $clang->gT("UCS-2 Unicode"), "ujis" => $clang->gT("EUC-JP Japanese"), "utf8" => $clang->gT("UTF-8 Unicode"), ); } /** * Swaps two positions in an array * * @param mixed $key1 * @param mixed $key2 * @param mixed $array */ function arraySwapAssoc($key1, $key2, $array) { $newArray = array (); foreach ($array as $key => $value) { if ($key == $key1) { $newArray[$key2] = $array[$key2]; } elseif ($key == $key2) { $newArray[$key1] = $array[$key1]; } else { $newArray[$key] = $value; } } return $newArray; } /** * Ellipsize String * * This public static function will strip tags from a string, split it at its max_length and ellipsize * * @param string string to ellipsize * @param integer max length of string * @param mixed int (1|0) or float, .5, .2, etc for position to split * @param string ellipsis ; Default '...' * @return string ellipsized string */ function ellipsize($sString, $iMaxLength, $fPosition = 1, $sEllipsis = '…') { // Strip tags $sString = trim(strip_tags($sString)); // Is the string long enough to ellipsize? if (mb_strlen($sString,'UTF-8') <= $iMaxLength+3) { return $sString; } $iStrLen=mb_strlen($sString,'UTF-8'); $sBegin = mb_substr($sString, 0, floor($iMaxLength * $fPosition),'UTF-8'); $sEnd = mb_substr($sString,$iStrLen-($iMaxLength-mb_strlen($sBegin,'UTF-8')),$iStrLen,'UTF-8'); return $sBegin.$sEllipsis.$sEnd; } /** * This function returns the real IP address under all configurations * */ function getIPAddress() { if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet { $sIPAddress=$_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy { $sIPAddress= $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (!empty($_SERVER['REMOTE_ADDR'])) { $sIPAddress= $_SERVER['REMOTE_ADDR']; } else { $sIPAddress= '127.0.0.1'; } if (!filter_var($sIPAddress, FILTER_VALIDATE_IP)) { return 'Invalid'; } else { return $sIPAddress; } } /** * This function tries to find out a valid language code for the language of the browser used * If it cannot find it it will return the default language from global settings * */ function getBrowserLanguage() { $sLanguage=Yii::app()->getRequest()->getPreferredLanguage(); Yii::app()->loadHelper("surveytranslator"); $aLanguages=getLanguageData(); if (!isset($aLanguages[$sLanguage])) { $sLanguage=str_replace('_','-',$sLanguage); if (!isset($aLanguages[$sLanguage])) { $sLanguage=substr($sLanguage,0,strpos($sLanguage,'-')); if (!isset($aLanguages[$sLanguage])) { $sLanguage=Yii::app()->getConfig('defaultlang'); } } } return $sLanguage; } function array_diff_assoc_recursive($array1, $array2) { $difference=array(); foreach($array1 as $key => $value) { if( is_array($value) ) { if( !isset($array2[$key]) || !is_array($array2[$key]) ) { $difference[$key] = $value; } else { $new_diff = array_diff_assoc_recursive($value, $array2[$key]); if( !empty($new_diff) ) $difference[$key] = $new_diff; } } else if( !array_key_exists($key,$array2) || $array2[$key] !== $value ) { $difference[$key] = $value; } } return $difference; } function convertPHPSizeToBytes($sSize) { //This function transforms the php.ini notation for numbers (like '2M') to an integer (2*1024*1024 in this case) $sSuffix = substr($sSize, -1); $iValue = substr($sSize, 0, -1); switch(strtoupper($sSuffix)){ case 'P': $iValue *= 1024; case 'T': $iValue *= 1024; case 'G': $iValue *= 1024; case 'M': $iValue *= 1024; case 'K': $iValue *= 1024; break; } return $iValue; } function getMaximumFileUploadSize() { return min(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize'))); } // Closing PHP tag intentionally omitted - yes, it is okay