Trivial 2.0: Responder pregunta

Cuando el usuario pinche en un botón tendremos que averiguar si la respuesta es correcta y guardar el resultado de la acción en la base de datos. Es más sencillo de lo que parece. En primer lugar enlazamos el click de los botones por jQuery:

  $('button').click(function () {
....
}

Ahí tendremos que hacer dos cosas. Comprobar que la respuesta es correcta o no y mostrar un mensaje en consecuencia y guardar en la base de datos. Lo primero es simple:

 var puntos = 0;
        if ($(this).text() === preguntas.correcta) {
            $('#mensaje').html('<div class="alert alert-success alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Bien! </strong> Respuesta correcta.</div>')
            puntos = 1;
        } else {
            $('#mensaje').html('<div class="alert alert-danger alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Error! </strong> Respuesta incorrecta.</div>')

        }

Lo segundo, también:

$.post("resultado.php", {idPregunta: preguntas.id, puntos: puntos}, function (datos, status) {
            $('#puntuacion').text(datos);
            cargarPregunta();
        });

Todo junto:

 $('button').click(function () {
        var puntos = 0;
        //Comprobamos que el botón pulsado es la respuesta correcta
        if ($(this).text() === preguntas.correcta) {
            $('#mensaje').html('<div class="alert alert-success alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Bien! </strong> Respuesta correcta.</div>')
            puntos = 1;
        } else {
            $('#mensaje').html('<div class="alert alert-danger alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Error! </strong> Respuesta incorrecta.</div>')

        }
        //Escondemos el tablero para queno pueda pulsar más botones
        $(".tablero").hide();
        //LLamamos por ajax con post para guardar los resultados, la función nos devuelve la puntuación
        $.post("resultado.php", {idPregunta: preguntas.id, puntos: puntos}, function (datos, status) {
            $('#puntuacion').text(datos);
            cargarPregunta();
        });

    });

La página a la que llamamos se limita a guardar los datos y devolver la puntuación:

<?php
require_once 'libreria.php';
session_start();
//Recuperamos los datos
$idUsuario= $_SESSION['idUsuario'];
$idPregunta= filter_input(INPUT_POST, 'idPregunta');
$puntos= filter_input(INPUT_POST, 'puntos');
//Y guardamos el resultado
$puntos=guardaResultado($idUsuario,$idPregunta,$puntos);
//Devolvemos los puntos
echo $puntos;

Guardar resultado es un simple insert:

function guardaResultado($idUsuario, $idPregunta, $puntos) {
    try {
        $conn = conectar();
        $sql = "insert into resultados (idusuarios,idpreguntas,puntos) values (:idu,:idp,:puntos)";
        $st = $conn->prepare($sql);
        $st->execute(['idu' => $idUsuario, 'idp' => $idPregunta, 'puntos' => $puntos]);
        return getPuntuacion($idUsuario);
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Y obtener los resultados un simple sql:

function getPuntuacion($idUsuario) {
    try {
        $conn = conectar();
        $sql = "SELECT ifnull(sum(puntos),0) puntuacion FROM resultados where idusuarios=:id";
        $st = $conn->prepare($sql);
        $st->execute(['id' => $idUsuario]);
        $fila = $st->fetch();
        return $fila['puntuacion'];
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Trivial 2.0: Recuperar pregunta por ajax

Para recuperar las preguntas por ajax necesitamos tres cosas. Una llamada con ajax desde JS. Una página en PHP que busque la pregunta y la devuelva. Y, como somos ordenaditos, una función en la librería que busque la pregunta.

Empecemos por el JS, que se limita a pedir la pregunta:

var preguntas;
//Busca una pregunta por Ajax
function cargarPregunta() {
    $.get("pregunta.php", function (datos, status) {

        if (status == "success") {
            preguntas = JSON.parse(datos);
            pintarPregunta();
        }
    });
}
//Pinta la pregunta en nuestro HTML
function pintarPregunta() {
    $('#pregunta').text(preguntas.pregunta);
    $('#res1').text(preguntas.respuestas[0]);
    $('#res2').text(preguntas.respuestas[1]);
    $('#res3').text(preguntas.respuestas[2]);
    $('#res4').text(preguntas.respuestas[3]);
    $(".tablero").show();
    $('#mensaje div').fadeOut();
}

El backend en php, donde llama el ajax, es sólo un poco más complicado:

<?php

require_once 'libreria.php';
session_start();
//Obtenemos una pregunta de la base de datos
$fila = getPregunta($_SESSION['idUsuario']);

//La fila que recuperamos la organizamos de una manera más amigable para el JS
$res['pregunta'] = $fila['pregunta'];
$res['id'] = $fila['idpreguntas'];
$res['correcta'] = $fila['respuesta1'];
$res['respuestas'] = [$fila['respuesta1'], $fila['respuesta2'], $fila['respuesta3'], $fila['respuesta4']];
shuffle($res['respuestas']);

//Lo codificamos en JSON
echo json_encode($res);

Por último necesitamos en nuestra librería una función que nos busque una pregunta en la BD y nos la devuelva:

function getPregunta($idUsuario) {
    try {
        $conn = conectar();
        //Buscamos una pregunta que no se haya hecho a este usuario al azar
   $sql = "SELECT * FROM trivial.preguntas where idpreguntas not in (select idpreguntas from resultados where idusuarios=$idUsuario) order by rand() limit 1";
            $resul = $conn->query($sql);
        $fila = $resul->fetch();
        return $fila;
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Trivial 2.0: Página de juego

Lo primero que tendremos en nuestra página de juego es una comprobación de que el usuario se haya logueado:

<?php
session_start();
//Si no está definida la variable de sesión es que no se ha logueado, lo mandamos al login
if (empty($_SESSION['idUsuario'])){
    header("location:login.php");
}
require_once("libreria.php");
//Recuperamos la puntuación para mostrarla
$puntuacion= getPuntuacion($_SESSION['idUsuario']);
?>

De paso recuperamos la puntuación (lo veremos más adelante).

La página de juego es una página muy sencilla con sólo html. La mecánica del juego la tenemos en el javascript. Puede ser algo como esto:

 <div class="container" >
            <div class="jumbotron">
                <h1 class="display-1">Trivial. Bienvenido <?=$_SESSION['nombre']?></h1>
                <p>¿Cual es tu cultura general? Puntuación: <span id="puntuacion"><?=$puntuacion?></span></p>
            </div>
            <div class="row">
                <div class="col-12" id="mensaje" style="min-height: 70px;"></div>
            </div>
            <div class="row tablero">
                <div class="col-12"><h1 id="pregunta" class="text-center">Bienvenido al trivial. Muy pronto preguntas</h1></div>
            </div>
            <div class="row my-4 tablero">

                <div class="col-6 text-center"><button id="res1" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res2" class="btn btn-lg btn-success">.</button></div>

            </div>

            <div class="row tablero">

                <div class="col-6 text-center"><button id="res3" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res4" class="btn btn-lg btn-success">.</button></div>

            </div>
        </div>
        <script src="trivial.js" type="text/javascript"></script>

Trivial 2.0: Login

Lo primero que vamos a hacer es el Login. Necesitamos un formulario normal y corriente:

  <div class="container" >
            <div class="jumbotron">
            <h1>Introduce tu usuario y contraseña</h1>
            <h2>Si no estás en el sistema se creará tu usuario</h2>
            <h2 class="text-danger"><?=$error?></h2>
            </div>
            <form method="post">
                <div class="form-group">
                    <label for="nombre">Usuario:</label>
                    <input type="text" class="form-control" name="nombre">
                </div>
                <div class="form-group">
                    <label for="pwd">Password:</label>
                    <input type="password" class="form-control" name="password">
                </div>
                <button type="submit" class="btn btn-primary">Enviar</button>
            </form>
        </div>

Cuando se hace el submit recuperamos los datos y lo comprobamos en la BD:

<?php
require_once 'libreria.php';
$error="";
session_start();
//Recuperamos el valor de nombre y password
$nombre= filter_input(INPUT_POST, 'nombre');
$password= filter_input(INPUT_POST, 'password');

//Si no están vacíos es porque hay un registro o login, lo comprobamos en la BD
if (!empty($nombre) && !empty($password)){
    //La función comprobar Usuario nos devuelve el id del usuario si existe
    $idUsuario=comprobarUsuario($nombre,$password);
    //Si existe el usuario guardamos la información en la BD y redirigimos al index
    if ($idUsuario){
        $_SESSION['idUsuario']=$idUsuario;
        $_SESSION['nombre']=$nombre;
        header("location:index.php");
    } else{
        $error="Usuario o contraseña incorrecta";
    }
}
?>

La función comprobarUsuario está en libreria, y se encarga de gestionar el alta o comprobación:

function comprobarUsuario($nombre, $password) {
    try {
        $conn = conectar();
        //Buscamos un usuario con el nombre solicitado
        $sql = "select * from usuarios where nombre=:nombre";
        $st = $conn->prepare($sql);
        $st->execute(['nombre' => $nombre]);
        $usuario = $st->fetch();
        //Si no existe es un alta, lo insertamos en la BD
        if (!$usuario) {
            $st = $conn->prepare("insert into usuarios (nombre,password) values (:nombre,:password)");
            $st->execute(['nombre' => $nombre, 'password' => md5($password)]);
            //Y devolvemos el id del usuario insertado
            return $conn->lastInsertId();
        } else {
            //Si el usuario existe miramos si la contrasela coincide, si es así devolvemos el id
            if (md5($password) == $usuario['password']) {
                return $usuario['idusuarios'];
            }
        }
        //Si no se da ninguna de las condiciones devolvemos falso
        return false;
    } catch (Exception $ex) {
        echo $ex->getMessage();
        return false;
    }
}

Ejercicio Trivial con login (I)

Al ejercicio de clase vamos a añadirle un login y comprobación para que no se repitan las preguntas. Para ello añadimos a la base de datos la tabla usuarios y una tabla intermedia entre usuarios y preguntas.

TrivialLogin

La web se ha organizado de la siguiente manera:

login.php Página donde se pregunta al usuario su nombre y contraseña y se valida / da de alta

index.php La página donde se desarrolla el juego

libreria.php Página con librerías útiles de conexión a la base de datos

trivial.js La página de javascript que se encarga de hacer las peticiones de ajax.

pregunta.php La página de backend de Ajax que nos devuelve una fila de la base de datos

resultado.php La página de backend de Ajax que nos guarda los resultados que le pasemos.

Explicaremos estas páginas en próximas entradas.

Ejercicio trivial ‘pregunta.php’ con divide y vencerás

Nuestra página tiene que hacer lo siguiente:

– Buscar una pregunta en la base de datos al azar
– Guardar la información en una variable
– Codificarla en json e imprimirla.

Las preguntas son ¿Sabemos recuperar una fila de una base de datos? Deberíamos (PDO). El problema es que queremos una fila al azar. Bien, es tan sencillo como usar este sql:

select * from preguntas order by rand() limit 1

Una vez tenemos esto podemos directamente pasar la fila al javascript o podemos crear nuestra variable dándole un poco de formato:

Si mi fila es $fila sería algo así:

$res['pregunta']=$fila['pregunta'];
$res['correcta']=$fila['respuesta1'];
$res['respuestas']=[$fila['respuesta1'],$fila['respuesta2'],$fila['respuesta3'],$fila['respuesta4']];
shuffle($res['respuestas']);

He aprovechado para desordenar las respuestas. Una vez hecho esto sólo hay que codificar en json e imprimir.

Ejercicio trivial

Vamos a hacer una página de trivial.

Necesitamos una base de datos. La llamaremos trivial.

Esta base de datos tendrá una tabla preguntas,y los campos idpreguntas, pregunta,respuesta1,respuesta2,respuesta3 y respuesta4. La respuesta correcta siempre será la número uno.

Nuestra página index tendrá el siguiente aspecto:

Además de esto necesitaremos una página pregunta.php que haga lo siguiente:

– Recuperar una fila al azar de la base de datos
– Codificar esa fila como json
– Imprimirla

Y en nuestro index una función cargar pregunta que haga lo siguiente:
– Llamar por get a la página anterior
– Recuperar la información decodificando el json
– Pintar los valores donde toquen

Por último cuando se pinche en un botón:

– Comprobar si es la respuesta correcta, si es así le sumo uno a la puntuación y la muestro.
– Cargar otra pregunta

Ajax con json

<script>
            $(function () {
                var ana = {
                    nombre: "ana Pi",
                    sueldo: 1000,
                    hobbies: ["danza", "sellos", "fumar en pipa"],
                    empleados: [
                        {nombre: "Juan"}, {nombre: "Eva"}
                    ]
                };
                var cadena=JSON.stringify(ana);
                $.get("json_php.php?cadena="+cadena,function(datos,status){
                    
                    var tonteria=JSON.parse(datos);
                    console.log(tontneria);
                })
            });
        </script>
<?php

$cadena= filter_input(INPUT_GET, 'cadena');

$ana= json_decode($cadena);
$hobbies=$ana->hobbies;
$tonteria=[];
foreach($hobbies as $hobbie){
    $tonteria[]= strrev($hobbie);
}
$cadena=json_encode($tonteria);
echo $cadena;

Ajax con jQuery

  <input type="text" id="nombre">
        <input type="button" id="boton" value="Pinchar">

        <div id="resultado"></div>
        <script>
            $(function () {
                $('#boton').click(function () {
                    var datodelusuario = $('#nombre').val();
                    $.post("datos.php",
                            {nombre: datodelusuario},
                            function (datos, status) {

                                if (status == "success") {
                                    console.log(datos);
                                    var xmlDoc = $.parseXML(datos);
                                    console.log(xmlDoc);
                                }
                            });
                });
            })
        </script>
<?php

$nombre = filter_input(INPUT_POST, "nombre");
$server = "localhost";
$user = "root";
$password = "";
$db = "sakila";
try {
    $conn = new PDO("mysql:host=$server;dbname=$db", $user, $password, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"]);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql="select * from actor where first_name like '%$nombre%'";
    
    $res=$conn->query($sql);
    $actores=$res->fetchAll();
    echo "<actores>";
    foreach($actores as $actor){
        echo "<actor><first_name>".$actor['first_name'].
                "</first_name><last_name>".$actor['last_name'].
                "</last_name></actor>";
    }
    echo "</actores>";

} catch (Exception $ex) {
    echo $ex->getMessage();
}

Ajax con js

index.php:

  <input type="text" id="nombre">
        
        
        <div id="resultado"></div>
        <script>
            document.getElementById("nombre").addEventListener("keyup", function () {
                var pepe = new XMLHttpRequest();

                pepe.onreadystatechange = function () {
                    if (this.readyState == 4 && this.status == 200) {
                        document.getElementById('resultado').innerHTML = this.responseText;
                        console.log(this.responseText);
                    }
                }
                var nombre=document.getElementById('nombre').value;
                pepe.open("POST", "datos.php");
                pepe.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                pepe.send("nombre="+nombre);


            })
        </script>

datos.php:

<?php

$nombre = filter_input(INPUT_POST, "nombre");
$server = "localhost";
$user = "root";
$password = "";
$db = "sakila";
try {
    $conn = new PDO("mysql:host=$server;dbname=$db", $user, $password, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"]);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql="select * from actor where first_name like '%$nombre%'";
    
    $res=$conn->query($sql);
    $actores=$res->fetchAll();
    echo "<actores>";
    foreach($actores as $actor){
        echo "<actor><first_name>".$actor['first_name'].
                "</first_name><last_name>".$actor['last_name'].
                "</last_name></actor>";
    }
    echo "</actores>";

} catch (Exception $ex) {
    echo $ex->getMessage();
}