1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/limesurvey_ynh.git synced 2024-09-03 19:36:32 +02:00
limesurvey_ynh/sources/application/helpers/export_helper.php

1853 lines
71 KiB
PHP

<?php
/*
* LimeSurvey
* Copyright (C) 2007-2011 The LimeSurvey Project Team / Carsten Schmitz
* All rights reserved.
* License: GNU/GPL License v2 or later, see LICENSE.php
* LimeSurvey is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*
*/
/**
* Strips html tags and replaces new lines
*
* @param $string
* @return $string
*/
function stripTagsFull($string) {
$string=html_entity_decode($string, ENT_QUOTES, "UTF-8");
//combining these into one mb_ereg_replace call ought to speed things up
$string = str_replace(array("\r\n","\r","\n",'-oth-'), '', $string);
//The backslashes must be escaped twice, once for php, and again for the regexp
$string = str_replace("'|\\\\'", "&apos;", $string);
return flattenText($string);
}
/**
* Returns true if passed $value is numeric
*
* @param $value
* @return bool
*/
function isNumericExtended($value) {
if (empty($value)) return true;
$eng_or_world = preg_match
('/^[+-]?'. // start marker and sign prefix
'(((([0-9]+)|([0-9]{1,4}(,[0-9]{3,4})+)))?(\\.[0-9])?([0-9]*)|'. // american
'((([0-9]+)|([0-9]{1,4}(\\.[0-9]{3,4})+)))?(,[0-9])?([0-9]*))'. // world
'(e[0-9]+)?'. // exponent
'$/', // end marker
$value) == 1;
return ($eng_or_world);
}
/**
* Returns splitted unicode string correctly
* source: http://www.php.net/manual/en/function.str-split.php#107658
*
* @param $str
* @param $l
* @return string
*/
function strSplitUnicode($str, $l = 0) {
if ($l > 0)
{
$ret = array();
$len = mb_strlen($str, "UTF-8");
for ($i = 0; $i < $len; $i += $l)
{
$ret[] = mb_substr($str, $i, $l, "UTF-8");
}
return $ret;
}
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* Exports CSV response data for SPSS and R
*
* @param mixed $iSurveyID The survey ID
* @param mixed $iLength Maximum text lenght data, usually 255 for SPSS <v16 and 16384 for SPSS 16 and later
* @param mixed $na Value for N/A data
* @param sep Quote separator. Use '\'' for SPSS, '"' for R
* @param logical $header If TRUE, adds SQGA code as column headings (used by export to R)
*/
function SPSSExportData ($iSurveyID, $iLength, $na = '', $q='\'', $header=FALSE) {
// Build array that has to be returned
$fields = SPSSFieldMap($iSurveyID);
// Now see if we have parameters for from (offset) & num (limit)
$limit = App()->getRequest()->getParam('limit');
$offset = App()->getRequest()->getParam('offset');
//Now get the query string with all fields to export
$query = SPSSGetQuery($iSurveyID, $limit, $offset);
$result = $query->query();
$rownr = 0;
foreach ($result as $row) {
$rownr++;
if ($rownr == 1) {
$num_fields = count($row);
//This shouldn't occur, but just to be safe:
if (count($fields)<>$num_fields) safeDie("Database inconsistency error");
// Add column headers (used by R export)
if($header==TRUE)
{
$i = 1;
foreach ($fields as $field) {
if (!$field['hide'] ) echo $q.strtoupper($field['sql_name']).$q;
if ($i<$num_fields && !$field['hide']) echo ',';
$i++;
}
echo("\n");
}
}
$row = array_change_key_case($row,CASE_UPPER);
//$row = $result->GetRowAssoc(true); //Get assoc array, use uppercase
reset($fields); //Jump to the first element in the field array
$i = 1;
foreach ($fields as $field)
{
$fieldno = strtoupper($field['sql_name']);
if ($field['SPSStype']=='DATETIME23.2'){
#convert mysql datestamp (yyyy-mm-dd hh:mm:ss) to SPSS datetime (dd-mmm-yyyy hh:mm:ss) format
if (isset($row[$fieldno]))
{
list( $year, $month, $day, $hour, $minute, $second ) = preg_split( '([^0-9])', $row[$fieldno] );
if ($year != '' && (int)$year >= 1900)
{
echo $q.date('d-m-Y H:i:s', mktime( $hour, $minute, $second, $month, $day, $year ) ).$q;
} else
{
echo ($na);
}
} else
{
echo ($na);
}
} else if ($field['LStype'] == 'Y')
{
if ($row[$fieldno] == 'Y') // Yes/No Question Type
{
echo( $q. 1 .$q);
} else if ($row[$fieldno] == 'N'){
echo( $q. 2 .$q);
} else {
echo($na);
}
} else if ($field['LStype'] == 'G') //Gender
{
if ($row[$fieldno] == 'F')
{
echo( $q. 1 .$q);
} else if ($row[$fieldno] == 'M'){
echo( $q. 2 .$q);
} else {
echo($na);
}
} else if ($field['LStype'] == 'C') //Yes/No/Uncertain
{
if ($row[$fieldno] == 'Y')
{
echo( $q. 1 .$q);
} else if ($row[$fieldno] == 'N'){
echo( $q. 2 .$q);
} else if ($row[$fieldno] == 'U'){
echo( $q. 3 .$q);
} else {
echo($na);
}
} else if ($field['LStype'] == 'E') //Increase / Same / Decrease
{
if ($row[$fieldno] == 'I')
{
echo( $q. 1 .$q);
} else if ($row[$fieldno] == 'S'){
echo( $q. 2 .$q);
} else if ($row[$fieldno] == 'D'){
echo( $q. 3 .$q);
} else {
echo($na);
}
} elseif (($field['LStype'] == 'P' || $field['LStype'] == 'M') && (substr($field['code'],-7) != 'comment' && substr($field['code'],-5) != 'other'))
{
if ($row[$fieldno] == 'Y')
{
echo($q. 1 .$q);
} else
{
echo($q. 0 .$q);
}
} elseif (!$field['hide']) {
$strTmp=mb_substr(stripTagsFull($row[$fieldno]), 0, $iLength);
if (trim($strTmp) != ''){
if($q=='\'') $strTemp=str_replace(array("'","\n","\r"),array("''",' ',' '),trim($strTmp));
if($q=='"') $strTemp=str_replace(array('"',"\n","\r"),array('""',' ',' '),trim($strTmp));
/*
* Temp quick fix for replacing decimal dots with comma's
if (isNumericExtended($strTemp)) {
$strTemp = str_replace('.',',',$strTemp);
}
*/
echo $q. $strTemp .$q ;
}
else
{
echo $na;
}
}
if ($i<$num_fields && !$field['hide']) echo ',';
$i++;
}
echo "\n";
}
}
/**
* Check it the gives field has a labelset and return it as an array if true
*
* @param $field array field from SPSSFieldMap
* @return array or false
*/
function SPSSGetValues ($field = array(), $qidattributes = null, $language ) {
$length_vallabel = 120;
$clang = Yii::app()->lang;
if (!isset($field['LStype']) || empty($field['LStype'])) return false;
$answers=array();
if (strpos("!LORFWZWH1",$field['LStype']) !== false) {
if (substr($field['code'],-5) == 'other' || substr($field['code'],-7) == 'comment') {
//We have a comment field, so free text
} else {
$query = "SELECT {{answers}}.code, {{answers}}.answer,
{{questions}}.type FROM {{answers}}, {{questions}} WHERE";
if (isset($field['scale_id'])) $query .= " {{answers}}.scale_id = " . (int) $field['scale_id'] . " AND";
$query .= " {{answers}}.qid = '".$field["qid"]."' and {{questions}}.language='".$language."' and {{answers}}.language='".$language."'
and {{questions}}.qid='".$field['qid']."' ORDER BY sortorder ASC";
$result= Yii::app()->db->createCommand($query)->query()->readAll(); //Checked
$num_results = count($result);
if ($num_results > 0)
{
$displayvaluelabel = 0;
# Build array that has to be returned
foreach ($result as $row)
{
$answers[] = array('code'=>$row['code'], 'value'=>mb_substr(stripTagsFull($row["answer"]),0,$length_vallabel));
}
}
}
} elseif ($field['LStype'] == ':') {
$displayvaluelabel = 0;
//Get the labels that could apply!
if (is_null($qidattributes)) $qidattributes=getQuestionAttributeValues($field["qid"], $field['LStype']);
if (trim($qidattributes['multiflexible_max'])!='') {
$maxvalue=$qidattributes['multiflexible_max'];
} else {
$maxvalue=10;
}
if (trim($qidattributes['multiflexible_min'])!='')
{
$minvalue=$qidattributes['multiflexible_min'];
} else {
$minvalue=1;
}
if (trim($qidattributes['multiflexible_step'])!='')
{
$stepvalue=$qidattributes['multiflexible_step'];
} else {
$stepvalue=1;
}
if ($qidattributes['multiflexible_checkbox']!=0) {
$minvalue=0;
$maxvalue=1;
$stepvalue=1;
}
for ($i=$minvalue; $i<=$maxvalue; $i+=$stepvalue)
{
$answers[] = array('code'=>$i, 'value'=>$i);
}
} elseif ($field['LStype'] == 'M' && substr($field['code'],-5) != 'other' && $field['size'] > 0)
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Yes'));
$answers[] = array('code'=>0, 'value'=>$clang->gT('Not Selected'));
} elseif ($field['LStype'] == "P" && substr($field['code'],-5) != 'other' && substr($field['code'],-7) != 'comment')
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Yes'));
$answers[] = array('code'=>0, 'value'=>$clang->gT('Not Selected'));
} elseif ($field['LStype'] == "G" && $field['size'] > 0)
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Female'));
$answers[] = array('code'=>2, 'value'=>$clang->gT('Male'));
} elseif ($field['LStype'] == "Y" && $field['size'] > 0)
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Yes'));
$answers[] = array('code'=>2, 'value'=>$clang->gT('No'));
} elseif ($field['LStype'] == "C" && $field['size'] > 0)
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Yes'));
$answers[] = array('code'=>2, 'value'=>$clang->gT('No'));
$answers[] = array('code'=>3, 'value'=>$clang->gT('Uncertain'));
} elseif ($field['LStype'] == "E" && $field['size'] > 0)
{
$answers[] = array('code'=>1, 'value'=>$clang->gT('Increase'));
$answers[] = array('code'=>2, 'value'=>$clang->gT('Same'));
$answers[] = array('code'=>3, 'value'=>$clang->gT('Decrease'));
}
if (count($answers)>0) {
//check the max width of the answers
$size = 0;
$spsstype = $field['SPSStype'];
foreach ($answers as $answer) {
$len = mb_strlen($answer['code']);
if ($len>$size) $size = $len;
if ($spsstype=='F' && (isNumericExtended($answer['code'])===false || $size>16)) $spsstype='A';
}
$answers['SPSStype'] = $spsstype;
$answers['size'] = $size;
return $answers;
} else {
return false;
}
}
/**
* Creates a fieldmap with all information necessary to output the fields
*
* @param $prefix string prefix for the variable ID
* @return array
*/
function SPSSFieldMap($iSurveyID, $prefix = 'V') {
global $clang, $surveyprivate;
$typeMap = array(
'5'=>Array('name'=>'5 Point Choice','size'=>1,'SPSStype'=>'F','Scale'=>3),
'B'=>Array('name'=>'Array (10 Point Choice)','size'=>1,'SPSStype'=>'F','Scale'=>3),
'A'=>Array('name'=>'Array (5 Point Choice)','size'=>1,'SPSStype'=>'F','Scale'=>3),
'F'=>Array('name'=>'Array (Flexible Labels)','size'=>1,'SPSStype'=>'F'),
'1'=>Array('name'=>'Array (Flexible Labels) Dual Scale','size'=>1,'SPSStype'=>'F'),
'H'=>Array('name'=>'Array (Flexible Labels) by Column','size'=>1,'SPSStype'=>'F'),
'E'=>Array('name'=>'Array (Increase, Same, Decrease)','size'=>1,'SPSStype'=>'F','Scale'=>2),
'C'=>Array('name'=>'Array (Yes/No/Uncertain)','size'=>1,'SPSStype'=>'F'),
'X'=>Array('name'=>'Boilerplate Question','size'=>1,'SPSStype'=>'A','hide'=>1),
'D'=>Array('name'=>'Date','size'=>20,'SPSStype'=>'DATETIME23.2'),
'G'=>Array('name'=>'Gender','size'=>1,'SPSStype'=>'F'),
'U'=>Array('name'=>'Huge Free Text','size'=>1,'SPSStype'=>'A'),
'I'=>Array('name'=>'Language Switch','size'=>1,'SPSStype'=>'A'),
'!'=>Array('name'=>'List (Dropdown)','size'=>1,'SPSStype'=>'F'),
'W'=>Array('name'=>'List (Flexible Labels) (Dropdown)','size'=>1,'SPSStype'=>'F'),
'Z'=>Array('name'=>'List (Flexible Labels) (Radio)','size'=>1,'SPSStype'=>'F'),
'L'=>Array('name'=>'List (Radio)','size'=>1,'SPSStype'=>'F'),
'O'=>Array('name'=>'List With Comment','size'=>1,'SPSStype'=>'F'),
'T'=>Array('name'=>'Long free text','size'=>1,'SPSStype'=>'A'),
'K'=>Array('name'=>'Multiple Numerical Input','size'=>1,'SPSStype'=>'F'),
'M'=>Array('name'=>'Multiple choice','size'=>1,'SPSStype'=>'F'),
'P'=>Array('name'=>'Multiple choice with comments','size'=>1,'SPSStype'=>'F'),
'Q'=>Array('name'=>'Multiple Short Text','size'=>1,'SPSStype'=>'F'),
'N'=>Array('name'=>'Numerical Input','size'=>3,'SPSStype'=>'F','Scale'=>3),
'R'=>Array('name'=>'Ranking','size'=>1,'SPSStype'=>'F'),
'S'=>Array('name'=>'Short free text','size'=>1,'SPSStype'=>'F'),
'Y'=>Array('name'=>'Yes/No','size'=>1,'SPSStype'=>'F'),
':'=>Array('name'=>'Multi flexi numbers','size'=>1,'SPSStype'=>'F','Scale'=>3),
';'=>Array('name'=>'Multi flexi text','size'=>1,'SPSStype'=>'A'),
'|'=>Array('name'=>'File upload','size'=>1,'SPSStype'=>'A'),
'*'=>Array('name'=>'Equation','size'=>1,'SPSStype'=>'A'),
);
$fieldmap = createFieldMap($iSurveyID,'full',false,false,getBaseLanguageFromSurveyID($iSurveyID));
#See if tokens are being used
$bTokenTableExists = tableExists('tokens_'.$iSurveyID);
#Lookup the names of the attributes
$query="SELECT sid, anonymized, language FROM {{surveys}} WHERE sid=$iSurveyID";
$aRow=Yii::app()->db->createCommand($query)->queryRow(); //Checked
$surveyprivate=$aRow['anonymized'];
$language=$aRow['language'];
$fieldno=0;
$fields=array();
if ($bTokenTableExists && $surveyprivate == 'N' && Permission::model()->hasSurveyPermission($iSurveyID,'tokens','read')) {
$tokenattributes=getTokenFieldsAndNames($iSurveyID,false);
foreach ($tokenattributes as $attributefield=>$attributedescription)
{
//Drop the token field, since it is in the survey too
if($attributefield!='token') {
$fieldno++;
$fields[] = array('id'=>"$prefix$fieldno",'name'=>mb_substr($attributefield, 0, 8),
'qid'=>0,'code'=>'','SPSStype'=>'A','LStype'=>'Undef',
'VariableLabel'=>$attributedescription['description'],'sql_name'=>$attributefield,'size'=>'100',
'title'=>$attributefield,'hide'=>0, 'scale'=>'');
}
}
}
$tempArray = array();
$fieldnames = Yii::app()->db->schema->getTable("{{survey_$iSurveyID}}")->getColumnNames();
$num_results = count($fieldnames);
$num_fields = $num_results;
$diff = 0;
$noQID = Array('id', 'token', 'datestamp', 'submitdate', 'startdate', 'startlanguage', 'ipaddr', 'refurl', 'lastpage');
# Build array that has to be returned
for ($i=0; $i < $num_results; $i++) {
#Condition for SPSS fields:
# - Length may not be longer than 8 characters
# - Name may not begin with a digit
$fieldname = $fieldnames[$i];
$fieldtype = '';
$ftype='';
$val_size = 1;
$hide = 0;
$export_scale = '';
$code='';
$scale_id = null;
$aQuestionAttribs=array();
#Determine field type
if ($fieldname=='submitdate' || $fieldname=='startdate' || $fieldname == 'datestamp') {
$fieldtype = 'DATETIME23.2';
} elseif ($fieldname=='startlanguage') {
$fieldtype = 'A';
$val_size = 19;
} elseif ($fieldname=='token') {
$fieldtype = 'A';
$val_size = 16;
} elseif ($fieldname=='id') {
$fieldtype = 'F';
$val_size = 7; //Arbitrarilty restrict to 9,999,999 (7 digits) responses/survey
} elseif ($fieldname == 'ipaddr') {
$fieldtype = 'A';
$val_size = 15;
} elseif ($fieldname == 'refurl') {
$fieldtype = 'A';
$val_size = 255;
} elseif ($fieldname == 'lastpage') {
$fieldtype = 'F';
$val_size = 7; //Arbitrarilty restrict to 9,999,999 (7 digits) pages
}
#Get qid (question id)
if (in_array($fieldname, $noQID) || substr($fieldname,0,10)=='attribute_'){
$qid = 0;
$varlabel = $fieldname;
$ftitle = $fieldname;
} else{
//GET FIELD DATA
if (!isset($fieldmap[$fieldname])) {
//Field in database but no longer in survey... how is this possible?
//@TODO: think of a fix.
$fielddata = array();
$qid=0;
$varlabel = $fieldname;
$ftitle = $fieldname;
$fieldtype = "F";
$val_size = 1;
} else {
$fielddata=$fieldmap[$fieldname];
$qid=$fielddata['qid'];
$ftype=$fielddata['type'];
$fsid=$fielddata['sid'];
$fgid=$fielddata['gid'];
$code=mb_substr($fielddata['fieldname'],strlen($fsid."X".$fgid."X".$qid));
$varlabel=$fielddata['question'];
if (isset($fielddata['scale'])) $varlabel = "[{$fielddata['scale']}] ". $varlabel;
if (isset($fielddata['subquestion'])) $varlabel = "[{$fielddata['subquestion']}] ". $varlabel;
if (isset($fielddata['subquestion2'])) $varlabel = "[{$fielddata['subquestion2']}] ". $varlabel;
if (isset($fielddata['subquestion1'])) $varlabel = "[{$fielddata['subquestion1']}] ". $varlabel;
$ftitle=$fielddata['title'];
if (!is_null($code) && $code<>"" ) $ftitle .= "_$code";
if (isset($typeMap[$ftype]['size'])) $val_size = $typeMap[$ftype]['size'];
if (isset($fielddata['scale_id'])) $scale_id = $fielddata['scale_id'];
if($fieldtype == '') $fieldtype = $typeMap[$ftype]['SPSStype'];
if (isset($typeMap[$ftype]['hide'])) {
$hide = $typeMap[$ftype]['hide'];
$diff++;
}
//Get default scale for this type
if (isset($typeMap[$ftype]['Scale'])) $export_scale = $typeMap[$ftype]['Scale'];
//But allow override
$aQuestionAttribs = getQuestionAttributeValues($qid,$ftype);
if (isset($aQuestionAttribs['scale_export'])) $export_scale = $aQuestionAttribs['scale_export'];
}
}
$fieldno++;
$fid = $fieldno - $diff;
$lsLong = isset($typeMap[$ftype]["name"])?$typeMap[$ftype]["name"]:$ftype;
$tempArray = array('id'=>"$prefix$fid",'name'=>mb_substr($fieldname, 0, 8),
'qid'=>$qid,'code'=>$code,'SPSStype'=>$fieldtype,'LStype'=>$ftype,"LSlong"=>$lsLong,
'ValueLabels'=>'','VariableLabel'=>$varlabel,"sql_name"=>$fieldname,"size"=>$val_size,
'title'=>$ftitle,'hide'=>$hide,'scale'=>$export_scale, 'scale_id'=>$scale_id);
//Now check if we have to retrieve value labels
$answers = SPSSGetValues($tempArray, $aQuestionAttribs, $language);
if (is_array($answers)) {
//Ok we have answers
if (isset($answers['size'])) {
$tempArray['size'] = $answers['size'];
unset($answers['size']);
}
if (isset($answers['SPSStype'])) {
$tempArray['SPSStype'] = $answers['SPSStype'];
unset($answers['SPSStype']);
}
$tempArray['answers'] = $answers;
}
$fields[] = $tempArray;
}
return $fields;
}
/**
* Creates a query string with all fields for the export
* @param
* @return CDbCommand
*/
function SPSSGetQuery($iSurveyID, $limit = null, $offset = null) {
$bDataAnonymized=(Survey::model()->findByPk($iSurveyID)->anonymized=='Y');
$tokensexist=tableExists('tokens_'.$iSurveyID);
#See if tokens are being used
$query = App()->db->createCommand();
$query->from('{{survey_' . $iSurveyID . '}} s');
$columns = array('s.*');
if (isset($tokensexist) && $tokensexist == true && !$bDataAnonymized && Permission::model()->hasSurveyPermission($iSurveyID,'tokens','read')) {
$tokenattributes=array_keys(getTokenFieldsAndNames($iSurveyID,false));
foreach ($tokenattributes as $attributefield) {
//Drop the token field, since it is in the survey too
if($attributefield!='token') {
$columns[] = 't.' . $attributefield;
}
}
$query->leftJoin('{{tokens_' . $iSurveyID . '}} t', App()->db->quoteColumnName('s.token') . ' = ' . App()->db->quoteColumnName('t.token'));
//LEFT JOIN {{tokens_$iSurveyID}} t ON ";
}
$query->select($columns);
switch (incompleteAnsFilterState()) {
case 'incomplete':
//Inclomplete answers only
$query->where('s.submitdate IS NULL');
break;
case 'complete':
//Inclomplete answers only
$query->where('s.submitdate IS NOT NULL');
break;
}
if (!empty($limit) & !is_null($offset))
{
$query->limit((int) $limit, (int) $offset);
}
return $query;
}
/**
* buildXMLFromQuery() creates a datadump of a table in XML using XMLWriter
*
* @param mixed $xmlwriter The existing XMLWriter object
* @param mixed $Query The table query to build from
* @param mixed $tagname If the XML tag of the resulting question should be named differently than the table name set it here
* @param array $excludes array of columnames not to include in export
*/
function buildXMLFromQuery($xmlwriter, $Query, $tagname='', $excludes = array())
{
$iChunkSize=3000; // This works even for very large result sets and leaves a minimal memory footprint
preg_match('/\bfrom\b\s*{{(\w+)}}/i', $Query, $MatchResults);
if ($tagname!='')
{
$TableName=$tagname;
}
else
{
$TableName = $MatchResults[1];
}
// Read table in smaller chunks
$iStart=0;
do
{
$QueryResult = Yii::app()->db->createCommand($Query)->limit($iChunkSize, $iStart)->query();
$result = $QueryResult->readAll();
if ($iStart==0 && count($result)>0)
{
$exclude = array_flip($excludes); //Flip key/value in array for faster checks
$xmlwriter->startElement($TableName);
$xmlwriter->startElement('fields');
$aColumninfo = array_keys($result[0]);
foreach ($aColumninfo as $fieldname)
{
if (!isset($exclude[$fieldname])) $xmlwriter->writeElement('fieldname',$fieldname);
}
$xmlwriter->endElement(); // close columns
$xmlwriter->startElement('rows');
}
foreach($result as $Row)
{
$xmlwriter->startElement('row');
foreach ($Row as $Key=>$Value)
{
if (!isset($exclude[$Key])) {
if(!(is_null($Value))) // If the $value is null don't output an element at all
{
if (is_numeric($Key[0])) $Key='_'.$Key; // mask invalid element names with an underscore
$Key=str_replace('#','-',$Key);
if (!$xmlwriter->startElement($Key)) safeDie('Invalid element key: '.$Key);
// Remove invalid XML characters
if ($Value!=='') {
$Value=str_replace(']]>','',$Value);
$xmlwriter->writeCData(preg_replace('/[^\x9\xA\xD\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u','',$Value));
}
$xmlwriter->endElement();
}
}
}
$xmlwriter->endElement(); // close row
}
$iStart=$iStart+$iChunkSize;
} while (count($result)==$iChunkSize);
if (count($result)>0)
{
$xmlwriter->endElement(); // close rows
$xmlwriter->endElement(); // close tablename
}
}
/**
* from export_structure_xml.php
*/
function surveyGetXMLStructure($iSurveyID, $xmlwriter, $exclude=array())
{
$sdump = "";
if (!isset($exclude['answers']))
{
//Answer table
$aquery = "SELECT {{answers}}.*
FROM {{answers}}, {{questions}}
WHERE {{answers}}.language={{questions}}.language
AND {{answers}}.qid={{questions}}.qid
AND {{questions}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$aquery);
}
// Assessments
$query = "SELECT {{assessments}}.*
FROM {{assessments}}
WHERE {{assessments}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$query);
if (!isset($exclude['conditions']))
{
//Condition table
$cquery = "SELECT DISTINCT {{conditions}}.*
FROM {{conditions}}, {{questions}}
WHERE {{conditions}}.qid={{questions}}.qid
AND {{questions}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$cquery);
}
//Default values
$query = "SELECT {{defaultvalues}}.*
FROM {{defaultvalues}} JOIN {{questions}} ON {{questions}}.qid = {{defaultvalues}}.qid AND {{questions}}.sid=$iSurveyID AND {{questions}}.language={{defaultvalues}}.language ";
buildXMLFromQuery($xmlwriter,$query);
// QuestionGroup
$gquery = "SELECT *
FROM {{groups}}
WHERE sid=$iSurveyID
ORDER BY gid";
buildXMLFromQuery($xmlwriter,$gquery);
//Questions
$qquery = "SELECT *
FROM {{questions}}
WHERE sid=$iSurveyID and parent_qid=0
ORDER BY qid";
buildXMLFromQuery($xmlwriter,$qquery);
//Subquestions
$qquery = "SELECT *
FROM {{questions}}
WHERE sid=$iSurveyID and parent_qid>0
ORDER BY qid";
buildXMLFromQuery($xmlwriter,$qquery,'subquestions');
//Question attributes
$sBaseLanguage=Survey::model()->findByPk($iSurveyID)->language;
$platform = Yii::app()->db->getDriverName();
if ($platform == 'mssql' || $platform =='sqlsrv' || $platform =='dblib')
{
$query="SELECT qa.qid, qa.attribute, cast(qa.value as varchar(4000)) as value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, cast(qa.value as varchar(4000)), qa.language";
}
else {
$query="SELECT qa.qid, qa.attribute, qa.value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, qa.value, qa.language";
}
buildXMLFromQuery($xmlwriter,$query,'question_attributes');
if (!isset($exclude['quotas']))
{
//Quota
$query = "SELECT {{quota}}.*
FROM {{quota}}
WHERE {{quota}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$query);
//1Quota members
$query = "SELECT {{quota_members}}.*
FROM {{quota_members}}
WHERE {{quota_members}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$query);
//Quota languagesettings
$query = "SELECT {{quota_languagesettings}}.*
FROM {{quota_languagesettings}}, {{quota}}
WHERE {{quota}}.id = {{quota_languagesettings}}.quotals_quota_id
AND {{quota}}.sid=$iSurveyID";
buildXMLFromQuery($xmlwriter,$query);
}
// Surveys
$squery = "SELECT *
FROM {{surveys}}
WHERE sid=$iSurveyID";
//Exclude some fields from the export
buildXMLFromQuery($xmlwriter,$squery,'',array('owner_id','active','datecreated'));
// Survey language settings
$slsquery = "SELECT *
FROM {{surveys_languagesettings}}
WHERE surveyls_survey_id=$iSurveyID";
buildXMLFromQuery($xmlwriter,$slsquery);
// Survey url parameters
$slsquery = "SELECT *
FROM {{survey_url_parameters}}
WHERE sid={$iSurveyID}";
buildXMLFromQuery($xmlwriter,$slsquery);
}
/**
* from export_structure_xml.php
*/
function surveyGetXMLData($iSurveyID, $exclude = array())
{
$xml = getXMLWriter();
$xml->openMemory();
$xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('document');
$xml->writeElement('LimeSurveyDocType','Survey');
$xml->writeElement('DBVersion',getGlobalSetting("DBVersion"));
$xml->startElement('languages');
$surveylanguages=Survey::model()->findByPk($iSurveyID)->additionalLanguages;
$surveylanguages[]=Survey::model()->findByPk($iSurveyID)->language;
foreach ($surveylanguages as $surveylanguage)
{
$xml->writeElement('language',$surveylanguage);
}
$xml->endElement();
surveyGetXMLStructure($iSurveyID, $xml,$exclude);
$xml->endElement(); // close columns
$xml->endDocument();
return $xml->outputMemory(true);
}
/**
* Exports a single table to XML
*
* @param inetger $iSurveyID The survey ID
* @param string $sTableName The database table name of the table to be export
* @param string $sDocType What doctype should be written
* @param string $sXMLTableName Name of the tag table name in the XML file
* @return object XMLWriter object
*/
function getXMLDataSingleTable($iSurveyID, $sTableName, $sDocType, $sXMLTableTagName='', $sFileName='', $bSetIndent=true)
{
$xml = getXMLWriter();
if ($sFileName=='')
{
$xml->openMemory();
}
else
{
$bOK=$xml->openURI($sFileName);
}
$xml->setIndent($bSetIndent);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('document');
$xml->writeElement('LimeSurveyDocType',$sDocType);
$xml->writeElement('DBVersion',getGlobalSetting("DBVersion"));
$xml->startElement('languages');
$aSurveyLanguages=Survey::model()->findByPk($iSurveyID)->additionalLanguages;
$aSurveyLanguages[]=Survey::model()->findByPk($iSurveyID)->language;
foreach ($aSurveyLanguages as $sSurveyLanguage)
{
$xml->writeElement('language',$sSurveyLanguage);
}
$xml->endElement();
$aquery = "SELECT * FROM {{{$sTableName}}}";
buildXMLFromQuery($xml,$aquery, $sXMLTableTagName);
$xml->endElement(); // close columns
$xml->endDocument();
if ($sFileName='')
{
return $xml->outputMemory(true);
}
else
{
return $bOK;
}
}
/**
* from export_structure_quexml.php
*/
function QueXMLCleanup($string,$allow = '<p><b><u><i><em>')
{
return str_replace("&","&amp;",html_entity_decode(trim(strip_tags(str_ireplace("<br />","\n",$string),$allow)),ENT_QUOTES,'UTF-8'));
}
/**
* from export_structure_quexml.php
*/
function QueXMLCreateFree($f,$len,$lab="")
{
global $dom;
$free = $dom->createElement("free");
$format = $dom->createElement("format",QueXMLCleanup($f));
$length = $dom->createElement("length",QueXMLCleanup($len));
$label = $dom->createElement("label",QueXMLCleanup($lab));
$free->appendChild($format);
$free->appendChild($length);
$free->appendChild($label);
return $free;
}
/**
* from export_structure_quexml.php
*/
function QueXMLFixedArray($array)
{
global $dom;
$fixed = $dom->createElement("fixed");
foreach ($array as $key => $v)
{
$category = $dom->createElement("category");
$label = $dom->createElement("label",QueXMLCleanup("$key",''));
$value= $dom->createElement("value",QueXMLCleanup("$v",''));
$category->appendChild($label);
$category->appendChild($value);
$fixed->appendChild($category);
}
return $fixed;
}
/**
* Calculate if this item should have a QueXMLSkipTo element attached to it
*
* from export_structure_quexml.php
*
* @param mixed $qid
* @param mixed $value
*
* @return bool|string Text of item to skip to otherwise false if nothing to skip to
* @author Adam Zammit <adam.zammit@acspri.org.au>
* @since 2010-10-28
* @TODO Correctly handle conditions in a database agnostic way
*/
function QueXMLSkipTo($qid,$value,$cfieldname = "")
{
return false;
}
/**
* from export_structure_quexml.php
*/
function QueXMLCreateFixed($qid,$rotate=false,$labels=true,$scale=0,$other=false,$varname="")
{
global $dom;
global $quexmllang;
$qlang = new limesurvey_lang($quexmllang);
if ($labels)
$Query = "SELECT * FROM {{labels}} WHERE lid = $labels AND language='$quexmllang' ORDER BY sortorder ASC";
else
$Query = "SELECT code,answer as title,sortorder FROM {{answers}} WHERE qid = $qid AND scale_id = $scale AND language='$quexmllang' ORDER BY sortorder ASC";
$QueryResult = Yii::app()->db->createCommand($Query)->query();
$fixed = $dom->createElement("fixed");
$nextcode = "";
foreach($QueryResult->readAll() as $Row)
{
$category = $dom->createElement("category");
$label = $dom->createElement("label",QueXMLCleanup($Row['title'],''));
$value= $dom->createElement("value",QueXMLCleanup($Row['code']));
$category->appendChild($label);
$category->appendChild($value);
$st = QueXMLSkipTo($qid,$Row['code']);
if ($st !== false)
{
$quexml_skipto = $dom->createElement("quexml_skipto",$st);
$category->appendChild($quexml_skipto);
}
$fixed->appendChild($category);
$nextcode = $Row['code'];
}
if ($other)
{
$category = $dom->createElement("category");
$label = $dom->createElement("label",quexml_get_lengthth($qid,"other_replace_text",$qlang->gT("Other")));
$value= $dom->createElement("value",'-oth-');
$category->appendChild($label);
$category->appendChild($value);
$contingentQuestion = $dom->createElement("contingentQuestion");
$length = $dom->createElement("length",24);
$text = $dom->createElement("text",quexml_get_lengthth($qid,"other_replace_text",$qlang->gT("Other")));
$contingentQuestion->appendChild($text);
$contingentQuestion->appendChild($length);
$contingentQuestion->setAttribute("varName",$varname . 'other');
$category->appendChild($contingentQuestion);
$fixed->appendChild($category);
}
if ($rotate) $fixed->setAttribute("rotate","true");
return $fixed;
}
/**
* from export_structure_quexml.php
*/
function quexml_get_lengthth($qid,$attribute,$default, $quexmllang=false)
{
global $dom;
if ($quexmllang!=false)
$Query = "SELECT value FROM {{question_attributes}} WHERE qid = $qid AND language='$quexmllang' AND attribute='$attribute'";
else
$Query = "SELECT value FROM {{question_attributes}} WHERE qid = $qid AND attribute='$attribute'";
//$QueryResult = mysql_query($Query) or die ("ERROR: $QueryResult<br />".mysql_error());
$QueryResult = Yii::app()->db->createCommand($Query)->query();
$Row = $QueryResult->read();
if ($Row && !empty($Row['value']))
return $Row['value'];
else
return $default;
}
/**
* from export_structure_quexml.php
*/
function quexml_create_multi(&$question,$qid,$varname,$scale_id = false,$free = false,$other = false)
{
global $dom;
global $quexmllang ;
global $iSurveyID;
$qlang = new limesurvey_lang($quexmllang);
$Query = "SELECT * FROM {{questions}} WHERE parent_qid = $qid AND language='$quexmllang' ";
if ($scale_id != false) $Query .= " AND scale_id = $scale_id ";
$Query .= " ORDER BY question_order ASC";
//$QueryResult = mysql_query($Query) or die ("ERROR: $QueryResult<br />".mysql_error());
$QueryResult = Yii::app()->db->createCommand($Query)->query();
$nextcode = "";
foreach($QueryResult->readAll() as $Row)
{
$response = $dom->createElement("response");
if ($free == false)
{
$fixed = $dom->createElement("fixed");
$category = $dom->createElement("category");
$label = $dom->createElement("label",QueXMLCleanup($Row['question'],''));
$value= $dom->createElement("value",1);
$nextcode = $Row['title'];
$category->appendChild($label);
$category->appendChild($value);
$st = QueXMLSkipTo($qid,'Y'," AND c.cfieldname LIKE '+$iSurveyID" . "X" . $Row['gid'] . "X" . $qid . $Row['title'] . "' ");
if ($st !== false)
{
$quexml_skipto = $dom->createElement("skipTo",$st);
$category->appendChild($quexml_skipto);
}
$fixed->appendChild($category);
$response->appendChild($fixed);
}
else
$response->appendChild(QueXMLCreateFree($free['f'],$free['len'],$Row['question']));
$response->setAttribute("varName",QueXMLCleanup($Row['title']));
$question->appendChild($response);
}
if ($other && $free==false)
{
$response = $dom->createElement("response");
$fixed = $dom->createElement("fixed");
$category = $dom->createElement("category");
$label = $dom->createElement("label",quexml_get_lengthth($qid,"other_replace_text",$qlang->gT("Other")));
$value= $dom->createElement("value",1);
//Get next code
if (is_numeric($nextcode))
$nextcode++;
else if (is_string($nextcode))
$nextcode = chr(ord($nextcode) + 1);
$category->appendChild($label);
$category->appendChild($value);
$contingentQuestion = $dom->createElement("contingentQuestion");
$length = $dom->createElement("length",24);
$text = $dom->createElement("text",quexml_get_lengthth($qid,"other_replace_text",$qlang->gT("Other")));
$contingentQuestion->appendChild($text);
$contingentQuestion->appendChild($length);
$contingentQuestion->setAttribute("varName",$varname . 'other');
$category->appendChild($contingentQuestion);
$fixed->appendChild($category);
$response->appendChild($fixed);
$response->setAttribute("varName",$varname . QueXMLCleanup($nextcode));
$question->appendChild($response);
}
return;
}
/**
* from export_structure_quexml.php
*/
function quexml_create_subQuestions(&$question,$qid,$varname,$use_answers = false)
{
global $dom;
global $quexmllang ;
if ($use_answers)
$Query = "SELECT answer as question, code as title FROM {{answers}} WHERE qid = $qid AND language='$quexmllang' ORDER BY sortorder ASC";
else
$Query = "SELECT * FROM {{questions}} WHERE parent_qid = $qid and scale_id = 0 AND language='$quexmllang' ORDER BY question_order ASC";
$QueryResult = Yii::app()->db->createCommand($Query)->query();
foreach($QueryResult->readAll() as $Row)
{
$subQuestion = $dom->createElement("subQuestion");
$text = $dom->createElement("text",QueXMLCleanup($Row['question'],''));
$subQuestion->appendChild($text);
$subQuestion->setAttribute("varName",$varname .'_'. QueXMLCleanup($Row['title']));
$question->appendChild($subQuestion);
}
return;
}
/**
* Export quexml survey.
*/
function quexml_export($surveyi, $quexmllan)
{
global $dom, $quexmllang, $iSurveyID;
$quexmllang = $quexmllan;
$iSurveyID = $surveyi;
$qlang = new limesurvey_lang($quexmllang);
$dom = new DOMDocument('1.0','UTF-8');
//Title and survey id
$questionnaire = $dom->createElement("questionnaire");
$Query = "SELECT * FROM {{surveys}},{{surveys_languagesettings}} WHERE sid=$iSurveyID and surveyls_survey_id=sid and surveyls_language='".$quexmllang."'";
$QueryResult = Yii::app()->db->createCommand($Query)->query();
$Row = $QueryResult->read();
$questionnaire->setAttribute("id", $Row['sid']);
$title = $dom->createElement("title",QueXMLCleanup($Row['surveyls_title']));
$questionnaire->appendChild($title);
//investigator and datacollector
$investigator = $dom->createElement("investigator");
$name = $dom->createElement("name");
$name = $dom->createElement("firstName");
$name = $dom->createElement("lastName");
$dataCollector = $dom->createElement("dataCollector");
$questionnaire->appendChild($investigator);
$questionnaire->appendChild($dataCollector);
//questionnaireInfo == welcome
if (!empty($Row['surveyls_welcometext']))
{
$questionnaireInfo = $dom->createElement("questionnaireInfo");
$position = $dom->createElement("position","before");
$text = $dom->createElement("text",QueXMLCleanup($Row['surveyls_welcometext']));
$administration = $dom->createElement("administration","self");
$questionnaireInfo->appendChild($position);
$questionnaireInfo->appendChild($text);
$questionnaireInfo->appendChild($administration);
$questionnaire->appendChild($questionnaireInfo);
}
if (!empty($Row['surveyls_endtext']))
{
$questionnaireInfo = $dom->createElement("questionnaireInfo");
$position = $dom->createElement("position","after");
$text = $dom->createElement("text",QueXMLCleanup($Row['surveyls_endtext']));
$administration = $dom->createElement("administration","self");
$questionnaireInfo->appendChild($position);
$questionnaireInfo->appendChild($text);
$questionnaireInfo->appendChild($administration);
$questionnaire->appendChild($questionnaireInfo);
}
//section == group
$Query = "SELECT * FROM {{groups}} WHERE sid=$iSurveyID AND language='$quexmllang' order by group_order ASC";
$QueryResult = Yii::app()->db->createCommand($Query)->query();
//for each section
foreach($QueryResult->readAll() as $Row)
{
$gid = $Row['gid'];
$section = $dom->createElement("section");
if (!empty($Row['group_name']))
{
$sectionInfo = $dom->createElement("sectionInfo");
$position = $dom->createElement("position","title");
$text = $dom->createElement("text",QueXMLCleanup($Row['group_name']));
$administration = $dom->createElement("administration","self");
$sectionInfo->appendChild($position);
$sectionInfo->appendChild($text);
$sectionInfo->appendChild($administration);
$section->appendChild($sectionInfo);
}
if (!empty($Row['description']))
{
$sectionInfo = $dom->createElement("sectionInfo");
$position = $dom->createElement("position","before");
$text = $dom->createElement("text",QueXMLCleanup($Row['description']));
$administration = $dom->createElement("administration","self");
$sectionInfo->appendChild($position);
$sectionInfo->appendChild($text);
$sectionInfo->appendChild($administration);
$section->appendChild($sectionInfo);
}
$section->setAttribute("id", $gid);
//boilerplate questions convert to sectionInfo elements
$Query = "SELECT * FROM {{questions}} WHERE sid=$iSurveyID AND gid = $gid AND type LIKE 'X' AND language='$quexmllang' ORDER BY question_order ASC";
$QR = Yii::app()->db->createCommand($Query)->query();
foreach($QR->readAll() as $RowQ)
{
$sectionInfo = $dom->createElement("sectionInfo");
$position = $dom->createElement("position","before");
$text = $dom->createElement("text",QueXMLCleanup($RowQ['question']));
$administration = $dom->createElement("administration","self");
$sectionInfo->appendChild($position);
$sectionInfo->appendChild($text);
$sectionInfo->appendChild($administration);
$section->appendChild($sectionInfo);
}
//foreach question
$Query = "SELECT * FROM {{questions}} WHERE sid=$iSurveyID AND gid = $gid AND parent_qid=0 AND language='$quexmllang' AND type NOT LIKE 'X' ORDER BY question_order ASC";
$QR = Yii::app()->db->createCommand($Query)->query();
foreach($QR->readAll() as $RowQ)
{
$question = $dom->createElement("question");
$type = $RowQ['type'];
$qid = $RowQ['qid'];
$other = false;
if ($RowQ['other'] == 'Y') $other = true;
//create a new text element for each new line
$questiontext = explode('<br />',$RowQ['question']);
foreach ($questiontext as $qt)
{
$txt = QueXMLCleanup($qt);
if (!empty($txt))
{
$text = $dom->createElement("text",$txt);
$question->appendChild($text);
}
}
//directive
if (!empty($RowQ['help']))
{
$directive = $dom->createElement("directive");
$position = $dom->createElement("position","during");
$text = $dom->createElement("text",QueXMLCleanup($RowQ['help']));
$administration = $dom->createElement("administration","self");
$directive->appendChild($position);
$directive->appendChild($text);
$directive->appendChild($administration);
$question->appendChild($directive);
}
if (Yii::app()->getConfig('quexmlshowprintablehelp')==true)
{
$RowQ['printable_help']=quexml_get_lengthth($qid,"printable_help","", $quexmllang);
if (!empty($RowQ['printable_help']))
{
$directive = $dom->createElement("directive");
$position = $dom->createElement("position","before");
$text = $dom->createElement("text", '['.$qlang->gT('Only answer the following question if:')." ".QueXMLCleanup($RowQ['printable_help'])."]");
$administration = $dom->createElement("administration","self");
$directive->appendChild($position);
$directive->appendChild($text);
$directive->appendChild($administration);
$question->appendChild($directive);
}
}
$response = $dom->createElement("response");
$sgq = $RowQ['title'];
$response->setAttribute("varName",$sgq);
switch ($type)
{
case "X": //BOILERPLATE QUESTION - none should appear
break;
case "5": //5 POINT CHOICE radio-buttons
$response->appendChild(QueXMLFixedArray(array("1" => 1,"2" => 2,"3" => 3,"4" => 4,"5" => 5)));
$question->appendChild($response);
break;
case "D": //DATE
$response->appendChild(QueXMLCreateFree("date","8",""));
$question->appendChild($response);
break;
case "L": //LIST drop-down/radio-button list
$response->appendChild(QueXMLCreateFixed($qid,false,false,0,$other,$sgq));
$question->appendChild($response);
break;
case "!": //List - dropdown
$response->appendChild(QueXMLCreateFixed($qid,false,false,0,$other,$sgq));
$question->appendChild($response);
break;
case "O": //LIST WITH COMMENT drop-down/radio-button list + textarea
quexml_create_subQuestions($question,$qid,$sgq);
$response = $dom->createElement("response");
$response->setAttribute("varName",QueXMLCleanup($sgq));
$response->appendChild(QueXMLCreateFixed($qid,false,false,0,$other,$sgq));
$response2 = $dom->createElement("response");
$response2->setAttribute("varName",QueXMLCleanup($sgq) . "_comment");
$response2->appendChild(QueXMLCreateFree("longtext","40",""));
$question->appendChild($response);
$question->appendChild($response2);
break;
case "R": //RANKING STYLE
quexml_create_subQuestions($question,$qid,$sgq,true);
$Query = "SELECT COUNT(*) as sc FROM {{answers}} WHERE qid = $qid AND language='$quexmllang' ";
$QRE = Yii::app()->db->createCommand($Query)->query();
//$QRE = mysql_query($Query) or die ("ERROR: $QRE<br />".mysql_error());
//$QROW = mysql_fetch_assoc($QRE);
$QROW = $QRE->read();
$response->appendChild(QueXMLCreateFree("integer",strlen($QROW['sc']),""));
$question->appendChild($response);
break;
case "M": //Multiple choice checkbox
quexml_create_multi($question,$qid,$sgq,false,false,$other);
break;
case "P": //Multiple choice with comments checkbox + text
//Not yet implemented
quexml_create_multi($question,$qid,$sgq,false,false,$other);
//no comments added
break;
case "Q": //MULTIPLE SHORT TEXT
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLCreateFree("text",quexml_get_lengthth($qid,"maximum_chars","10"),""));
$question->appendChild($response);
break;
case "K": //MULTIPLE NUMERICAL
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLCreateFree("integer",quexml_get_lengthth($qid,"maximum_chars","10"),""));
$question->appendChild($response);
break;
case "N": //NUMERICAL QUESTION TYPE
$response->appendChild(QueXMLCreateFree("integer",quexml_get_lengthth($qid,"maximum_chars","10"),""));
$question->appendChild($response);
break;
case "S": //SHORT FREE TEXT
// default is fieldlength of 24 characters.
$response->appendChild(QueXMLCreateFree("text",quexml_get_lengthth($qid,"maximum_chars","24"),""));
$question->appendChild($response);
break;
case "T": //LONG FREE TEXT
$response->appendChild(QueXMLCreateFree("longtext",quexml_get_lengthth($qid,"display_rows","40"),""));
$question->appendChild($response);
break;
case "U": //HUGE FREE TEXT
$response->appendChild(QueXMLCreateFree("longtext",quexml_get_lengthth($qid,"display_rows","80"),""));
$question->appendChild($response);
break;
case "Y": //YES/NO radio-buttons
$response->appendChild(QueXMLFixedArray(array($qlang->gT("Yes") => 'Y',$qlang->gT("No") => 'N')));
$question->appendChild($response);
break;
case "G": //GENDER drop-down list
$response->appendChild(QueXMLFixedArray(array($qlang->gT("Female") => 'F',$qlang->gT("Male") => 'M')));
$question->appendChild($response);
break;
case "A": //ARRAY (5 POINT CHOICE) radio-buttons
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLFixedArray(array("1" => 1,"2" => 2,"3" => 3,"4" => 4,"5" => 5)));
$question->appendChild($response);
break;
case "B": //ARRAY (10 POINT CHOICE) radio-buttons
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLFixedArray(array("1" => 1,"2" => 2,"3" => 3,"4" => 4,"5" => 5,"6" => 6,"7" => 7,"8" => 8,"9" => 9,"10" => 10)));
$question->appendChild($response);
break;
case "C": //ARRAY (YES/UNCERTAIN/NO) radio-buttons
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLFixedArray(array($qlang->gT("Yes") => 'Y',$qlang->gT("Uncertain") => 'U',$qlang->gT("No") => 'N')));
$question->appendChild($response);
break;
case "E": //ARRAY (Increase/Same/Decrease) radio-buttons
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLFixedArray(array($qlang->gT("Increase") => 'I',$qlang->gT("Same") => 'S',$qlang->gT("Decrease") => 'D')));
$question->appendChild($response);
break;
case "F": //ARRAY (Flexible) - Row Format
//select subQuestions from answers table where QID
quexml_create_subQuestions($question,$qid,$sgq);
$response->appendChild(QueXMLCreateFixed($qid,false,false,0,$other,$sgq));
$question->appendChild($response);
//select fixed responses from
break;
case "H": //ARRAY (Flexible) - Column Format
quexml_create_subQuestions($question,$RowQ['qid'],$sgq);
$response->appendChild(QueXMLCreateFixed($qid,true,false,0,$other,$sgq));
$question->appendChild($response);
break;
case "1": //Dualscale multi-flexi array
//select subQuestions from answers table where QID
quexml_create_subQuestions($question,$qid,$sgq);
//get the header of the first scale of the dual scale question
$Query = "SELECT value FROM {{question_attributes}} WHERE qid = $qid AND language='$quexmllang' AND attribute='dualscale_headerA'";
$QRE = Yii::app()->db->createCommand($Query)->query();
$QROW = $QRE->read();
$response = $dom->createElement("response");
if ($QROW['value'])
$response->setAttribute("varName",QueXMLCleanup($QROW['value']));
$response->appendChild(QueXMLCreateFixed($qid,false,false,0,$other,$sgq));
//get the header of the second scale of the dual scale question
$Query = "SELECT value FROM {{question_attributes}} WHERE qid = $qid AND language='$quexmllang' AND attribute='dualscale_headerB'";
$QRE = Yii::app()->db->createCommand($Query)->query();
$QROW = $QRE->read();
$response2 = $dom->createElement("response");
if ($QROW['value'])
$response2->setAttribute("varName",QueXMLCleanup($QROW['value']));
$response2->appendChild(QueXMLCreateFixed($qid,false,false,1,$other,$sgq));
$question->appendChild($response);
$question->appendChild($response2);
break;
case ":": //multi-flexi array numbers
quexml_create_subQuestions($question,$qid,$sgq);
//get multiflexible_checkbox - if set then each box is a checkbox (single fixed response)
$mcb = quexml_get_lengthth($qid,'multiflexible_checkbox',-1);
if ($mcb != -1)
quexml_create_multi($question,$qid,$sgq,1);
else
{
//get multiflexible_max and maximum_chars - if set then make boxes of max of these widths
$mcm = max(quexml_get_lengthth($qid,'maximum_chars',1), strlen(quexml_get_lengthth($qid,'multiflexible_max',1)));
quexml_create_multi($question,$qid,$sgq,1,array('f' => 'integer', 'len' => $mcm, 'lab' => ''));
}
break;
case ";": //multi-flexi array text
quexml_create_subQuestions($question,$qid,$sgq);
//foreach question where scale_id = 1 this is a textbox
quexml_create_multi($question,$qid,$sgq,1,array('f' => 'text', 'len' => quexml_get_lengthth($qid,'maximum_chars',10), 'lab' => ''));
break;
case "^": //SLIDER CONTROL - not supported
$response->appendChild(QueXMLFixedArray(array("NOT SUPPORTED:$type" => 1)));
$question->appendChild($response);
break;
} //End Switch
$section->appendChild($question);
}
$questionnaire->appendChild($section);
}
$dom->appendChild($questionnaire);
$dom->formatOutput = true;
return $dom->saveXML();
}
/**
* From adodb
*
* Different SQL databases used different methods to combine strings together.
* This function provides a wrapper.
*
* param s variable number of string parameters
*
* Usage: $db->Concat($str1,$str2);
*
* @return concatenated string
*/
function concat()
{
$arr = func_get_args();
return implode('+', $arr);
}
// DUMP THE RELATED DATA FOR A SINGLE QUESTION INTO A SQL FILE FOR IMPORTING LATER ON OR
// ON ANOTHER SURVEY SETUP DUMP ALL DATA WITH RELATED QID FROM THE FOLLOWING TABLES
// 1. questions
// 2. answers
function group_export($action, $iSurveyID, $gid)
{
viewHelper::disableHtmlLogging();
$fn = "limesurvey_group_$gid.lsg";
$xml = getXMLWriter();
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=$fn");
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");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: cache"); // HTTP/1.0
$xml->openUri('php://output');
$xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('document');
$xml->writeElement('LimeSurveyDocType','Group');
$xml->writeElement('DBVersion', getGlobalSetting("DBVersion"));
$xml->startElement('languages');
$lresult = QuestionGroup::model()->findAllByAttributes(array('gid' => $gid), array('select'=>'language','group' => 'language'));
foreach($lresult as $row)
{
$xml->writeElement('language',$row->language);
}
$xml->endElement();
groupGetXMLStructure($xml,$gid);
$xml->endElement(); // close columns
$xml->endDocument();
}
function groupGetXMLStructure($xml,$gid)
{
// QuestionGroup
$gquery = "SELECT *
FROM {{groups}}
WHERE gid=$gid";
buildXMLFromQuery($xml,$gquery);
// Questions table
$qquery = "SELECT *
FROM {{questions}}
WHERE gid=$gid and parent_qid=0 order by question_order, language, scale_id";
buildXMLFromQuery($xml,$qquery);
// Questions table - Subquestions
$qquery = "SELECT *
FROM {{questions}}
WHERE gid=$gid and parent_qid>0 order by question_order, language, scale_id";
buildXMLFromQuery($xml,$qquery,'subquestions');
//Answer
$aquery = "SELECT DISTINCT {{answers}}.*
FROM {{answers}}, {{questions}}
WHERE ({{answers}}.qid={{questions}}.qid)
AND ({{questions}}.gid=$gid)";
buildXMLFromQuery($xml,$aquery);
//Condition - THIS CAN ONLY EXPORT CONDITIONS THAT RELATE TO THE SAME GROUP
$cquery = "SELECT DISTINCT c.*
FROM {{conditions}} c, {{questions}} q, {{questions}} b
WHERE (c.cqid=q.qid)
AND (c.qid=b.qid)
AND (q.gid={$gid})
AND (b.gid={$gid})";
buildXMLFromQuery($xml,$cquery,'conditions');
//Question attributes
$iSurveyID=Yii::app()->db->createCommand("select sid from {{groups}} where gid={$gid}")->query()->read();
$iSurveyID=$iSurveyID['sid'];
$sBaseLanguage=Survey::model()->findByPk($iSurveyID)->language;
$platform = Yii::app()->db->getDriverName();
if ($platform == 'mssql' || $platform =='sqlsrv' || $platform =='dblib')
{
$query="SELECT qa.qid, qa.attribute, cast(qa.value as varchar(4000)) as value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID} and q.gid={$gid}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, cast(qa.value as varchar(4000)), qa.language";
}
else {
$query="SELECT qa.qid, qa.attribute, qa.value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID} and q.gid={$gid}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, qa.value, qa.language";
}
buildXMLFromQuery($xml,$query,'question_attributes');
// Default values
$query = "SELECT dv.*
FROM {{defaultvalues}} dv
JOIN {{questions}} ON {{questions}}.qid = dv.qid
AND {{questions}}.language=dv.language
AND {{questions}}.gid=$gid
order by dv.language, dv.scale_id";
buildXMLFromQuery($xml,$query,'defaultvalues');
}
// DUMP THE RELATED DATA FOR A SINGLE QUESTION INTO A SQL FILE FOR IMPORTING LATER ON OR
// ON ANOTHER SURVEY SETUP DUMP ALL DATA WITH RELATED QID FROM THE FOLLOWING TABLES
// - Questions
// - Answer
// - Question attributes
// - Default values
function questionExport($action, $iSurveyID, $gid, $qid)
{
$fn = "limesurvey_question_$qid.lsq";
$xml = getXMLWriter();
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=$fn");
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");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: cache");
// HTTP/1.0
$xml->openURI('php://output');
$xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('document');
$xml->writeElement('LimeSurveyDocType','Question');
$xml->writeElement('DBVersion', getGlobalSetting('DBVersion'));
$xml->startElement('languages');
$aLanguages=Survey::model()->findByPk($iSurveyID)->additionalLanguages;
$aLanguages[]=Survey::model()->findByPk($iSurveyID)->language;
foreach ($aLanguages as $sLanguage)
{
$xml->writeElement('language',$sLanguage);
}
$xml->endElement();
questionGetXMLStructure($xml,$gid,$qid);
$xml->endElement(); // close columns
$xml->endDocument();
exit;
}
function questionGetXMLStructure($xml,$gid,$qid)
{
// Questions table
$qquery = "SELECT *
FROM {{questions}}
WHERE qid=$qid and parent_qid=0 order by language, scale_id, question_order";
buildXMLFromQuery($xml,$qquery);
// Questions table - Subquestions
$qquery = "SELECT *
FROM {{questions}}
WHERE parent_qid=$qid order by language, scale_id, question_order";
buildXMLFromQuery($xml,$qquery,'subquestions');
// Answer table
$aquery = "SELECT *
FROM {{answers}}
WHERE qid = $qid order by language, scale_id, sortorder";
buildXMLFromQuery($xml,$aquery);
// Question attributes
$iSurveyID=Yii::app()->db->createCommand("select sid from {{groups}} where gid={$gid}")->query();
$iSurveyID=$iSurveyID->read();
$iSurveyID=$iSurveyID['sid'];
$sBaseLanguage=Survey::model()->findByPk($iSurveyID)->language;
$platform = Yii::app()->db->getDriverName();
if ($platform == 'mssql' || $platform =='sqlsrv'|| $platform =='dblib')
{
$query="SELECT qa.qid, qa.attribute, cast(qa.value as varchar(4000)) as value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID} and q.qid={$qid}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, cast(qa.value as varchar(4000)), qa.language";
}
else {
$query="SELECT qa.qid, qa.attribute, qa.value, qa.language
FROM {{question_attributes}} qa JOIN {{questions}} q ON q.qid = qa.qid AND q.sid={$iSurveyID} and q.qid={$qid}
where q.language='{$sBaseLanguage}' group by qa.qid, qa.attribute, qa.value, qa.language";
}
buildXMLFromQuery($xml,$query);
// Default values
$query = "SELECT *
FROM {{defaultvalues}}
WHERE qid=$qid order by language, scale_id";
buildXMLFromQuery($xml,$query);
}
function tokensExport($iSurveyID)
{
$sEmailFiter=trim(App()->request->getPost('filteremail'));
$iTokenStatus=App()->request->getPost('tokenstatus');
$iInvitationStatus=App()->request->getPost('invitationstatus');
$iReminderStatus=App()->request->getPost('reminderstatus');
$sTokenLanguage=App()->request->getPost('tokenlanguage');
$oSurvey=Survey::model()->findByPk($iSurveyID);
$bIsNotAnonymous= ($oSurvey->anonymized=='N' && $oSurvey->active=='Y');// db table exist (survey_$iSurveyID) ?
$bquery = "SELECT * FROM {{tokens_$iSurveyID}} where 1=1";
$databasetype = Yii::app()->db->getDriverName();
if ($sEmailFiter!='')
{
if (in_array($databasetype, array('mssql', 'sqlsrv', 'dblib')))
{
$bquery .= ' and CAST(email as varchar) like '.dbQuoteAll('%'.$sEmailFiter.'%', true);
}
else
{
$bquery .= ' and email like '.dbQuoteAll('%'.$sEmailFiter.'%', true);
}
}
if ($iTokenStatus==1)
{
$bquery .= " and completed<>'N'";
}
elseif ($iTokenStatus==2)
{
$bquery .= " and completed='N'";
if ($bIsNotAnonymous)
{
$bquery .=" and token not in (select token from {{survey_$iSurveyID}} group by token)";
}
}
if ($iTokenStatus==3 && $bIsNotAnonymous)
{
$bquery .= " and completed='N' and token in (select token from {{survey_$iSurveyID}} group by token)";
}
if ($iInvitationStatus==1)
{
$bquery .= " and sent<>'N'";
}
if ($iInvitationStatus==2)
{
$bquery .= " and sent='N'";
}
if ($iReminderStatus==1)
{
$bquery .= " and remindersent<>'N'";
}
if ($iReminderStatus==2)
{
$bquery .= " and remindersent='N'";
}
if ($sTokenLanguage!='')
{
$bquery .= " and language=".dbQuoteAll($sTokenLanguage);
}
$bquery .= " ORDER BY tid";
Yii::app()->loadHelper('database');
$bresult = Yii::app()->db->createCommand($bquery)->query(); //dbExecuteAssoc($bquery) is faster but deprecated!
//HEADERS should be after the above query else timeout errors in case there are lots of tokens!
header("Content-Disposition: attachment; filename=tokens_".$iSurveyID.".csv");
header("Content-type: text/comma-separated-values; charset=UTF-8");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: cache");
// Export UTF8 WITH BOM
$tokenoutput = chr(hexdec('EF')).chr(hexdec('BB')).chr(hexdec('BF'));
$tokenoutput .= "tid,firstname,lastname,email,emailstatus,token,language,validfrom,validuntil,invited,reminded,remindercount,completed,usesleft";
$attrfieldnames = getAttributeFieldNames($iSurveyID);
$attrfielddescr = getTokenFieldsAndNames($iSurveyID, true);
foreach ($attrfieldnames as $attr_name)
{
$tokenoutput .=", $attr_name";
if (isset($attrfielddescr[$attr_name]))
$tokenoutput .=" <".str_replace(","," ",$attrfielddescr[$attr_name]['description']).">";
}
$tokenoutput .="\n";
echo $tokenoutput;
$tokenoutput="";
// Export token line by line and fill $aExportedTokens with token exported
Yii::import('application.libraries.Date_Time_Converter', true);
$aExportedTokens = array();
while ($brow = $bresult->read())
{
if (trim($brow['validfrom']!=''))
{
$datetimeobj = new Date_Time_Converter($brow['validfrom'] , "Y-m-d H:i:s");
$brow['validfrom']=$datetimeobj->convert('Y-m-d H:i');
}
if (trim($brow['validuntil']!=''))
{
$datetimeobj = new Date_Time_Converter($brow['validuntil'] , "Y-m-d H:i:s");
$brow['validuntil']=$datetimeobj->convert('Y-m-d H:i');
}
$tokenoutput .= '"'.trim($brow['tid']).'",';
$tokenoutput .= '"'.trim($brow['firstname']).'",';
$tokenoutput .= '"'.trim($brow['lastname']).'",';
$tokenoutput .= '"'.trim($brow['email']).'",';
$tokenoutput .= '"'.trim($brow['emailstatus']).'",';
$tokenoutput .= '"'.trim($brow['token']).'",';
$tokenoutput .= '"'.trim($brow['language']).'",';
$tokenoutput .= '"'.trim($brow['validfrom']).'",';
$tokenoutput .= '"'.trim($brow['validuntil']).'",';
$tokenoutput .= '"'.trim($brow['sent']).'",';
$tokenoutput .= '"'.trim($brow['remindersent']).'",';
$tokenoutput .= '"'.trim($brow['remindercount']).'",';
$tokenoutput .= '"'.trim($brow['completed']).'",';
$tokenoutput .= '"'.trim($brow['usesleft']).'",';
foreach ($attrfieldnames as $attr_name)
{
$tokenoutput .='"'.trim($brow[$attr_name]).'",';
}
$tokenoutput = substr($tokenoutput,0,-1); // remove last comma
$tokenoutput .= "\n";
echo $tokenoutput;
$tokenoutput='';
$aExportedTokens[] = $brow['tid'];
}
if (Yii::app()->request->getPost('tokendeleteexported') && !empty($aExportedTokens))
{
Token::model($iSurveyID)->deleteByPk($aExportedTokens);
}
}
function CPDBExport($data,$filename)
{
header("Content-Disposition: attachment; filename=".$filename.".csv");
header("Content-type: text/comma-separated-values; charset=UTF-8");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: cache");
$tokenoutput = chr(hexdec('EF')).chr(hexdec('BB')).chr(hexdec('BF'));
foreach($data as $key=>$value)
{
foreach($value as $values)
{
$tokenoutput .= trim($values).',';
}
$tokenoutput = substr($tokenoutput,0,-1); // remove last comma
$tokenoutput .= "\n";
}
echo $tokenoutput;
exit;
}