Acceder a la base de datos desde el lenguaje de programación PHP

publicado en: Tutorial | 5

Servidor web IoTHTTP POST Servidor web IoTBase Datos MySQL. Servidor web IoTLenguaje PHP Servidor web IoT

En este último artículo de la serie sobre el uso de un servidor web para almacenar los datos de los dispositivos conectados a la Internet de las cosas, se explica como grabar en una base de datos MySQL la información que los nodos IoT envían al servidor haciendo peticiones HTTP POST. Los lectores de este artículo, de todo el blog, puede que no estén especialmente familiarizados con la programación en el lenguaje PHP pero seguramente sí con la programación de microcontroladores en los lenguajes C o C++ así que, salvo algunos detalles, como preceder del signo dólar ($) a las variables, podrán seguir los ejemplos sin necesidad de mayores explicaciones ya que se han hecho siguiendo un estilo de programación muy neutro, no específico de PHP.

Almacenar información en la base de datos

Como se explicaba en el artículo sobre el almacenamiento de datos de la IoT haciendo peticiones HTTP POST a un servidor web, al final de las cabeceras, el cuerpo de la petición POST contiene los datos que se envían al servidor. La forma más común de enviar esa información al servidor es en formato de texto plano porque es más sencillo analizarla incluso «manualmente». Cuando los datos que se envían al servidor son complejos seguramente será conveniente estructurarlos usando, por ejemplo el formato XML o JSON. En el uso habitual de un servidor web para gestionar la información de dispositivos conectados a la Internet de las cosas no es frecuente necesitar una estructura de datos por lo que lo normal es enviarlos en texto plano en el formato variable=valor.

En la petición HTTP POST del siguiente ejemplo se solicita al servidor polaridad.es el recurso (normalmente una página web) /iot/grabar_temperatura y se le envían tres variables: ne, tp y cr que contienen respectivamente los valores «12», «10.26» y «2.18» También es importante recordar que hay una línea en blanco para separar las cabeceras de los datos.

El objetivo final del siguiente código PHP será enviar al servidor de bases de datos MySQL la orden SQL:

Con la que se creará un nuevo registro (INSERT)
en la base de datos calefacciones (INTO calefacciones)
asignando a los campos (numero_estancia,temperatura,corriente)
los valores correspondientes a la petición HTTP POST VALUES (12, 10.26, 2.18)

La conexión a la base de datos se realiza con la función mysqli_connect conforme al formato: mysqli_connect($servidor,$usuario,$clave,$base_datos) que devuelve un puntero al objeto-conexión y que usa la variables que definen el acceso (como usuario, clave…) y que han sido previamente asignadas para futuros hipotéticos usos en el script.

Para detectar si la conexión ha tenido éxito se utiliza la función mysqli_connect_errno() que devuelve el número de error que se pueda haber producido o cero (false) si la conexión se ha establecido correctamente. Para avisar de los errores se responde con el valor cero a la aplicación que realiza la petición HTTP, en este caso el programa que se ejecuta en el µC del nodo IoT.

Antes de incorporar al texto que se almacena en $consulta_sql con el que se compone la orden SQL que se envía al servidor de bases de datos la información que ha llegado en las variables de la petición POST se preprocesan, como mínimo, para evitar un ataque por inyección de código SQL. En el ejemplo anterior se fuerza la conversión al tipo de dato correspondiente (int) (entero) o (float) (decimal en coma flotante) lo que sería suficiente para eliminar posible código malicioso añadido a los datos de la petición al servidor web.

Como puede verse, en el lenguaje PHP se utiliza el símbolo del punto (.) para concatenar los textos que forman la orden SQL o el operador punto y signo igual (.=) para añadir un texto a la derecha del que ya almacene una variable y se utiliza la comilla simple (‘) también para encerrar constantes de texto, no sólo caracteres. Aunque en este caso pueden utilizarse también comillas dobles («), en lenguaje PHP se utilizan para procesar el contenido, por ejemplo, incluyendo variables dentro del texto en el formato $texto="Me llamo $nombre"; como alternativa al formato $texto='Me llamo '.$nombre; permitiendo, además, incluir comillas de un tipo en otro sin necesidad de usar signos de escape siempre que se alternen dobles dentro de simples o simples dentro de dobles como en la asignación $texto='esto no hay que "escaparlo" en PHP';.

Para ejecutar la consulta al servidor MySQL se utiliza la función mysqli_query con el formato mysqli_query($conexion,$consulta_sql) que toma como parámetros el objeto-conexión a la base de datos y el texto con la orden SQL que se ha compuesto.

