Recientemente me vi en la necesidad de implementar un sistema de encuestas para una Intranet. Buscando en la web encontré varias alternativas bastante útiles e innovadoras en algunos casos. Sin embargo, mi requerimiento era algo sencillo que permitiera incluirla en un CMS ya existente que esta implementada y no pude encontrar nada “sencillo”, es decir, sin administración independiente y que me permitiera manejar las encuestas con bastante rapidez.
Al no encontrar nada que pudiera satisfacer mi necesidad; decidí desarrollar mi propio sistema de encuestas el cual quiero compartir con ustedes.
Estos son los requerimientos para que este sistema script de encuestas funcione:
– PHP 5.x (http://php.net/)
– MySql 5.0.22 o superior (http://dev.mysql.com/downloads/mysql/5.5.html)
– PHP MySQL wrapper (http://www.ricocheting.com/code/php/mysql-database-class-wrapper)
– phpMyAdmin (http://www.phpmyadmin.net/)
– jQuery mediante google jsapi (http://www.google.com/jsapi)
El script es bastante sencillo y opera bajo una variable de url que maneja la validación y el query.
Primero necesitaremos crear una base de datos en MySql. Vamos a llamarla “encuestas”
Luego procedemos a crear las tablas necesarias utilizando phpmyadmin, suponiendo que lo tenemos configurado como nuestro administrador de mysql:
Tabla “surveys” que contiene el titulo, descripción y el “survey_id” el cual nos servirá para enlazar las preguntas y sus respuestas.
CREATE TABLE `surveys` ( `survey_id` int(11) NOT NULL auto_increment, `survey_title` varchar(120) NOT NULL, `survey_text` text, `survey_code` varchar(128) default NULL, `survey_status` varchar(15) default NULL, PRIMARY KEY (`survey_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Tala “survey_q” que alojará las preguntas de cada una de nuestas encuestas
CREATE TABLE `surveys_q` ( `q_id` int(11) NOT NULL auto_increment, `survey_id` int(11) NOT NULL, `q_format` varchar(30) default NULL, `q_text` varchar(120) default NULL, `q_createdby` varchar(32) default NULL, `q_createddate` datetime default NULL, `q_status` varchar(3) default NULL, PRIMARY KEY (`q_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Tabla “surveys_o que alojara las posibles respuestas a seleccionar por cada pregunta.
CREATE TABLE `surveys_o` ( `o_id` int(11) NOT NULL auto_increment, `o_text` varchar(120) default NULL, `o_value` varchar(120) default NULL, `survey_id` int(11) default NULL, `q_id` int(11) default NULL, `o_status` varchar(3) default NULL, PRIMARY KEY (`o_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Tabla “surveys_a” que almacenará las respuestas con el valor de la opción seleccionada para cada pregunta de nuestras encuestas.
CREATE TABLE `surveys_a` ( `a_id` int(11) NOT NULL auto_increment, `survey_id` int(11) NOT NULL, `q_id` int(11) NOT NULL, `o_id` int(11) NOT NULL, `o_value` varchar(120) default NULL, `a_date` datetime default NULL, `a_remoteip` varchar(30) default NULL, PRIMARY KEY (`a_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Por último, la tabla “surveys_c” que utilizaremos para almacenar algún comentario del encuestado para cada survey. Esto es por si queremos permitir que nuestro conosultado nos escriba algun comentario relacionado con la encuesta a procesar.
CREATE TABLE `surveys_c` ( `c_id` int(11) NOT NULL auto_increment, `survey_id` int(11) NOT NULL, `c_text` text, `c_status` varchar(3) default NULL, `c_remoteip` varchar(30) default NULL, PRIMARY KEY (`c_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Antes de continuar, es importante notar los campos “survey_id” y “q_id”; uno guarda la relación con el survey que agrupará las preguntas y el segundo relaciona la opción y respuesta con su pregunta respectivamente.
El campo “a_remoteip” de la tabla “surveys_a” para controlar por IP el que la encuesta pueda ser completada una sola vez por encuestado.
Ya tenemos la estructura de datos. Procederemos a crear una encuesta de prueba o “demo”.
Primero insertaremos los datos de nuestro survey.
INSERT INTO `surveys` VALUES (1, 'Customer Service Satisfaction Survey', '<h3>Thank you for tacking our customer service questionnaire.</h3><p>Your opinion is valuable to us. It will take only 2-3 minutes to complete. We''ll use your opinions to take stock of our service and to make improvements.</p>', 'c4ca4238a0b923820dcc509a6f75849b', 'Open');
Notemos el valor “Open” para el campo “survey_status”. Esto como modo de seguridad para tener varias fases de nuestra encuesta para futura ampliación del sistema de encuestas. Los valores pueden ser (Open, Edit, Test, Closed).
Ahora vamos a crear las preguntas y sus opciones de respuesta:
Las preguntas:
INSERT INTO `surveys_q` VALUES (1, 1, 'Radio', 'How many times did you stay at our resorts?', NULL, '2010-09-15 10:53:27', 'on'); INSERT INTO `surveys_q` VALUES (2, 1, 'Radio', 'How would you rate your overall experience?', NULL, '2010-09-15 10:55:03', 'on'); INSERT INTO `surveys_q` VALUES (3, 1, 'Radio', 'Was the call center agent friendly?', NULL, '2010-09-15 10:56:12', 'on'); INSERT INTO `surveys_q` VALUES (4, 1, 'Radio', 'Please rate the knowledge of the call center agent?', NULL, '2010-09-15 10:56:53', 'on'); INSERT INTO `surveys_q` VALUES (5, 1, 'Radio', 'How would you rate the condition of our properties?', NULL, '2010-09-15 10:57:43', 'on'); INSERT INTO `surveys_q` VALUES (6, 1, 'Radio', 'Tell us what motivated you to cancel your membership?', NULL, '2010-09-15 10:58:58', 'on'); INSERT INTO `surveys_q` VALUES (7, 1, 'Radio', 'Did the condition of our properties influence your decision to cancel?', NULL, '2010-09-15 11:00:23', 'on'); INSERT INTO `surveys_q` VALUES (8, 1, 'Radio', 'If yes, how much?', NULL, '2010-09-15 11:00:56', 'on'); INSERT INTO `surveys_q` VALUES (9, 1, 'Radio', 'Would you consider visiting us again?', NULL, '2010-09-15 11:01:36', 'on');
Las opciones o posibles respuestas.
INSERT INTO `surveys_o` VALUES (1, '1-2', '1-2', 1, 1, 'on'); INSERT INTO `surveys_o` VALUES (2, '3-4', '3-4', 1, 1, 'on'); INSERT INTO `surveys_o` VALUES (3, '5-8', '5-8', 1, 1, 'on'); INSERT INTO `surveys_o` VALUES (4, '8+', '8+', 1, 1, 'on'); INSERT INTO `surveys_o` VALUES (5, 'Excelent', 'Excelent', 1, 2, 'on'); INSERT INTO `surveys_o` VALUES (6, 'Satisfactory', 'Satisfactory', 1, 2, 'on'); INSERT INTO `surveys_o` VALUES (7, 'Needs improvements', 'Needs improvements', 1, 2, 'on'); INSERT INTO `surveys_o` VALUES (8, 'Poor', 'Poor', 1, 2, 'on'); INSERT INTO `surveys_o` VALUES (9, 'Yes', 'Yes', 1, 3, 'on'); INSERT INTO `surveys_o` VALUES (10, 'No', 'No', 1, 3, 'on'); INSERT INTO `surveys_o` VALUES (11, 'Excelent', 'Excelent', 1, 4, 'on'); INSERT INTO `surveys_o` VALUES (12, 'Satisfactory', 'Satisfactory', 1, 4, 'on'); INSERT INTO `surveys_o` VALUES (13, 'Needs improvements', 'Needs improvements', 1, 4, 'on'); INSERT INTO `surveys_o` VALUES (14, 'Poor', 'Poor', 1, 4, 'on'); INSERT INTO `surveys_o` VALUES (15, 'Excelent', 'Excelent', 1, 5, 'on'); INSERT INTO `surveys_o` VALUES (16, 'Satisfactory', 'Satisfactory', 1, 5, 'on'); INSERT INTO `surveys_o` VALUES (17, 'Needs improvements', 'Needs improvements', 1, 5, 'on'); INSERT INTO `surveys_o` VALUES (18, 'Poor', 'Poor', 1, 5, 'on'); INSERT INTO `surveys_o` VALUES (19, 'Job loss', 'Job loss', 1, 6, 'on'); INSERT INTO `surveys_o` VALUES (20, 'Economic uncertainty', 'Economic uncertainty', 1, 6, 'on'); INSERT INTO `surveys_o` VALUES (21, 'Dissatisfaction with service', 'Dissatisfaction with service', 1, 6, 'on'); INSERT INTO `surveys_o` VALUES (22, 'A bit of all from above', 'A bit of all from above', 1, 6, 'on'); INSERT INTO `surveys_o` VALUES (23, 'Other', NULL, 1, 6, 'on'); INSERT INTO `surveys_o` VALUES (24, 'Yes', 'Yes', 1, 7, 'on'); INSERT INTO `surveys_o` VALUES (25, 'No', 'No', 1, 7, 'on'); INSERT INTO `surveys_o` VALUES (26, 'Not at all', 'Not at all', 1, 8, 'on'); INSERT INTO `surveys_o` VALUES (27, 'Little bit', 'Little bit', 1, 8, 'on'); INSERT INTO `surveys_o` VALUES (28, 'It was decisive', 'It was decisive', 1, 8, 'on'); INSERT INTO `surveys_o` VALUES (29, 'It was the main reason', 'It was the main reason', 1, 8, 'on'); INSERT INTO `surveys_o` VALUES (30, 'Yes', 'Yes', 1, 9, 'on'); INSERT INTO `surveys_o` VALUES (31, 'No', 'No', 1, 9, 'on');
Pongamos atención a la opción “o_id” con el valor “23”. Perteneciente a la encuesta “survey_id” con el valor 1; pregunta “q_id” con el valor 6, ya que el valor del campo “o_value” es NULL. Esto es indicativo de que es una opción de respuesta con el valor indicado por el encuestado mediante un text input, el cual es generado automáticamente bajo esta condición, como veremos en el archivo del script mas adelante.
A continuación vamos a crear nuestra estructura de archivo.
– Creamos una carpeta en nuestro servidor web a la cual vamos a llamar “encuesta”.
– Dentro de la carpeta “encuesta”, crearemos otra llamada “includes”.
– Colocamos dentro de “includes” el archivo “database.class.php”, suponiendo que descargaste el PHP MySQL wrapper.
– Creamos un archivo, el cual llamaremos “config.inc.php” tambien dentro de la carpeta “includes”.
– Creamos un archivo llamado “index.php” dentro de la carpeta “encuesta”, suponiendo que queremos que sea nuestro script para ser llamado mediante la url por defecto.
Esta seria nuestra estructura:
/encuesta/
/encuesta/includes/
/encuesta/includes/database.class.php
/encuesta/includes/config.inc.php
/encuesta/index.php
En nuestro archivo “/includes/config.inc.php”, tendremos las siguientes lineas de configuracion de nuestro PHP MySQL wrapper:
//database server $config['server'] = "localhost"; //database login name $config['user'] = "user"; //database login password $config['pass'] = "pass"; //database name $config['database'] = "encuestas"; // table prefix $config['tablePrefix'] = "";
Y en nuestro archivo index.php, tendremos lo siguiente:
<?php session_start(); include_once("includes/config.inc.php"); include_once("includes/database.class.php"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Encuesta de Satisfaccion</title> <script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript"> google.load("jquery", "1.4"); </script> </head> <?php $db = new Database($config['server'],$config['user'],$config['pass'],$config['database'],$config['tablePrefix']); $db->connect(); if(isset($_POST['survey_']) && is_numeric($_POST['survey_'])){ $sql = "SELECT * FROM surveys_a WHERE survey_id = '".$_POST['survey_']."' AND a_remoteip = '".$_SERVER['REMOTE_ADDR']."'"; $result = $db->query($sql); if($db->affected_rows > 0){ echo "<div class=\"warning-box\">You have already taken this survey!. You will be redirected to our main website.</div>\n"; echo "<meta http-equiv=\"refresh\" content=\"3;URL=https://www.weblantropia.com\">"; exit; } //for each question foreach($_POST['qid'] as $q){ if($_POST['question'][$q] != NULL){ //explode $answer array items to get answer id and value $answer = explode("_",$_POST['question'][$q]); $data['survey_id'] = $_POST['survey_']; $data['q_id'] = $q; $data['o_id'] = $answer[0]; if(!($answer[1]) || $answer[1] == NULL) { $data['o_value'] = $_POST['other'][$q]; }else{ $data['o_value'] = $answer[1]; } $data['a_date'] = date("Y-m-d h:i:s a"); $data['a_remoteip'] = $_SERVER['REMOTE_ADDR']; $db->query_insert("surveys_a", $data); unset($data); } } //insert comment if(isset($_POST['comment']) && $_POST['comment']!=""){ $data['survey_id'] = $_POST['survey_']; $data['c_text'] = $_POST['comment']; $data['c_status'] = 'on'; $data['c_remoteip'] = $_SERVER['REMOTE_ADDR']; $db->query_insert("surveys_c", $data); unset($data); } $message = "<div class=\"warning-box\">Thank you! All your answers are confidential and help us to serve you better.!</div>\n"; } //explode url to get survey conde and id $survey = explode("_",$_REQUEST['survey']); $survey_id = $survey[1]; $survey_code = $survey[0]; if (!isset($_REQUEST['mode'])){ $mode = "Open"; }else{ $mode = $_REQUEST['mode']; } if(!(isset($_POST['survey_']))){ $sql = "SELECT * FROM surveys_a WHERE survey_id = '".$survey_id."' AND a_remoteip = '".$_SERVER['REMOTE_ADDR']."'"; $result = $db->query($sql); if($db->affected_rows > 0){ echo "<div class=\"warning-box\">You have already taken this survey!. You will be redirected to our main website.</div>\n"; echo "<meta http-equiv=\"refresh\" content=\"3;URL=https://www.weblantropia.com\">"; exit; } } //Query the request survey $sql = "SELECT * FROM surveys as s LEFT JOIN surveys_q as q ON s.survey_id = q.survey_id WHERE s.survey_code = '".$survey_code."' AND s.survey_status = '".$mode."' AND s.survey_id = '".$survey_id."' AND q.q_status = 'on' ORDER BY q.q_id ASC"; $result = $db->query($sql); if($db->affected_rows <= 0){ echo "<div class=\"warning-box\">No survey was found!. You will be redirected to our main website.</div>\n"; echo "<meta http-equiv=\"refresh\" content=\"3;URL=https://www.weblantropia.com\">"; exit; } ?> <body> <div id="header"> <div id="oval"><img src="images/pixel.gif" width="58" height="45" /></div> <div id="title">Encuesta de Satisfaccion</div> <div id="options"> </div> </div> <?php echo $message; ?> <div id="content"> <div id="top"> <div id="survey_title"></div> <div> </div> </div> <div id="container"> <div id="survey_text"> </div> <form id="survey_form" name="survey_form" method="post" action=""> <input type="hidden" name="survey_" id="survey_" value="<?php echo $survey_id; ?>"> <?php $display_number = 1; while($row = $db->fetch_array($result)){ $q_format = $row['q_format']; $title = $row['survey_title']; $text = $row['survey_text']; $q_id = $row['q_id']; ?> <div><?php echo $display_number; ?>. <?php echo $row['q_text']; ?></div> <input type="hidden" name="qid[]" id="qid[]" value="<?php echo $row['q_id']; ?>"> <?php $sqlo = "SELECT * FROM surveys_o WHERE survey_id = '".$row['survey_id']."' AND q_id = '".$row['q_id']."' AND o_status = 'on'"; $resulto = $db->query($sqlo); if($q_format == "Dropdown"){ echo "<div class=\"option\">\n"; echo "<select name=\"question[$q_id]answer\">\n"; while($rowo = $db->fetch_array($resulto)){ echo "<option value=\"".$rowo['o_id']."_".$rowo['o_value']."\">".$rowo['o_text']."</option>\n"; } echo "</select>\n"; echo "</div>\n"; }elseif($q_format == "Radio"){ while($rowo = $db->fetch_array($resulto)){ echo "<div class=\"option\">\n"; echo "<input type=\"radio\" name=\"question[$q_id]answer\" value=\"".$rowo['o_id']."_".$rowo['o_value']."\">\n"; echo "<label>".$rowo['o_text']."</label>\n"; if($rowo['o_value'] == NULL){ echo "<input type=\"text\" name=\"other[$q_id]answer\" value=\"\">\n"; } echo "</div>\n"; } }else{ } ?> <?php $display_number++; }//end while ?> <div>Comments</div> <textarea name="comment" cols="60" rows="5" wrap="soft"></textarea> <script type="text/javascript"> jQuery("#survey_title").html("<?php echo $title; ?>"); jQuery("#survey_text").html("<?php echo $text; ?>"); </script> <div style="height:30px"> </div> <div style="padding:5px;"> <input name="submit" type="submit" value="Submit" onclick="this.disabled=true" /> <input name="reset" type="reset" /> </div> </form> </div> <div id="bottom"> </div> </div> <div style="height:60px"> </div> <script type="text/javascript"> </script> </body> </html>
Ahora llamamos la encuesta mediante la url:
http://localhost/encuesta/?survey=c4ca4238a0b923820dcc509a6f75849b_1
Fijémonos en el valor de la variable “survey” la cual tiene un valor string. Este valor en realidad contiene dos parámetros separados por “_’.
El primero, el string o cadena “c4ca4238a0b923820dcc509a6f75849b” la cual es un código cualquiera que deseemos utilizar con fines de validar la solicitud de la encuesta a tomar.
El segundo, el entro “1”, el cual indica el “survey_id” que quermos presentar.
Ambos valores deben coincidir con los de la encuesta en la tabla “surveys” para cada encuesta; de lo contrario nos indicara que la encuesta seleccionada no existe.
Por ejemplo, si creamos otra encuesta, según el index key seria la “survey_id” con valor 2, entonces colocaremos en el campo “survey_code” el string “asdfg”, entonces para llamar nuestra segunda encuesta sería:
http://localhost/encuesta/?survey=asdfg_2
Listo. Nuestro propio sistema de encuesta base a partir del cual podemos desarrollar algo mas robusto; con la versatilidad de poder incorporarlo en cual quier sistema que estemos desarrollando o para una pagina web.
Es importante que recuerdes que este script no tiene una rigurosa seguridad puesto que fue desarrollado para implementarlo en una intranet con controles de seguridad terceros. Por lo que, si vas a tomarlo como base para una aplicación web o pagina, es necesario que trabajes mas la seguridad.
Espero les se de utilidad.
“CODE IS POETRY”.
oe man te falta poner el codigo del archivo
database.class.php
si lo pones antes le lo voy agraceder,
saludos
Puedes verlo y copiarlo aqui: http://www.ricocheting.com/static/code/php/mysql/Database.class.phps o descargarlo directamente desde: http://www.ricocheting.com/code/php/mysql-database-class-wrapper
me marca el siguiente error
Database Error
Message: Could not connect to server: .
MySQL Error: Access denied for user ‘ODBC’@’localhost’ (using password: NO)
Date: Friday, December 10, 2010 at 11:24:39 AM
Script: /encuesta/?survey=c4ca4238a0b923820dcc509a6f75849b_1
Database Error
Message: Could not open database: .
MySQL Error: Access denied for user ‘ODBC’@’localhost’ (using password: NO)
Date: Friday, December 10, 2010 at 11:24:39 AM
Script: /encuesta/?survey=c4ca4238a0b923820dcc509a6f75849b_1
Database Error
Message: MySQL Query fail: SELECT * FROM surveys_a WHERE survey_id = ‘1‘ AND a_remoteip = ‘127.0.0.1‘
MySQL Error: Access denied for user ‘ODBC’@’localhost’ (using password: NO)
Date: Friday, December 10, 2010 at 11:24:39 AM
Script: /encuesta/?survey=c4ca4238a0b923820dcc509a6f75849b_1
Database Error
Message: MySQL Query fail: SELECT * FROM surveys as s LEFT JOIN surveys_q as q ON s.survey_id = q.survey_id WHERE s.survey_code = ‘c4ca4238a0b923820dcc509a6f75849b‘ AND s.survey_status = ‘“Openâ€â€˜ AND s.survey_id = ‘1‘ AND q.q_status = ‘on’ ORDER BY q.q_id ASC
MySQL Error: Access denied for user ‘ODBC’@’localhost’ (using password: NO)
Date: Friday, December 10, 2010 at 11:24:39 AM
Script: /encuesta/?survey=c4ca4238a0b923820dcc509a6f75849b_1
Revisa el user/pass de tu base de datos y en la configuración en el archivo config.inc.php.
Gracias por el aporte. Pero ya que los requerimientos piden
PHP 5.x, por que no utilizar PDO? >
http://blog.tordek.com.ar/2010/11/pdo-o-por-que-todos-los-tutoriales-de-php-llevan-a-las-malas-practicas/
>
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
Excelente tu aporte, y mejor la pregunta. Puedes utilizar cualquier controlador de datos que desees. Indico la librería mencionada por la flexibilidad que esta presenta y lo fácil de su uso. PDO es otra alternativa mejorada para PHP 5.x. Sin embargo, PDO presenta ciertas restricciones y una observación importante que hace PHP.net: “Algunos tipos de tablas MySQL (motores de almacenamiento) no son compatibles con las transacciones. Cuando se escriba código de base de datos transaccional usando un tipo de tabla que no soporta transacciones, MySQL supondrá que una transacción fue iniciada con éxito. Además, cualquier consulta DDL emitida validará implícitamente cualquier transacción pendiente. “.
Nice site ….)