Only little documentation is available at the moment. If you would like to help with documenting flexSURVEY, please contact me!

Copyright (C) 2009, 2010 Sven Hartenstein.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found at

Quick start

  1. Download flexSURVEY and unpack it.
  2. Make a copy of the file demosurvey.php (so that you keep the original). This is the survey file.
  3. Open your survey file in a text editor and change the database configuration.
  4. Copy the survey file, demosurvey.css, and flexsurvey-VERSION.php in a directory on your server and call the survey file in your browser.
  5. If it works, change the survey file to build your own survey. Of course, you could also start a new survey file from scratch.

Structure of a survey file

Typically, the whole survey is specified in a single PHP file, though you could also use e. g. one file per survey page. Here I assume a single file is used. This is what it consists of:


/* (1) Load flexSURVEY. This defines flexSURVEY's functions but also the default configuration. Be sure so place this line before your personal configuration. */
require "flexsurvey-VERSION.php";

/* (2) Your configuration. */
$fscfg["mysql"]["server"]   = "SERVER";
$fscfg["mysql"]["database"] = "DATABASE";


/* (3) Initialize flexSURVEY. Call fsInit() after configuration! */

/* (4) Output (X)HTML for page layout. */
echo "<html>";
echo "<head>". ... ."</head>";
echo "<body>";
echo "<p>A Survey</p>";

/* (5) Content of the pages */
if (fsPage("Title of first page")) {
  echo "Content of first page.";
if (fsPage("Title of second page")) {
  echo "Content of second page.";
  echo fsAdd("Enter your name: {username,text,border-width:4px;}");
if (fsPage("Title of third page")) {


/* (6) Output (X)HTML for page layout. */
echo fsButtons();
echo "</body>";

Some people may prefer to put (1) - (4) into a separate PHP file and include it in the main file. The latter could then look like this:


require "mysurveyincludefile.php";


if (fsPage("Title of first page")) {
  echo "Content of first page.";
if (fsPage("Title of second page")) {
  echo "Content of second page.";
  echo fsAdd("Enter your name: {username,text,border-width:4px;}");
if (fsPage("Title of third page")) {



Now, let's have a closer look at the section holding the content of the single survey pages.

When you include all survey content in a single file, you need some if (...) { ... } construct, in order to only really echo the content of the current page when parsing the survey file. flexSURVEY simply enumerates the pages, i. e. when the user proceeds to the next page, the session variable $_SESSION["fs_pagecurrent"] is increased by one. Thus, instead of the above example, the survey content could be defined like this:

if ($_SESSION["fs_pagecurrent"] == 1) {
if ($_SESSION["fs_pagecurrent"] == 2) {
if ($_SESSION["fs_pagecurrent"] == 3) {

This is ok but gets difficult if you decide to include another page between, say, page 2 and 3. You would have to do manual renumbering. It gets even more difficult if your survey includes pages that are skipped for some users. flexSURVEY offers the function fsPage() to have an easier life.

fsPage() uses another counter, namely $GLOBALS["fs_pageparsed"]. Each call of fsPage(), no matter of which page we are on, increases this counter by one. Then, fsPage() compares $GLOBALS["fs_pageparsed"] with $_SESSION["fs_pagecurrent"] and returns TRUE if both have the same value.

fsPage() takes the page title as an optional argument. This makes setting the page title easy, but you need to use a certain "hook" in order to include the page name in your page template. See the section on hooks for details.

One important thing is how to use fsPage() when you have pages that are skipped for some users, e. g. depending on previous input or randomization. If, for example, the third page is only for users older than 50 years, this is how you could do it:

if (fsPage("Title of first page")) {
if (fsPage("Title of second page")) {
if ($age > 50) {
  if (fsPage("Title of special page")) {
if (fsPage("Title of third or fourth page")) {

In this example, the above mentioned counters will not count the "special" page for users younger than 51. This is correct. $_SESSION["fs_pagecurrent"] does not know about skipped pages. It only counts how often the user successfully pressed the button to the next page. Therefore it is important to call fsPage() (i. e. to alter $GLOBALS["fs_pageparsed"]) only when the page is to be shown.

This is how you should not do it:

if ($age > 50 && fsPage("Title of special page")) {

This would not work as desired because fsPage() is called independent of age, and the counters count differently.

Adding form elements

Let's start with an example of one element of type text:

echo "What is your name?<br />";
echo fsAdd("My name is {name,text}.");

Imagine the above example with the call of fsAdd() omitted. It would just produce some strange output. fsAdd() however looks for some markup to magically translate into form elements. Curly braces ("{}") tell fsAdd() to add HTML of a form element and to take care of all the fuss like saving the posted value, checking for valid entries, and, first of all, creating a column in the database table if it is not there yet.

Between the curly braces, parameters can be specified. Only one parameter is obligatory and it must directly follow the opening brace: that is the variable name. If multiple parameters (in any order you like) are specified, they must be separated by a "non-word character" as defined by perl regular expressions. Thus, in the above example, you could also write "{name|text}" or "{name#text}" or "{name:text}" or whatever. Please note, that you will run into problems if the separation character which you use is also used as part of one of the parameters! For this reason I prefer to use the comma (",") or vertical bar ("|"), both of which I rarely need to use inside parameters. If I do, I have to use a different separation character. Here is a more complex example:

echo "Do you like italian food? (Please answer with yes or no.)<br />";
echo fsAdd("{italfood,text,width:5em;,?r:/^(yes|no)$/,class=\"myclass\"}");

For more examples of this markup, please refer to the demo survey that comes with flexSURVEY.

You do not need to use the curly-braces markup. flexSURVEY translates the markup into an array of parameters and calls fsFormElement(). You can call fsFormElement() directly if you wish:

echo "Do you like italian food? (Please answer with yes or no.)<br />";
$parameters = array("varname"    => "italfood",
                    "type"       => "text",
                    "attributes" => "style=\"\" class=\"myclass\"",
                    "mandatory"  => "r:/^(yes|no)$/");
echo fsAdd(fsFormElement($parameters);

TO BE WRITTEN: fsAdd and fsFormElement should only be called for elements on the active page. This is bad: $html = fsAdd("{bla}"); if (thispage) echo $html;

Setting form element parameters


Supported form element parameters

Variable name ("varname")

This is the only obligatory parameter needed for every form element. The posted value will be saved in a column of that name in the database table. The variable name must contain only word characters (a-z, A-Z, 0-9, _).

Note: Never use the varname "id", as flexSURVEY uses "id" as the primary index key of each table.

Element type ("type")

This defines the kind of form element. The following table lists possible values and their possible abbreviations which can be used instead. I assume you know HTML's form elements, so the table should be self-explanatory. The HTML form element for file upload is currently not supported.


To set this parameter in the curly-braces markup, just write the type or its abbreviation into the parameter list.


echo fsAdd("Please insert your story:<br />{story|textarea}");
echo fsAdd("Please decide! {decision|r} yes, {decision} no.

If the type is not specified for some form element then flexSURVEY decides in this order:

  • If the same variable name has been used in the same call of fsAdd(), which only makes sense for type radio, then type is radio.
  • If it is not the first element of the page, use the type of the previous element.
  • If it is the first element of the page, use type "text".

Value or options of select elements ("value")

For elements of type text, password, and hidden the default value is put in the element's XHMTL value attribute, but only if the user did not already send a different value (i.e. if there is no other value for the user in the database). The result could look like this:

<input name="pizza" type="text" value="VALUE" />

For elements of type radio and checkbox the value will always be written in the element's XHTML attribute. If the value matches the value in the database, checked="checked" will be added.

For elements of type radio, the default value is "__FSNR__". This is a special markup which will be translated into a number, namely "1" for the first radio element of the same name, "2" for the second, and so forth.

<input name="size" type="radio" value="1" /> XL,
<input name="size" type="radio" value="2" checked="checked" /> XXL

For elements of type textarea the value is what is put between the opening and closing XHTML tags if there is no other value in the database.

<textarea name="story">VALUE</textarea>

For elements of type select the value is what is put between the opening and closing XHTML tags. This is actually all the "<option>" tags and their contents.

<select name="pizza">
<option value="1">Margherita</option>
<option value="2">Quattro formaggi</option>
<option value="3">Calzone</option>

To set this parameter in the curly-braces markup, use ":" as a prefix:

echo fsAdd("Name:<br />{name|text|:Insert here...}");
echo fsAdd("Do you agree? {decision|checkbox|:y} Yes.");

For elements of type select, the ":" can be ommited. flexSURVEY will see that the string starts with "<option" and treat it as the value parameter. You can change the prefix character by setting $fscfg["indicatorstr"]["value"].

Values for unchecked radio and checkbox elements ("ucvalue")

This is the value to be saved in the database if the checkbox is not checked or if none of the radio elements of the same name are checked. If the default value in the database column is different to the ucvalue parameter you can tell whether the user has not submitted the page carrying the form element or whether it was left unchecked.

The "ucvalue" parameter can not be set within the curly-braces markup.

Pre-checking checkboxes or radio buttons ("checked")

Set this to TRUE in order to make the checkbox or radio button being checked by default.

To set this parameter in the curly-braces markup, use "+". You can change the character by setting $fscfg["indicatorstr"]["checked"].

echo fsAdd("{box1,checkbox,+} I am checked when you first come to my page.");
echo fsAdd("{box2,checkbox} I am unchecked when you first come to my page.");

Rules for mandatory user input ("mandatory")

Use this parameter to set rules that need to be followed by the user to proceed to the next page. For example, you can force a text field to include special characters or to be of a certain length, or you can force a certain radio element to be checked. By including your own function which checks validity, you could e. g. check whether the value is unique in the database (when asking users for a new username) or force a LDAP login before continuing.

Note that the rule check compares the criterion with the saved value in the database, not with the posted value. Saved and posted can differ if you set the runfunction parameter. The "mandatory" parameter thus will not prohibit certain values being saved but rather the user proceeding to the next page.

To set this parameter in the curly-braces markup, use "?" as a prefix. You can change the prefix character by setting $fscfg["indicatorstr"]["mandatory"].

The first character after the "?" must be a character indicating the type of rule used:

svalue must equal a given string
rvalue must match a given (perl-compatible) regular expression
cthe checkbox or one of the radio buttons must be checked
evalue(s) checked by code evaluation

The second character after the "?" is a separation character. It is ignored. I usually use ":".

Here is an example of using a regular expression rule. Please see PHP's documentation of its PCRE implementation for information about the syntax.

//Note: you will find better adresse-matching regexp in the www.
echo fsAdd("e-mail: {email,text,?r:/[a-zA-Z0-9\.]+@[a-zA-Z0-9\.]+/}");

When the first character after the "?" is "e", flexSURVEY will take the parameter as a PHP expression that is either TRUE or FALSE. To make things easier, some magic is supported: "[varname]" will be replaced by the value, saved in database column varname. Here is an example:

echo fsAdd("e-mail: {email|text|?e:strlen([email]) >= 6}");
// Two out of three checkboxes with value 1 and ucvalue 0 each need to
// be checked (be careful if you use other ucvalue!):
echo fsAdd("{cb1|checkbox|?e:[cb1] + [cb2] + [cb3] == 2}");

Here is an example of forcing a certain radio button to be choosen:

//Second needs to be checked.
echo fsAdd("{license,r,?s:2} No, I do not agree with this license.<br />
            {license} Yes, I totally agree.<br />
            {license} Well, not sure yet."

Any other attributes (including CSS) for the form element ("attributes", "attributesmarkup")

These parameters allow for inclusion of arbitrary attributes into the XHTML of the form elements. You can e.g. use them for adding CSS style definition or JavaScript event-handlers.

The "attributes" parameter and the "attributesmarkup" parameter have the same effect. The "attributes" parameter should be used when setting parameters in $fscfg["param_by_type"] or $fscfg["param_by_name"]. The "attributesmarkup" is set by flexSURVEY when translating the curly-braces markup. By having those two separate parameters you can combine those two ways of setting additional attributes, i. e. they do not overwrite each other.

To set this parameter in the curly-braces markup, just add it to the list without any prefix:

echo fsAdd("Name: {name,text,style=\"color:red;\",onmouseover=\"this.focus();\"}");

In the above example you could as well change the "," between the two attributes (style and onmouseover) into a space - it would then be one attribute parameter with two attributes. Both is possible.

flexSURVEY supports even easier inclusion of CSS definition, so instead of the above you could write

echo fsAdd("Name: {name,text,color:red;,onmouseover=\"this.focus();\"}");

When flexSURVEY looks for parameters and finds "color:red;" it will notice that there is no "=" character in this parameter string. If that is the case then "style=\"\"" will automatically be added. Isn't that cool? Thus, in this example the "," is needed between the CSS and the onmouseover.

Two special markups can be used and are automatically translated: "__FSNAME__" as part of an attribute will be replaced by the variable name respectively and "__FSNR__" will be replaced by the number this radio button is in the sequence of radio buttons of equal variable name. For example this is useful for defining the default values of radio buttons:

$fscfg["param_by_type"]["radio"]["value"] = "__FSNR__";
$fscfg["param_by_type"]["radio"]["attr1"] = "id=\"__FSNAME____FSNR__\"";

The first row makes radio buttons have values "1", "2", "3", ... . The second row will add an id attribute to radio buttons (e.g. for usage of XHTML's label tag), e.g. "id=\"name3\".

Database related parameters ("dbcolumntype", "dbtable", "dbcolumn", "dbid")

These parameters can not be set within the curly-braces markup.

Parameter "dbcolumntype" is a column type definition as understood by MySQL. Further, it must contain the word "DEFAULT" followed by the default value. (This is because flexSURVEY cuts the default value from this string in order to compare it with the actual value in the database.)

$fscfg["param_by_type"]["checkbox"]["dbcolumntype"] = "SMALLINT DEFAULT -101";

Parameter "dbtable" defines the database table in which to save this variable. It overwrites $fscfg["mysql"]["table"] and is useful if you want to save different variables to different tables.

Parameter "dbcolumn" defines the database column name in which to save the variable. Usually the column name is the same as the variable name, but "dbcolumn" overwrites that default.

Parameter "dbid" sets the table row in which to save the value. Experts only! Be sure you know what you are doing.

TO BE WRITTEN: more details, especially about dbid.

Running posted values through a function ("runfunction")

Parameter "runfunction" can not be set within the curly braces markup.

Setting this parameter makes flexSURVEY calling a function with the posted value of the variable as its parameter and saving the value returned by the function instead of the posted one. To send the value through more than one function, you can use an array:

$fscfg["param_by_type"]["*"]["runfunction"] = "trim";
$fscfg["param_by_name"]["mypassword"]["runfunction"] = "myencryptfunction";
$fscfg["param_by_name"]["myotherpassword"]["runfunction"] = array("strtolower", "myencryptfunction");

You can of course use "runfunction" in order to run a function that does not change the variable's value. E. g. you could write a function that takes the posted value as a parameter, then emails certain variables to you, and returns the unchanged value. Whenever the variable is posted, the function will be called and you receive the email.



Function reference


Variable reference


Item boxes, progress bar, ...

flexSURVEY does not provide such elements. It is your job. However, you can copy the code from the demo survey.



Page last modified on August 18, 2010, at 08:43 AM