La función mysqli_query($conexion,$consulta_sql) devuelve un objeto-cursor que puede usarse para recorrer los datos devueltos en su caso o, como ocurre en el ejemplo de arriba, para obtener información sobre la operación, concretamente para conocer el índice asignado al nuevo registro que la operación ha creado en la tabla «calefacciones» con la función mysqli_insert_id($conexion)

El valor devuelto por mysqli_query($conexion,$consulta_sql) puede evaluarse como falso en una operación booleana para determinar que se ha producido un error. En el ejemplo anterior se usa para devolver, al igual que en el caso del error de conexión, un cero a la aplicación que hace la petición POST. De esta forma, el programa devolverá un número mayor que cero que representa el índice del nuevo registro si la operación es correcta o un cero si la operación produce algún error.

Para liberar los recursos que se han asignado a la conexión a la base de datos se «cierra» usando la función mysqli_close($conexion)

Leer información de la base de datos

Salvo en arquitecturas para fog computing la mayoría de los nodos IoT se limitan a enviar al servidor la información que captan sus sensores, es decir, el servidor web sólo comunica con ellos para almacenar la información por lo que, con el ejemplo anterior ya se han resuelto buena parte de los casos que se plantearán en esta aplicación. El siguiente paso podría ser crear una web que mostrara los datos monitorizados por los dispositivos conectados a la Internet de las cosas, un trabajo de frontend que queda fuera de lo que se está tratando en esta serie de tutoriales.

Lo que sí puede ocurrir es que un nodo IoT tenga cierta interactividad y se comporte de forma diferente en función de un histórico de datos o prevea la posibilidad de alterar su comportamiento conforme a una configuración que le llegue de un servidor o incluso el nodo sea una pantalla que muestre una gráfica con los datos que se han monitorizado recientemente en comparación con los adquiridos en fechas anteriores. Para todas estas situaciones es interesante también poder leer datos del servidor MySQL a través del servidor web como se ilustra en el siguiente ejemplo en el que se simula la obtención de una lista de las fechas de los estados de alarma determinados por los momentos en los que la temperatura superó los 40°C

En el ejemplo de arriba, para consultar la base de datos se usa la orden SQL SELECT conforme al formato básico SELECT campos FROM tabla WHERE condición ORDER BY campo DESC con la única peculiaridad de añadir al campo fecha las funciones DAY, MONTH, YEAR y TIME al objeto de obtener de la misma el día, el número del mes el año y la hora por separado. La condición impuesta es que la temperatura sea mayor que 40.0 y se ordena usando el campo fecha de mayor (más actual) a menor (más antiguo) indicándolo con la cláusula DESC

Para recorrer los valores devueltos por la consulta desde un bucle for con una dimensión conocida se utiliza la función mysqli_num_rows($resultado) que indica el número de registros que se han encontrado. Con la función mysqli_data_seek($resultado,$numero_resultado) se puede mover el cursor de los resultados a una posición concreta expresada por el contador del bucle for, $numero_resultado, en el ejemplo.

Para almacenar en un vector los campos del registro que apunta el cursor del resultado se utiliza la función mysqli_fetch_row($resultado) que se asigna a la variable $registro que después se usará formando una frase con los diferentes valores accediendo a ellos por sus índices.

Una vez que se han recorrido todos los valores se liberan los recursos asignados al resultado de la consulta SQL con la función mysqli_free_result($resultado)

Procesar información de la base de datos. Comparar valores.

En algunas ocasiones conviene que el procesado de la información se centralice en el servidor incluso aunque fuera posible realizarla en los nodos IoT al estilo fog computing. En el siguiente ejemplo las razones que se simulan para hacerlo son de seguridad; el nodo tiene información sobre su clave (cerradura) y sobre una solicitud (llave) pero no sabe si corresponde dar paso a la combinación de ambas así que debe consultarlo al servidor que es el que toma la decisión e informa al nodo respondiendo cero (para indicar una comparación incorrecta) o uno (para indicar que la comparación tuvo éxito) según el resultado de una consulta a su base de datos.

Con esta excusa se puede ver un ejemplo en el que se reciben datos del dispositivo conectado a la Internet de las cosas (un código de llave y otro de cerradura), se devuelve un resultado (uno o cero según el resultado sea verdadero o falso) y se realiza un pequeño procesado de la información consistente en comparar los resultados obtenidos al consultar la base de datos con los enviados por el nodo IoT.

