diff --git a/api/app_questionnaires.php b/api/app_questionnaires.php index 8af1c6f..aa1d3d3 100644 --- a/api/app_questionnaires.php +++ b/api/app_questionnaires.php @@ -77,6 +77,10 @@ if ($qnID) { if (isset($config['range'])) $q['range'] = $config['range']; if (isset($config['constraints'])) $q['constraints'] = $config['constraints']; if (isset($config['minSelection'])) $q['minSelection'] = $config['minSelection']; + if (isset($config['maxLength'])) $q['maxLength'] = (int)$config['maxLength']; + if (!empty($config['multiline'])) $q['multiline'] = true; + if (isset($config['otherNextQuestionId'])) $q['otherNextQuestionId'] = $config['otherNextQuestionId']; + if (isset($config['otherOptionKey'])) $q['otherOptionKey'] = $config['otherOptionKey']; // String spinner static options if ($layout === 'string_spinner' && isset($config['options'])) { diff --git a/common.php b/common.php index 1a3b33a..9b05818 100644 --- a/common.php +++ b/common.php @@ -2,6 +2,8 @@ // /var/www/html/common.php // Gemeinsame Helfer für Token-Validierung, Key-Derivation (HKDF) und AES (CBC, IV vorangestellt). +require_once __DIR__ . '/lib/text_sanitize.php'; + /** * Load KEY=value pairs from .env in the project root. * Does not override variables already set in the real environment. diff --git a/handlers/app_questionnaires.php b/handlers/app_questionnaires.php index c764f30..9915f46 100644 --- a/handlers/app_questionnaires.php +++ b/handlers/app_questionnaires.php @@ -54,12 +54,20 @@ if ($method === 'POST') { : ($clientRow['coachID'] ?? ''); // Load all questions for this questionnaire: full questionID keyed by short ID - $qRows = $pdo->prepare("SELECT questionID FROM question WHERE questionnaireID = :qn"); + $qRows = $pdo->prepare( + "SELECT questionID, type, configJson FROM question WHERE questionnaireID = :qn" + ); $qRows->execute([':qn' => $qnID]); - $shortIdMap = []; // shortId -> fullQuestionID - foreach ($qRows->fetchAll(PDO::FETCH_COLUMN) as $fullId) { + $shortIdMap = []; // shortId -> fullQuestionID + $freeTextMaxLen = []; // fullQuestionID -> maxLength + foreach ($qRows->fetchAll(PDO::FETCH_ASSOC) as $qRow) { + $fullId = $qRow['questionID']; $parts = explode('__', $fullId); $shortIdMap[end($parts)] = $fullId; + if (($qRow['type'] ?? '') === 'free_text') { + $cfg = json_decode($qRow['configJson'] ?? '{}', true) ?: []; + $freeTextMaxLen[$fullId] = max(1, min((int)($cfg['maxLength'] ?? 500), 10000)); + } } // Load all answer options for this questionnaire: keyed by [questionID][defaultText] @@ -104,6 +112,14 @@ if ($method === 'POST') { $numericValue = isset($a['numericValue']) ? (float)$a['numericValue'] : null; $answeredAt = isset($a['answeredAt']) ? (int)$a['answeredAt'] : null; + if ($freeTextValue !== null && $freeTextValue !== '') { + $maxLen = $freeTextMaxLen[$fullQID] ?? 2000; + $freeTextValue = sanitize_free_text($freeTextValue, $maxLen); + if ($freeTextValue === '') { + continue; + } + } + // Resolve option key to answerOptionID and accumulate points $optionKey = $a['answerOptionKey'] ?? null; if ($optionKey !== null && isset($optionMap[$fullQID][(string)$optionKey])) { @@ -252,6 +268,10 @@ if ($qnID) { if (isset($config['range'])) $q['range'] = $config['range']; if (isset($config['constraints'])) $q['constraints'] = $config['constraints']; if (isset($config['minSelection'])) $q['minSelection'] = $config['minSelection']; + if (isset($config['maxLength'])) $q['maxLength'] = (int)$config['maxLength']; + if (!empty($config['multiline'])) $q['multiline'] = true; + if (isset($config['otherNextQuestionId'])) $q['otherNextQuestionId'] = $config['otherNextQuestionId']; + if (isset($config['otherOptionKey'])) $q['otherOptionKey'] = $config['otherOptionKey']; if ($layout === 'string_spinner' && isset($config['options'])) { $q['options'] = $config['options']; diff --git a/import_questionnaires.php b/import_questionnaires.php index 8cce9f6..3050999 100644 --- a/import_questionnaires.php +++ b/import_questionnaires.php @@ -86,6 +86,17 @@ try { if (isset($q['range'])) $config['range'] = $q['range']; if (isset($q['constraints'])) $config['constraints'] = $q['constraints']; if (isset($q['minSelection'])) $config['minSelection'] = $q['minSelection']; + if (isset($q['maxLength'])) $config['maxLength'] = (int)$q['maxLength']; + if (!empty($q['multiline'])) $config['multiline'] = true; + if (isset($q['otherNextQuestionId'])) $config['otherNextQuestionId'] = $q['otherNextQuestionId']; + if (isset($q['otherOptionKey'])) $config['otherOptionKey'] = $q['otherOptionKey']; + if (isset($q['config']) && is_array($q['config'])) { + foreach (['otherNextQuestionId', 'otherOptionKey', 'hint', 'maxLength', 'multiline', 'textKey'] as $ck) { + if (isset($q['config'][$ck])) { + $config[$ck] = $q['config'][$ck]; + } + } + } if ($layout === 'string_spinner' && isset($q['options']) && is_array($q['options']) && isset($q['options'][0]) && is_string($q['options'][0])) { diff --git a/lib/text_sanitize.php b/lib/text_sanitize.php new file mode 100644 index 0000000..009859c --- /dev/null +++ b/lib/text_sanitize.php @@ -0,0 +1,61 @@ +${(config.options || []).join('\n')} `; break; + case 'free_text': + html = ` +