En el ejemplo anterior se utiliza la función hexdec para obtener un número decimal desde un texto que representa uno hexadecimal y que es el enviado por el dispositivo IoT. la ventaja añadida de usar está función es evitar, como se explicó antes, un ataque añadiendo código SQL malicioso a los datos de la petición POST.

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

5 Respuestas

  1. Alfredo Segura

    Hola Victor: Mi ESP8266 hace la conexión con mi localhost muy bien, pero al consultar la base de datos no veo que se guarden mis 3 parámetros enviados:

    print(wifi.sta.getip())
    192.168.0.29 255.255.255.0 192.168.0.1
    >
    conex = net.createConnection(net.TCP,0)
    > conex:connect(80, ‘192.168.0.28’)
    > conex:send(‘POST /esp8266/iot2.php HTTP/1.1\r\n’)
    > conex:send(‘Host: 192.168.0.28\r\n’)
    > conex:send(‘Accept: text/plain\r\n’)
    > conex:send(‘Accept-Charset: utf-8\r\n’)
    > conex:send(‘Accept-Encoding: identity\r\n’)
    > conex:send(‘Accept-Language: es-ES\r\n’)
    > conex:send(‘Connection: close\r\n’)
    > conex:send(‘Content-Length: 65\r\n’)
    > conex:send(‘Content-Type: application/jsonrequest\r\n’)
    > conex:send(‘User-Agent: Sensoreitor-2000\r\n’)
    > conex:send(‘\r\n’)
    > conex:send(‘nom=1\r\n’)
    > conex:send(‘tem=2\r\n’)
    > conex:send(‘sit=3\r\n’)
    > conex:close()
    >

    Los cuales son nom, temp y sit. Ya los he puesto ordenados de muchas manera, y en la base datos solo salen:

    Textos completos id nombre temperatura sitio fecha status
    Edita Borra 1 ESP8266 26.9 Lab2 2017-09-30 1
    Edita Borra 2 Pila 1.5 Recargable 2017-10-01 1
    Edita Borra 3 0 2017-10-01 1
    Edita Borra 4 0 2017-10-01 1
    Edita Borra 5 0 2017-10-01 1
    Edita Borra 6 0 2017-10-01 1
    Edita Borra 7 0 2017-10-01 1
    Edita Borra 8 0 2017-10-01 1
    Edita Borra 9 0 2017-10-01 1
    Edita Borra 10 0 2017-10-01 1

    La temperatura es FLOAT, por eso siempre lo rellena con 0. STATUS siempre es 1. Pero los campos de nombre y sitio deberían aparecer con el nombre 1 y 3 (incluso tem=2)

    Ya casi logro que funcione, pero quiero pedir tu ayuda para llegar a ese punto. Te estaré agradecido de tus comentarios….saludos.

  2. Alfredo Segura

    Hola Víctor…ya encontré una solución. (Es posible que tu lo hayas aclarado, pero seguramente no le tomé importancia)…
    Note that $_POST is NOT set for all HTTP POST operations, but only for specific types of POST operations. I have not been able to find documentation, but here’s what I’ve found so far.

    $_POST _is_ set for:
    Content-Type: application/x-www-form-urlencoded
    In other words, for standard web forms.
    $_POST is NOT set for:
    Content-Type:text/xml
    A type used for a generic HTTP POST operation.

    tomado de: http://php.net/manual/es/reserved.variables.post.php

    Saludos….

  3. Waldo Gomez

    Victor
    No me queda claro cómo se configura para que el sensor envíe datos al servidor.
    Los envía a una ip/port ?
    Hay un programa php ‘escuchando en esa ip/port ? Algo así como un demon ?

    Puede extenderse un poco más acerca de este tema ?

    Gracias

    • Víctor Ventura

      Hola, Waldo.

      Creo que es mejor que no me extienda más, que bastante abuso ya de la paciencia de mis lectores.

      Seguramente tus dudas están respondidas a lo largo de la serie de cuatro artículos que este encabeza. Puedes acceder a ellos en los enlaces de la parte superior (los cuatro iconos grandes del principio)

      En cualquier caso, para abrir boca, sí, más o menos hay un programa PHP escuchando. Para ser precisos, es el servidor web el que escucha y lanza el script PHP.

      Claro, el MCU hace una petición al servidor web en una dirección IP y en un puerto (típicamente el 80)

      Espero haberte orientado un poco.

      Hasta pronto.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *