En la empresa BK Programación están a punto de hacerse cargo de un importante proyecto. Ada, la directora, va a comprometerse con un cliente y amigo, Esteban, que necesita ayuda con un problema concreto.
Esteban fundó hace ahora tres años una pequeña empresa dedicada a la venta de material tecnológico: cámaras, televisores, material informático, etc. Con el tiempo, esa pequeña empresa ha crecido. El número de ventas ha aumentado, así como el catálogo de productos que ofrece, e incluso ha abierto dos nuevas tiendas en localidades cercanas.
Pero como sucede muchas veces, al aumentar el negocio han ido surgiendo ciertas necesidades. El proyecto que Esteban le ha propuesto a Ada consiste en desarrollar una web. No una página web que explique dónde está la empresa o qué hace. Quiere una web enfocada a dos temas concretos: mejorar la comunicación con sus clientes, y que le aporte información interna a la empresa sobre su negocio.
Por ejemplo, quiere que los clientes puedan ver desde su casa los productos que vende, el precio de los mismos, o la disponibilidad en una u otra tienda. O que los empleados de la propia empresa puedan ver de forma sencilla el stock que tienen de los productos en las distintas sucursales, para poder decidir mejor qué productos se piden a los distribuidores y en qué cantidad.
Sin embargo, tal y como Ada ya le ha comentado a Esteban, la experiencia de BK Programación en el desarrollo de aplicaciones web es muy reducida. La mayoría de proyectos que han realizado hasta el momento se han centrado en aplicaciones para plataformas Windows y Linux, o para dispositivos móviles. Sólo uno de sus empleados, Juan, tiene cierta experiencia con la programación web.
Aun así, Esteban confía en que Ada y su empresa lograrán llevar a cabo el proyecto. No tiene prisa por ponerlo en funcionamiento, y sabe que a BK Programación le servirá para ir formando a sus empleados en temas relacionados en el desarrollo de aplicaciones web, por lo que finalmente llegan a un acuerdo.
El nuevo proyecto al que se enfrenta BK Programación requiere que sus empleados actualicen su formación en temas relacionados con la programación web. Juan, el único con cierta experiencia en ese ámbito, ha propuesto a sus compañeros la realización de unas jornadas en las que explique a los demás los fundamentos del desarrollo de aplicaciones para la web. De esta forma, aquellos que quieran pasarán a formar parte del equipo que se dedique al nuevo proyecto.
Todos se apuntan a la propuesta de Juan, incluyendo a Ada, la directora.
El primer objetivo de las jornadas es ver en qué consiste la programación web. Por ejemplo, ver la diferencia existente entre hacer una página web y programar una aplicación web.
Seguro que ya sabes exactamente qué es una página web, e incluso conozcas cuáles son los pasos que se suceden para que, cuando visitas una web poniendo su dirección en el navegador, la página se descargue a tu equipo y se pueda mostrar. Sin embargo, este procedimiento que puede parecer sencillo, a veces no lo es tanto. Todo depende de cómo se haya hecho esa página.
Cuando una página web se descarga a tu ordenador, su contenido define qué se debe mostrar en pantalla. Este contenido está programado en un lenguaje de marcado, formado por etiquetas, que puede ser HTML o XHTML. Las etiquetas que componen la página indican el objetivo de cada una de las partes que la componen. Así, dentro de estos lenguajes hay etiquetas para indicar que un texto es un encabezado, que forma parte de una tabla, o que simplemente es un párrafo de texto.
Además, si la página está bien estructurada, la información que le indica al navegador el estilo con que se debe mostrar cada parte de la página estará almacenado en otro fichero, una hoja de estilos o CSS. La hoja de estilos se encuentra indicada en la página web y el navegador la descarga junto a ésta. En ella nos podemos encontrar, por ejemplo, estilos que indican que el encabezado debe ir con tipo de letra Arial y en color rojo, o que los párrafos deben ir alineados a la izquierda.
Estos dos ficheros se descargan a tu ordenador desde un servidor web como respuesta a una petición. El proceso es el que se refleja en la siguiente figura.
Tu ordenador solicita a un servidor web una página con extensión .htm, .html o .xhtml.
El servidor busca esa página en un almacén de páginas (cada una suele ser un fichero).
Si el servidor encuentra esa página, la recupera.
Y por último se la envía al navegador para que éste pueda mostrar su contenido.
Este es un ejemplo típico de una comunicación cliente-servidor. El cliente es el que hace la petición e inicia la comunicación, y el servidor es el que recibe la petición y la atiende. En nuestro caso, el navegador es el cliente web.
Abreviatura de “Hoja de estilos en cascada”, del inglés Cascading Style Sheet (CSS). Es un lenguaje utilizado para definir las características de presentación de un documento escrito en lenguaje HTML o XML.
Las páginas que viste en el ejemplo anterior se llaman páginas web estáticas. Estas páginas se encuentran almacenadas en su forma definitiva, tal y como se crearon, y su contenido no varía. Son útiles para mostrar una información concreta, y mostrarán esa misma información cada vez que se carguen. La única forma en que pueden cambiar es si un programador la modifica y actualiza su contenido.
En contraposición a las páginas web estáticas, como ya te imaginarás, existen las páginas web dinámicas. Estas páginas, como su nombre indica, se caracterizan porque su contenido cambia en función de diversas variables, como puede ser el navegador que estás usando, el usuario con el que te has identificado, o las acciones que has efectuado con anterioridad.
Dentro de las páginas web dinámicas, es muy importante distinguir dos tipos:
Aquellas que incluyen código que ejecuta el navegador. En estas páginas el código ejecutable, normalmente en lenguaje JavaScript, se incluye dentro del HTML y se descarga junto con la página. Cuando el navegador muestra la página en pantalla, ejecuta el código que la acompaña. Este código puede incorporar múltiples funcionalidades que pueden ir desde mostrar animaciones hasta cambiar totalmente la apariencia y el contenido de la página. En este módulo no vamos a ver JavaScript, salvo cuando éste se relaciona con la programación web del lado del servidor.
Y por otro lado están las páginas web dinámicas de servidor. Se trata de aplicaciones que se ejecutan en el servidor y que generan contenido dinámico que el navegador simplemente tendrá que mostrar. En ocasiones es fácil identificar este tipo de aplicaciones porque veremos extensiones como .php, .asp, .jsp, .cgi o .aspx en la barra de direcciones del navegador. En éstas, por tanto, el contenido que se descarga al navegador es similar al de una página web estática: HTML; sin embargo, lo que cambia es la forma en que se obtiene ese contenido. Al contrario de lo que hemos visto hasta ahora, estas páginas no están almacenadas en el servidor tal cual; sino que el HTML de estas páginas se forma como resultado de la ejecución de un programa y esa ejecución tiene lugar en el servidor, no en el navegador.
El esquema de funcionamiento de una aplicación web dinámica que se ejecuta en el servidor es el siguiente:
El cliente web (navegador) de tu ordenador solicita a un servidor web un recurso (página web, imagen, etc.) realizando una petición HTTP (HTTP Request) .
El servidor busca ese recurso y la recupera.
En el caso de que el recurso sea un script o guión o programa, es decir, en caso de que deba ejecutarse un programa para obtener el HTML, el servidor web inicia con el módulo responsable la ejecución del código. En nuestro caso, ese módulo será el motor PHP.
Como parte del proceso de ejecución, puede ser necesario obtener información de algún repositorio, como por ejemplo consultar registros almacenados en una base de datos.
El resultado de la ejecución será generalmente una página en formato HTML, similar a cualquier otra página web no dinámica.
Una vez finalizada la ejecución, el servidor web envía el resultado obtenido al navegador a través de una respuesta HTTP (HTTP Response), el cual procesa el HTML recibido y lo muestra al usuario en un proceso conocido como renderizado.
Cualquier almacén de información digital, normalmente una base de datos.
Aunque la utilización de páginas web dinámicas te parezca la mejor opción para construir un sitio web, no siempre lo es. Sin lugar a dudas, es la que más potencia y flexibilidad permite, pero las páginas web estáticas tienen también algunas ventajas:
No es necesario saber programar para crear un sitio que utilice únicamente páginas web estáticas. Simplemente habría que conocer HTML/XHTML y CSS, e incluso esto no sería indispensable: se podría utilizar algún programa de diseño web para generarlas.
La característica diferenciadora de las páginas web estáticas es que su contenido nunca varía, y esto en algunos casos también puede suponer una ventaja. Sucede, por ejemplo, cuando quieres almacenar un enlace a un contenido concreto del sitio web: si la página es dinámica, al volver a visitarla utilizando el enlace su contenido puede variar con respecto a cómo estaba con anterioridad. O cuando quieres dar de alta un sitio que has creado en un motor de búsqueda como Google.
Para que Google muestre un sitio web en sus resultados de búsqueda, previamente tiene que indexar su contenido. Es decir, un programa recorre las páginas del sitio consultando su contenido y clasificándolo. Si las páginas se generan de forma dinámica, puede ser que su contenido, en parte o por completo, no sea visible para el buscador y por tanto no quedará indexado. Esto nunca sucedería en un sitio que utilizase páginas web estáticas.
Como ya sabes, para que un servidor web pueda procesar una página web dinámica de servidor necesita ejecutar un programa. Esta ejecución la realiza un módulo concreto, que puede estar integrado en el servidor web o ser independiente. Además, puede ser necesario consultar una base de datos como parte de la ejecución del programa. Es decir, la ejecución de una página web dinámica requiere una serie de recursos del lado del servidor. Estos recursos deben instalarse y mantenerse.
Las páginas web estáticas sólo necesitan un servidor web que se comunique con tu navegador para enviártela. Y de hecho para ver una página estática almacenada en tu equipo no necesitas siquiera de un servidor web. Son archivos que pueden almacenarse en un soporte de almacenamiento como puede ser un disco óptico o una memoria USB y abrirse desde él directamente con un navegador web.
Pero si decides hacer un sitio web utilizando páginas estáticas, ten en cuenta que tienen limitaciones. La desventaja más importante ya la comentamos anteriormente: la actualización de su contenido debe hacerse de forma manual editando la página que almacena el servidor web. Esto implica un mantenimiento que puede ser prohibitivo en sitios web con gran cantidad de contenido.
¿Qué tipo de tecnología emplearías para crear una página web personal? ¿Sería necesario utilizar páginas dinámicas? ¿Qué tareas de actualización y mantenimiento tendrías que realizar en cada caso?
Las aplicaciones web de servidor emplean, entre otras tecnologías, scripts o guiones para crear aplicaciones que se ejecutan en un servidor web y cuyo resultado se muestra en un navegador. Puedes encontrar aplicaciones web para realizar múltiples tareas. Unas de las primeras en aparecer fueron los clientes de correo, que te permiten consultar los mensajes de correo recibidos y enviar los tuyos propios utilizando un navegador.
Hoy en día existen aplicaciones web para multitud de tareas como procesadores de texto, gestión de tareas, o edición y almacenamiento de imágenes. Estas aplicaciones tienen ciertas ventajas e inconvenientes si las comparas con las aplicaciones tradicionales que se ejecutan sobre el sistema operativo de la propia máquina.
Ventajas de las aplicaciones web de servidor:
No es necesario instalarlas en aquellos equipos en que se vayan a utilizar. Se instalan y se ejecutan solamente en un equipo, en el servidor, y esto es suficiente para que se puedan utilizar de forma simultánea desde muchos equipos.
Como solo se encuentran instaladas en un equipo, es muy sencillo gestionarlas (hacer copias de seguridad de sus datos, corregir errores, actualizarlas).
Se pueden utilizar en todos aquellos sistemas que dispongan de un navegador web, independientemente de sus características (no es necesario un equipo potente) o de su sistema operativo.
Se pueden utilizar desde cualquier lugar en el que dispongamos de conexión con el servidor. En muchos casos esto hace posible que se pueda acceder a las aplicaciones desde sistemas no convencionales, como por ejemplo teléfonos móviles.
Inconvenientes de las aplicaciones web de servidor:
El interface de usuario de las aplicaciones web es la página que se muestra en el navegador. Esto restringe las características del interface a aquellas de una página web.
Dependemos de una conexión con el servidor para poder utilizarlas. Si nos falla la conexión, no podremos acceder a la aplicación web.
La información que se muestra en el navegador debe transmitirse desde el servidor. Esto hace que cierto tipo de aplicaciones no sean adecuadas para su implementación como aplicación web.
Hoy en día muchas aplicaciones web utilizan las ventajas que les ofrece la generación de páginas dinámicas. La gran mayoría de su contenido está almacenado en una base de datos. Aplicaciones como Drupal, Joomla!, Wordpress y otras muchas ofrecen dos partes bien diferenciadas:
Una parte externa o front-end, que es el conjunto de páginas que ven la gran mayoría de usuarios que las usan (usuarios externos).
Una parte interna o back-end, que es otro conjunto de páginas dinámicas que utilizan las personas que producen el contenido y las que administran la aplicación web (usuarios internos) para crear contenido, organizarlo, decidir la apariencia externa, etc.
Como vimos, cuando tu navegador solicita a un servidor web una página o recurso, es posible que antes de enviártela haya tenido que ejecutar, por sí mismo o por delegación, algún programa para obtenerla. Ese programa es el que genera, en parte o en su totalidad, la página web que llega a tu equipo. En estos casos, el código se ejecuta en el entorno del servidor web.
Además, cuando una página web llega a tu navegador, es también posible que incluya algún programa o fragmentos de código que se deban ejecutar. Ese código, normalmente en lenguaje JavaScript, se ejecutará en tu navegador y, además de poder modificar el contenido de la página, también puede llevar a cabo acciones como la animación de textos u objetos de la página o la comprobación de los datos que introduces en un formulario.
Estas dos tecnologías se complementan una con otra. Así, volviendo al ejemplo del correo web, el programa que se encarga de obtener tus mensajes y su contenido de una base de datos se ejecuta en el entorno del servidor, mientras que tu navegador ejecuta, por ejemplo, el código encargado de avisarte cuando quieres enviar un mensaje y te has olvidado de poner un texto en el asunto.
Esta división es así porque el código que se ejecuta en el cliente web (en tu navegador) no tiene, o mejor dicho tradicionalmente no tenía, acceso a los datos que se almacenan en el servidor. Es decir, cuando en tu navegador querías leer un nuevo correo, el código Javascript que se ejecutaba en el mismo no podía obtener de la base de datos el contenido de ese mensaje. La solución era crear una nueva página en el servidor con la información que se pedía y enviarla de nuevo al navegador.
Sin embargo, desde hace unos años existe una técnica de desarrollo web conocida como AJAX, que nos posibilita realizar programas en los que el código JavaScript que se ejecuta en el navegador pueda comunicarse con un servidor de Internet para obtener información con la que, por ejemplo, modificar la página web actual.
En nuestro ejemplo, cuando pulsas con el ratón encima de un correo que quieres leer, la página puede contener código Javascript que detecte la acción y, en ese instante, consultar a través de Internet el texto que contiene ese mismo correo y mostrarlo en la misma página, modificando su estructura en caso de que sea necesario. Es decir, sin salir de una página poder modificar su contenido en base a la información que se almacena en un servidor de Internet.
En este módulo vas a aprender a crear aplicaciones web que se ejecuten en el lado del servidor. Otro módulo de este mismo ciclo, Desarrollo Web en Entorno Cliente, enseña las características de la programación de código que se ejecute en el navegador web.
Muchas de las aplicaciones web actuales utilizan estas dos tecnologías: la ejecución de código en el servidory en el cliente. Así, el código que se ejecuta en el servidor genera páginas web que ya incluyen código destinado a su ejecución en el navegador. Hacia el final de este módulo verás las técnicas que se usan para programar aplicaciones que incorporen esta funcionalidad.
En BK Programación han formado un equipo que se dedicará al nuevo proyecto. Juan será el jefe del proyecto, y contará con la ayuda de María, que trabaja habitualmente en la instalación y mantenimiento de servidores, y con Carlos, un amigo de Juan que pese a no tener experiencia en ese tipo de trabajo se siente muy atraído por todo lo relacionado con la programación web.
Juan ha programado aplicaciones en lenguajes C, Java y PHP. María por su parte conoce el lenguaje C y utiliza Perl en su trabajo habitual. Carlos es autodidacta y tiene nociones de programación en lenguaje Pascal. Todos conocen bien el lenguaje HTML.
En la primera reunión, los tres ponen en común los objetivos generales del trabajo y deciden estudiar las distintas opciones que tienen para lograr el objetivo.
Cuando programas una aplicación, utilizas un lenguaje de programación. Por ejemplo, utilizas el lenguaje Java para crear aplicaciones que se ejecuten en distintos sistemas operativos. Al programar cada aplicación utilizas ciertas herramientas como un entorno de desarrollo o librerías de código. Además, una vez acabado su desarrollo, esa aplicación necesitará ciertos componentes para su ejecución, como por ejemplo una máquina virtual de Java.
En este bloque vas a aprender las distintas tecnologías que se pueden utilizar para programar aplicaciones que se ejecuten en un servidor web, y cómo se relacionan unas con otras. Verás las ventajas e inconvenientes de utilizar cada una, y qué lenguajes de programación deberás aprender para utilizarlas.
Los componentes principales con los que debes contar para ejecutar aplicaciones web en un servidor son los siguientes:
Un servidor web para recibir las peticiones de los clientes web (normalmente navegadores) y enviarles la página que solicitan (una vez generada puesto que hablamos de páginas web dinámicas). El servidor web debe conocer el procedimiento a seguir para generar la página web: qué módulo se encargará de la ejecución del código y cómo se debe comunicar con él.
El módulo encargado de ejecutar el código o programa y generar la página web resultante. Este módulo debe integrarse de alguna forma con el servidor web, y dependerá del lenguaje y tecnología que utilicemos para programar la aplicación web.
Una aplicación de base de datos, que normalmente también será un servidor. Este módulo no es estrictamente necesario pero en la práctica se utiliza en todas las aplicaciones web que utilizan grandes cantidades de datos para almacenarlos.
El lenguaje de programación que utilizarás para desarrollar las aplicaciones.
Además de los componentes a utilizar, también es importante decidir cómo vas a organizar el código de la aplicación. Muchas de las arquitecturas que se usan en la programación de aplicaciones web te ayudan a estructurar el código de las aplicaciones en capas o niveles.
El motivo de dividir en capas el diseño de una aplicación es que se puedan separar las funciones lógicas de la misma, de tal forma que sea posible ejecutar cada una en un servidor distinto (en caso de que sea necesario).
En una aplicación puedes distinguir, de forma general, funciones de presentación (se encarga de dar formato a los datos para presentárselo al usuario final), lógica (utiliza los datos para ejecutar un proceso y obtener un resultado), persistencia (que mantiene los datos almacenados de forma organizada) y acceso (que obtiene e introduce datos en el espacio de almacenamiento).
Cada capa puede ocuparse de una o varias de las funciones anteriores. Por ejemplo, en las aplicaciones de 3 capas nos podemos encontrar con:
Una capa cliente, que es donde programarás todo lo relacionado con el interface de usuario, esto es, la parte visible de la aplicación con la que interactuará el usuario.
Una capa intermedia donde deberás programar la funcionalidad de tu aplicación.
Una capa de acceso a datos, que se tendrá que encargar de almacenar la información de la aplicación en una base de datos y recuperarla cuando sea necesario.
La primera elección que harás antes de comenzar a programar una aplicación web es la arquitectura que vas a utilizar. Hoy en día, puedes elegir entre:
Java EE (Enterprise Edition), que antes también se conocía como J2EE. Es una plataforma orientada a la programación de aplicaciones en lenguaje Java. Puede funcionar con distintos gestores de bases de datos, e incluye varias librerías y especificaciones para el desarrollo de aplicaciones de forma modular.
Está apoyada por grandes empresas como Oracle,que mantiene Java, y otras como Red Hat e IBM. Es una buena solución para el desarrollo de aplicaciones de tamaño mediano o grande. Una de sus principales ventajas es la multitud de librerías existentes en ese lenguaje y la gran base de programadores que lo conocen.
Dentro de esta arquitectura existen distintas tecnologías como las páginas JSP y los servlets, ambos orientados a la generación dinámica de páginas web, o los EJB, componentes que normalmente aportan la lógica de la aplicación web.
AMP. Son las siglas de Apache, MySQL y PHP/Perl/Python. Las dos primeras siglas hacen referencia al servidor web (Apache) y al servidor de base de datos (MySQL). La última se corresponde con el lenguaje de programación utilizado, que puede ser PHP, Perl o Python, siendo PHP el más empleado de los tres.
Dependiendo del sistema operativo que se utilice para el servidor, se utilizan las siglas LAMP (para Linux), WAMP (para Windows) o MAMP (para Mac). También es posible usar otros componentes, como el gestor de bases de datos PostgreSQL en lugar de MySQL.
Todos los componentes de esta arquitectura son de código libre (open source). Es una plataforma de programación que permite desarrollar aplicaciones de tamaño pequeño o mediano con un aprendizaje sencillo. Su gran ventaja es la gran comunidad que la soporta y la multitud de aplicaciones de código libre disponibles.
Denominación habitual del código que permite a los usuarios un control total sobre el mismo. Los programas de código libre pueden ser usados, modificados y copiados libremente. Esto no implica que no tengan coste. Se pueden comercializar programas de código libre.
Existen paquetes software que incluyen en una única instalación una plataforma AMP completa. Algunos ni siquiera es necesario instalarlos, e incluso disponen de versiones para distintos sistemas operativos como Linux, Windows o Mac. Uno de los más conocidos es XAMPP.
CGI/Perl. Es la combinación de dos componentes: Perl, un potente lenguaje de código libre creado originalmente para la administración de servidores, y CGI, un estándar para permitir al servidor web ejecutar programas genéricos, escritos en cualquier lenguaje (también se pueden utilizar por ejemplo C o Python), que devuelven páginas web (HTML) como resultado de su ejecución. Es la más primitiva de las arquitecturas que comparamos aquí, y posiblemente, la menos utilizada hoy día.
El principal inconveniente de esta combinación es que CGI es lento, aunque existen métodos para acelerarlo. Por otra parte, Perl es un lenguaje muy potente con una amplia comunidad de usuarios y mucho código libre disponible.
ASP.Net es la arquitectura comercial propuesta por Microsoft para el desarrollo de aplicaciones. Es la parte de la plataforma .NET destinada a la generación de páginas web dinámicas. Proviene de la evolución de la anterior tecnología de Microsoft: ASP.
El lenguaje de programación puede ser Visual Basic .Net o C#. La arquitectura utiliza el servidor web de Microsoft, IIS, y puede obtener información de varios gestores de bases de datos entre los que se incluye, como no, Microsoft SQL Server.
Una de las mayores ventajas de la arquitectura .Net es que incluye todo lo necesario para el desarrollo y el despliegue de aplicaciones. Por ejemplo, tiene su propio entorno de desarrollo, Visual Studio, aunque hay otras opciones disponibles. La mayor desventaja es que se trata de una plataforma comercial de código propietario.
Estas tecnologías son posiblemente las más tradicionales.
De cara a acelerar el desarrollo web han surgido lo diferentes frameworks. ¿Qué es un framework? Un framework consiste en un conjunto de herramientas, bibliotecas, servicios y componentes que permiten acelerar el desarrollo. En el caso en el desarrollo web en el lado del servidor, los frameworks generalmente proporcionan servicios como autenticación, mapeado objeto-relacional, validación de datos, motores de plantillas, facilidades de depuración, etc. además de una estructura estándar y predefinida que simplemente hay que extender.
Para empezar a utilizar un framework antes hay que aprender a programar en el lenguaje de programación sobre el que se sustenta y, además, las características propias del framework. En cada framework se hacen las cosas de una forma diferente. No son lo mismo la autenticación en Laravel y en Symfony, aunque ambos sean frameworks PHP.
Por otro lado, no todos los frameworks tienen los mismos servicios o componentes. Puede que un framework no tenga un servicio de autenticación o un componente para validar datos, mientras que otro si. Antes de utilizar un framework y decidirte por aprenderlo deberás revisar si dicho framework tiene lo que necesitas para tu proyecto.
En este curso profundizaremos más adelante en el framework Laravel de PHP. No obstante, vamos a repasar algunos de los frameworks más importantes:
Symfony, CodeIgniter, Laminas, Yii, Phalcon, CakePHP, Slim y FuelPHP son algunos ejemplos de frameworks disponibles en PHP (sin contar con Laravel).
Spring (lenguaje Java): Posiblemente el framework más utilizado en aplicaciones Java en entorno servidor, dispone de una gran variedad de componentes y servicios.
Express (lenguaje JavaScript en la plataforma Node.js): es un framework minimalista y muy extensible. No incorpora por si solo muchos componentes y servicios, pero se pueden agregar como paquetes. Es común utilizarlo junto a MongoDB y Angular.js. conformando la conocida arquitectura MEAN.
Django (lenguaje Python) y Flask (lenguaje Python). Dos frameworks en en muy extendidos.
A lo largo de este módulo vamos a utilizar PHP como lenguaje y motor para realizar aplicaciones web en entorno servidor. Pero antes empezar, respondamos a una pregunta; ¿dónde se sitúa exactamente PHP?
Comunicación Cliente web (navegador) y Servidor web
La comunicación entre un cliente web o navegador y un servidor web se lleva a cabo gracias al protocolo HTTP. En el caso de las aplicaciones web, HTTP es el vínculo de unión entre el usuario y la aplicación en sí. Cualquier introducción de información que realice el usuario se transmite mediante una petición HTTP (HTTP Request), y el resultado que obtiene le llega por medio de una respuesta HTTP (HTTP Response), o HTTPS si se utiliza el protocolo seguro.
Integrar la ejecución de código al recibir peticiones HTTP
A la hora de crear una aplicación web en el servidor existen generalmente dos opciones:
Redirigir las peticiones HTTP a un motor o engine. En este caso, hacemos que el servidor web redirija peticiones HTTP concretas a un motor o engine encargado de ejecutar un programa.
La aplicación web recibe las peticiones HTTP directamente. Hacer que sea el sea la misma aplicación web la que reciba las peticiones y se encargue de generar una respuesta HTTP. Este enfoque es común en frameworks específicos como Express.js, Django, Flask o Spring.
En el primer escenario las peticiones HTTP son recibidas por el servidor web (también llamado servidor HTTP) y será el servidor web el encargado de decidir cómo procesar las peticiones que recibe. El servidor web actúa de intermediario redirigiendo las peticiones a motores o enginesencargados de ejecutar un programa que generará una respuesta dinámica. Para lograr esto, en el servidor web se pueden integrar, por ejemplo, el motor que procesa los scripts o guiones PHP (entre otros), generalmente en forma de módulos o componentes.
La tecnología más antigua para integrar un lenguaje de programación en un servidor web es CGI. CGI es un protocolo estándar que existe en muchas plataformas. Lo implementan la gran mayoría de servidores web. Define qué debe hacer el servidor web para delegar en un programa externo la generación de una página web. Esos programas externos se conocen como guiones o scripts CGI, independientemente del lenguaje en el que estén programados.
El principal problema de CGI es que cada vez que se ejecuta un guion CGI, el sistema operativo debe crear un nuevo proceso. Para evitar esto muchos servidores web (como Apache y Nginx) permiten instalar motores (como el de PHP) como módulos que se ejecutan en el mismo navegador web. Aunque es posible ejecutar código en lenguaje PHP utilizando CGI, los intérpretes PHP no se suelen utilizar con este método, sino que se instalan como módulos. Por ejemplo, el módulo mod_php es la forma habitual que se utiliza para ejecutar guiones en PHP utilizando plataformas AMP (Apache).
En el segundo escenario, por otro lado, se diseñan aplicaciones web que, simplificando la arquitectura, reciben ellas mismas las peticiones web y generan el resultado. Aunque en PHP no es muy común, empieza a haber algunos frameworks que permiten desarrollar aplicaciones PHP que funcionan de esta forma. Un claro ejemplo lo tenemos en el muy interesante frameworkReactPHP.
Otras arquitecturas.
A la hora de desarrollar aplicaciones web, la arquitectura Java EE desarrolla una línea bastante diferente. Para poder ejecutar aplicaciones Java EE en un servidor, básicamente tenemos dos opciones: servidores de aplicaciones, que implementan todas las tecnologías disponibles en Java EE, y contenedores de servlets, que soportan solo parte de la especificación. Dependiendo de la magnitud de nuestra aplicación y de las tecnologías que utilice, tendremos que instalar una solución u otra.
Puedes consultar una lista con los servidores de aplicaciones JavaEE certificados en la Wikipedia y las implementaciones de software compatibles con Java EE.
En este sentido el concepto de servidor de aplicaciones que desarrolla Java EE implica la utilización de una serie de componentes que hacen más fácilmente escalable la aplicación, y además, su división en diferentes capas (capa de presentación, capa de lógica de aplicación, etc.). Este concepto de servidor de aplicaciones se ha extendido a otras arquitecturas tales como el framework .NET de Microsoft.
También para PHP hay disponibles servidores de aplicaciones que nos permitirán escalar y compartimentar más fácilmente nuestra aplicación, a continuación tienes dos ejemplos:
Tras analizar distintas arquitecturas de programación web, Juan y su equipo comprueban que una de las decisiones más importantes antes de ponerse manos a la obra es el lenguaje de programación que utilizarán en el desarrollo.
Además de la sintaxis propia de cada lenguaje, la elección de uno u otro afecta a la complejidad del proyecto, a las herramientas que tendrán que utilizar, e incluso a la forma en que tendrán que programar la aplicación web.
Juan propone utilizar el lenguaje PHP, que ya conoce, pero no sin antes estudiar las ventajas y desventajas que les supondría con respecto a la utilización de otras alternativas.
Una de las diferencias más notables entre un lenguaje de programación web y otro es la manera en que se ejecutan en el servidor web. Debes distinguir tres grandes grupos:
Lenguajes de guiones (scripting). Son aquellos en los que los programas se ejecutan directamente a partir de su código fuente original. Se almacenan normalmente en un fichero de texto plano. Cuando el servidor web necesita ejecutar código programado en un lenguaje de guiones, le pasa la petición a un intérprete, que procesa las líneas del programa y genera como resultado una página web. Normalmente, a este tipo de lenguajes se les conoce como lenguajes interpretados.
De los lenguajes que estudiaste anteriormente, pertenecen a este grupo Perl, Python, PHP y ASP (el precursor de ASP.Net).
Lenguajes compilados a código nativo. Son aquellos en los que el código fuente se traduce a código binario, dependiente del procesador, antes de ser ejecutado. El servidor web almacena los programas en su modo binario, que ejecuta directamente cuando se les invoca.
El método principal para ejecutar programas binarios desde un servidor web es CGI. Utilizando CGI podemos hacer que el servidor web ejecute código programado en cualquier lenguaje de propósito general como puede ser C.
Lenguajes compilados a código intermedio. Son lenguajes en los que el código fuente original se traduce a un código intermedio, independiente del procesador, antes de ser ejecutado. Es la forma en la que se ejecutan por ejemplo las aplicaciones programadas en Java, y lo que hace que puedan ejecutarse en varias plataformas distintas.
En la programación web, operan de esta forma los lenguajes de las arquitecturas Java EE (servlets y páginas JSP) y ASP.Net.
En la plataforma ASP.Net y en muchas implementaciones de Java EE, se utiliza un procedimiento de compilación JIT. Este término hace referencia a la forma en que se convierte el código intermedio a código binario para ser ejecutado por el procesador. Para acelerar la ejecución, el compilador puede traducir todo o parte del código intermedio a código nativo cuando se invoca a un programa. El código nativo obtenido suele almacenarse para ser utilizado de nuevo cuando sea necesario.
Cada una de estas formas de ejecución del código por el servidor web tiene sus ventajas e inconvenientes.
Los lenguajes de guiones tienen la ventaja de que no es necesario traducir el código fuente original para ser ejecutados, lo que aumenta su portabilidad. Si se necesita realizar alguna modificación a un programa, se puede hacer en el momento. Por el contrario, el proceso de interpretación ofrece un peor rendimiento que las otras alternativas.
Los lenguajes compilados a código nativo son los de mayor velocidad de ejecución, pero tienen problemas en lo relativo a su integración con el servidor web. Son programas de propósito general que no están pensados para ejecutarse en el entorno de un servidor web. Por ejemplo, no se reutilizan los procesos para atender a varias peticiones: por cada petición que se haga al servidor web, se debe ejecutar un nuevo proceso. Además, los programas no son portables entre distintas plataformas.
Los lenguajes compilados a código intermedio ofrecen un equilibrio entre las dos opciones anteriores. Su rendimiento es muy bueno y pueden portarse entre distintas plataformas en las que exista una implementación de la arquitectura (como un contenedor de servlets o un servidor de aplicaciones Java EE).
Denominación habitual del lenguaje máquina. Código que puede ser ejecutado directamente por el procesador.
Conjunto de instrucciones que componen un programa, y que no son ejecutables directamente, sino que deben traducirse utilizando un compilador, intérprete o similar antes de que pueda ser ejecutado por la máquina.
A partir de PHP 8 se incluye una mejora muy importante: el compilador JIT. En la configuración por defecto de PHP no suele ir habilitado, pero podemos habilitar si lo deseamos esta característica que compilará y cacheará partes del código para mejorar notablemente el rendimiento (hasta 4 veces más rápido). En el siguiente artículo se explica como habilitarlo:
Cuando la web comenzó a evolucionar desde las páginas web estáticas a las dinámicas, una de las primeras tecnologías que se utilizaron fue la ejecución de código utilizando CGI. Los guiones o scriptsCGI son programas estándar, que se ejecutan por el sistema operativo, pero que generan como salida el código HTML de una página web. Por tanto, los guiones CGI deben contener, mezcladas dentro de su código, sentencias encargadas de generar la página web.
Por ejemplo, si quieres generar una página web utilizando CGI a partir de un guion de sentencias en Linux, tienes que hacer algo como lo siguiente:
Esta es una de las principales formas de realizar páginas web dinámicas: integrar las etiquetas HTML en el código de los programas. Es decir, los programas como el guión o script anterior incluyen dentro de su código sentencias de salida (echo en el caso anterior) que son las que incluyen el código HTML de la página web que se obtendrá cuando se ejecuten. De esta forma se programan, por ejemplo, los guiones CGI y los servlets.
Un enfoque distinto consiste en integrar el código del programa en medio de las etiquetas HTML de la página web. De esta forma, el contenido que no varía de la página se puede introducir directamente en HTML, y el lenguaje de programación se utilizará para todo aquello que pueda variar de forma dinámica.
Por ejemplo, puedes incluir dentro de una página HTML un pequeño código en lenguaje PHP que muestre el nombre del servidor:
Esta metodología de programación es la que se emplea en los lenguajes ASP, PHP y con las páginas JSP de Java EE.
Los servlets de Java EE se diferencian de las páginas JSP en que los primeros son programas Java compilados y almacenados en el contenedor de servlets. Sin embargo, las páginas JSP contienen código Java embebido en lenguaje HTML y se almacenan de forma individual en el servidor web. La primera vez que se necesita una página JSP, se convierte a un servlet y éste se guarda para ser utilizado en posteriores llamadas a la misma página.
En la arquitectura ASP.Net, cada página se divide en dos ficheros: uno contiene las etiquetas HTML y otro el código en el lenguaje de programación utilizado. De esta forma se logra cierta independencia entre el aspecto de la aplicación y la gestión del contenido dinámico. A partir de esos ficheros se obtiene un código intermedio (MSIL en la terminología de la plataforma) que es lo que almacena el servidor.
A la hora de ponerte a programar una aplicación web, debes tener en cuenta con que herramientas cuentas que te puedan ayudar de una forma u otra a realizar el trabajo. Además de las herramientas que se tengan que utilizar en el servidor una vez que la aplicación se ejecute, como por ejemplo el servidor de aplicaciones o el gestor de bases de datos, de las que ya conoces su objetivo, existen otras que resultan de gran ayuda en el proceso previo, en el desarrollo de la aplicación.
Desde hace tiempo, existen entornos integrados de desarrollo (IDE) que agrupan en un único programa muchas de estas herramientas. Algunos de estos entornos de desarrollo son específicos de una plataforma o de un lenguaje, como sucede por ejemplo con Visual Studio, el IDE de Microsoft para desarrollar aplicaciones en lenguaje C# o Visual Basic para la plataforma .Net. Otros como Eclipse o NetBeans te permiten personalizar el entorno para trabajar con diferentes lenguajes y plataformas, como Java EE o PHP.
No es imprescindible utilizar un IDE para programar. En muchas ocasiones puedes echar mano de un simple editor de texto para editar el código que necesites. Sin embargo, si tu objetivo es desarrollar una aplicación web, las características que te aporta un entorno de desarrollo son muy convenientes. Entre estas características se encuentran:
Resaltado de texto. Muestra con distinto color o tipo de letra los diferentes elementos del lenguaje: sentencias, variables, comentarios, etc. También genera sangrado automático para diferenciar de forma clara los distintos bloques de un programa.
Completado automático. Detecta qué estás escribiendo y cuando es posible te muestra distintas opciones para completar el texto.
Navegación en el código. Permite buscar de forma sencilla elementos dentro del texto, por ejemplo, definiciones de variables.
Comprobación de errores al editar. Reconoce la sintaxis del lenguaje y revisa el código en busca de errores mientras lo escribes.
Generación automática de código. Ciertas estructuras, como la que se utiliza para las clases, se repiten varias veces en un programa. La generación automática de código puede encargarse de crear la estructura básica, para que sólo tengas que rellenarla.
Ejecución y depuración. Esta característica es una de las más útiles. El IDE se puede encargar de ejecutar un programa para poder probar su funcionamiento. Además, cuando algo no funciona, te permite depurarlo con herramientas como la ejecución paso a paso, el establecimiento de puntos de ruptura o la inspección del valor que almacenan las variables.
Gestión de versiones. En conjunción con un sistema de control de versiones, el entorno de desarrollo te puede ayudar a guardar copias del estado del proyecto a lo largo del tiempo, para que si es necesario puedas revertir los cambios realizados.
Uno de los IDE de código abierto más utilizados es NetBeans. Permite el desarrollo de aplicaciones informáticas en varios lenguajes de programación. Aunque en sus orígenes se centraron en la programación en lenguaje Java, hoy en día admiten directamente o a través de módulos, varios lenguajes entre los que se incluyen C, C++ y PHP. Otro de los IDE más utilizados hoy día es Visual Studio Code, que gracias a su sistema de extensiones permite dar soporte a una gran variedad de lenguajes.
Haciendo doble clic en él se iniciará el proceso de instalación. Para la instalación de Visual Studio en también se proporciona un instalable .deb para Ubuntu en la página oficial.
Cuando estamos desarrollando aplicaciones web para ser desplegadas en un servidor necesitamos recrear el entorno donde se ejecutará la aplicación. A este nivel distinguiremos dos situaciones diferentes:
Ambiente de desarrollo y pruebas: equipo donde se ha instalado el software que habría en el servidor para simular el funcionamiento real.
Ambiente de producción: servidor real donde, una vez desarrollada y probada la aplicación web, se pone a disposición del usuario final. A este proceso se le conoce como despliegue de aplicaciones.
En este módulo, como ya sabrás, trabajaremos con PHP en una pila AMP (Apache, MySQL y PHP), y para poder desarrollar aplicaciones es necesario instalar un ambiente de desarrollo y pruebas. Para este propósito existen varias opciones:
Instalar el software de servidor en nuestra máquina local. En este caso lo que realizamos es instalar el software que tendría el servidor en el equipo de cada desarrollador o desarrolladora.
Virtualización. El software que tendría el servidor se instala en una máquina virtual. Este procedimiento, aunque es más costoso, tiene ciertas ventajas, dado que permite que todo el equipo de desarrollo pueda usar la misma máquina virtual para desarrollar evitando las inconsistencias típicas producidas al usar diferentes versiones software o herramientas. Este enfoque tiene varias variantes, donde podríamos destacar:
Usar máquinas virtuales tradicionales. En este escenario se emula todo el sistema operativo de servidor y en él se instalaría todo el software necesario.
Usar contenedores. Los contenedores permiten recrear el ambiente de producción de forma muy cómoda y sencilla partiendo de simples archivos de configuración, instalando solamente el software que es estrictamente necesario. Es un mecanismo mucho más ligero que una máquina virtual tradicional y permiten una instalación rápida del ambiente de desarrollo, pudiendo tener multitud de configuraciones y contenedores con el objetivo de poder atender a las necesidades de cada proyecto que vayamos a desarrollar. Hoy día la tecnología más usada para poner en marcha un contenedor es Docker.
En todos los casos anteriores, el ambiente de desarrollo suele ir configurado de forma diferente al ambiente de producción. Por ejemplo, en el ambiente de desarrollo se suelen mostrar los errores en el código, mientras que en el ambiente de producción esta característica suele estar capada por motivos de seguridad y estética.
En nuestro caso, para poner en marcha el ambiente de desarrollo vamos a instalar XAMPP el cual puedes descargar de la siguiente página:
Este paquete ya incluye todo lo necesario para disponer del ambiente de desarrollo que necesitamos. Revisemos el proceso de instalación de este software en Windows:
1) Descarga de XAMPP para Windows
En la URL indicada antes podrás descargar XAMPP para Windows. Asegúrate de elegir la versión adecuada. Una vez descargado haz doble clic encima para empezar la instalación:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
2) Instalación: selección de componentes
Al instalar XAMPP en Windows tendremos que tomar realmente pocas decisiones, la primera decisión es seleccionar los componentes a instalar: MySQL, PHP y phpMyAdmin; el resto no los usaremos:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
3) Instalación: ruta de instalación
En el siguiente paso te pedirá la carpeta donde instalar XAMPP, te recomendamos utilizar la carpeta por defecto: C:\xampp
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
4) Localización de la instalación. ¿Qué hay en el directorio C:\xampp?
En el directorio C:\xampp encontraremos varias cosas, pero lo más importante es lo siguiente:
Directorio C:\xampp\htdocs: carpeta donde crearemos nuestras aplicaciones web.
Ejecutable C:\xampp\xampp-control.exe: ejecutable que nos permitirá arrancar y detener los servicios de Apache y MySql instalados. Apache integra PHP como un módulo (no es necesario arrancarlo o detenerlo por separado).
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
5) Panel de control de XAMPP.
El panel de control de XAMPP es muy sencillo. Al ejecutar C:\xampp\xampp-control.exe, aparecerá una interfaz donde podrás iniciar y detener los servicios de Apache (que incluye PHP) y MySQL:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Para poder probar tus aplicaciones web deberás iniciar Apache.
Para instalar la pila de desarrollo LAMP en sistemas como Ubuntu, lo mejor es instalar los paquetes por separado e ir configurándolos. En el siguiente enlace tienes un ejemplo detallado de como realizarlo:
PHP es un lenguaje de guiones de propósito general, pero diseñado para el desarrollo de páginas web dinámicas utilizando código embebido dentro del lenguaje de marcas HTML. Su sintaxis está basada en la de C / C++, es parecida a la de Java, salvando el hecho de que es un lenguaje interpretado. El código de nuestras páginas web dinámicas creadas con PHP incluirán el código PHP dentro de una página web con <?php y ?> como verás más adelante.
Nuestras aplicaciones web en PHP tendremos que ubicarlas dentro de un directorio concreto una vez instalado en ambiente de desarrollo. Dependiendo de dónde y como se haya dicho ambiente, el servidor web buscará las aplicaciones web y contenido a servir en ubicaciones específicas:
Si has realizado la instalación de XAMPP en en siguiendo los pasos descritos en el punto anterior el código PHP tendrías que ubicarlo en la ruta C:\xampp\htdocs\. En ese directorio puedes crear diferentes directorios y archivos para ir desarrollando tu aplicación.
Si has realizado una instalación en Ubuntu o otro entorno la ubicación más habitual será /var/www/html/. Dentro de esa carpeta puedes organizar tu aplicación web o aplicaciones web en diferentes carpetas y subcarpetas.
Prueba a crear dentro de esas ubicaciones (por ejemplo en C:\xampp\htdocs\ en XAMPP para Windows) el archivo phpinfo.php (C:\xampp\htdocs\phpinfo.php) y dentro de dicho archivo escribe el siguiente código:
<?php
phpinfo();
Cuando arranques el servidor web podrás ejecutar tu primer script PHP simplemente tecleando en el navegador web la siguiente ruta: http://localhost/phpinfo.php.
Existe una correlación entre los directorios creados y el contenido servido por el servidor web. Si por ejemplo, el archivo anterior lo creas en el directorio C:\xampp\htdocs\ejemplo\phpinfo.php la ruta para acceder al mismo desde el navegador web sería http://localhost/ejemplo/phpinfo.php. El ejemplo anterior es para XAMPP en Windows, pero algo similar ocurriría en sistemas Linux.
El código PHP se ejecuta por tanto en un entorno o ambiente de ejecución con el que se integra el servidor web (normalmente utilizando Apache con el módulo mod_php). La configuración tanto del servidor web Apache, como de PHP, se realiza por medio de ficheros de configuración. El de Apache es httpd.conf, y el de PHP es php.ini. Este fichero, php.ini, puede encontrarse en distintas ubicaciones. La función phpinfo() que ejecutaste puede informarte, entre otras muchas cosas, del lugar en que se encuentra almacenado el fichero php.ini en tu ordenador:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
La captura anterior se trata de una instalación de PHP en un ambiente de desarrollo en Ubuntu. Si has instalado XAMPP en Windows en como se ha indicado en el apartado anterior, el directorio donde esta el archivo php.ini normalmente es C:\xampp\php\php.ini.
Si realizas cambios en los archivos de configuración deberás reiniciar el servidor web:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
En caso de utilizar Linux, en función de la instalación realizada, reiniciar el servidor web Apache suele ser tan sencillo como ejecutar el comando siguiente en el terminal: sudo service apache2 restart o bien sudo /etc/init.d/apache2 restart.
Algunas de las directivas más utilizadas que figuran en el fichero php.ini son:
short_open_tag. Indica si se pueden utilizar en PHP los delimitadores cortos <? y ?>. Es preferible no usarlos, pues puede causarnos problemas si utilizamos páginas con XML. Para prohibir la utilización de estos delimitadores con PHP le asignamos a esta directiva el valor Off.
max_execution_time. Permite que puedas ajustar el número máximo de segundos que podrá durar la ejecución de un script PHP. Evita que el servidor se bloquee si se produce algún error en un script.
error_reporting. Indica qué tipo de errores se mostrarán en el caso de que se produzcan. Por ejemplo, si haces error_reporting = E_ALL, te mostrará todos los tipos de errores. Si no quieres que te muestre los avisos pero sí otros tipos de errores, puedes hacer error_reporting = E_ALL & ~E_NOTICE.
file_uploads. Indica si se pueden o no subir ficheros al servidor por HTTP.
upload_max_filesize. En caso de que se puedan subir ficheros por HTTP, puedes indicar el límite máximo permitido para el tamaño de cada archivo. Por ejemplo, upload_max_filesize = 1M.
Iremos viendo otras directivas a lo largo del módulo cuando las vayamos necesitando.
El nuevo proyecto va a ponerse en marcha. En BK Programación las tres personas asignadas comienzan los preparativos. Juan, el jefe de proyecto, está elaborando un calendario para intentar definir las distintas fases del desarrollo. María, en el tiempo que le puede dedicar, se ha puesto a refrescar sus conocimientos de programación en PHP. Carlos es el que más trabajo tiene por delante, sabe que si quiere aportar algo, debe aprender a programar aplicaciones web, y pronto.
Carlos le pide ayuda a Juan, que le orienta sobre los conceptos fundamentales del lenguaje y le ofrece su ayuda en todo lo que le sea posible. Sabe que es importante adquirir unos conocimientos sólidos antes de comenzar el desarrollo, para no cometer errores al principio que después sea complicado solucionar.
Con la ayuda de María, ponen en funcionamiento un servidor de aplicaciones dentro de la empresa. De momento lo utilizarán para ir haciendo pruebas, pero dentro de poco será la plataforma sobre la que programarán la nueva aplicación.
En PHP el código de nuestro programa se entrelaza con las etiquetas HTML utilizando los delimitadores <?php y ?>. Entre ambos delimitadores tendremos que escribir nuestro código, por ejemplo:
El código HTML formará parte directa de lo que se enviará al cliente web (navegador), es decir, no se modificará y se enviará tal cual al navegador. Mientras que el código PHP servirá para completar el código generado de forma dinámica. Como puedes ver en el ejemplo anterior, los programas escritos en PHP suelen incluir en una mismo script varios bloques de código PHP entremezclados, en la mayor parte de las ocasiones, con HTML. Además, una aplicación web completa normalmente se estructura en múltiples scripts. Ya veremos más adelante cómo estructurar una aplicación web y el flujo de datos de un script a otro pasando por el navegador.
Dentro de cada bloque tendremos sentencias de código, que serán acciones a realizar. El final de cada sentencia debe ser el punto y coma (;):
<?php
$edad=10; //Sentencia de asignación
$peso=29; //Sentencia de asignación
?>
A medida que vayas escribiendo código en PHP, será útil que introduzcas en el mismo algunos comentarios que ayuden a revisarlo cuando lo necesites. En una página web los comentarios HTML van entre los delimitadores <!-- y -->. Dentro del código PHP, hay tres formas de poner comentarios:
Comentarios de una línea utilizando //. Son comentarios al estilo del lenguaje C. Cuando una línea comienza por los símbolos //, toda ella se considera que contiene un comentario, hasta la siguiente línea.
Comentarios de una línea utilizando #. Son similares a los anteriores, pero utilizando la sintaxis de los scripts de Linux.
Comentarios de varias líneas. También iguales a los del lenguaje C. Cuando en una línea aparezcan los caracteres /*, se considera que ahí comienza un comentario. El comentario puede extenderse varias líneas, y acabará cuando escribas la combinación de caracteres opuesta: */.
Recuerda que cuando pongas comentarios al código PHP, éstos no figurarán en ningún caso en la página web que se envía al navegador (justo al contrario de lo que sucede con los comentarios a las etiquetas HTML). En el siguiente ejemplo puedes observar el uso de los diferentes comentarios:
<?php
$a=10; //a la variable $a se le asigna el valor 10
/* Doblar el valor de $a */
$a=2*$a;
echo $a; #Mostrar el valor de $a
Por último, es importante que sepas que cuando un script PHP solo contiene código PHP (es decir, no contiene fragmentos de HTML entremezclados con PHP), suele escribirse el código como en el ejemplo anterior. Al principio del documento se escribe <?php, y a continuación todo el código PHP, sin llegar a escribir el cierre ?> final.
Como en todos los lenguajes de programación, en PHP puedes crear variables para almacenar valores. Las variables en PHP siempre deben comenzar por el signo $ (por ejemplo: $mi_variable). Los nombres de las variables deben comenzar por letras o por el carácter _, y pueden contener también números. Sin embargo, al contrario que en muchos otros lenguajes, en PHP no es necesario declarar una variable ni especificarle un tipo (entero, cadena,…) concreto. Para empezar a usar una variable, simplemente asígnale un valor utilizando el operador =.
$mi_variable = 7;
Dependiendo del valor que se le asigne, a la variable se le aplica un tipo de datos, que puede cambiar si cambia su contenido. Esto significa que el tipo de la variable se decide en función del contexto en que se emplee.
// Al asignarle el valor 7, la variable es de tipo entero (int)
$mi_variable = 7;
// Si le cambiamos el contenido la variable puede cambiar de tipo
$mi_variable = 'siete';
// En este caso pasa a ser de tipo cadena de texto (string)
Los tipos de datos simples en PHP son:
booleano (boolean): sus posibles valores son true o false. Los literales true o false pueden escribirse tanto en minúscula como en mayúsculas (por ejemplo, TRUE o True).
entero (integer). Cualquier número sin decimales. Se pueden representar en formato decimal, octal (comenzando por un 0), o hexadecimal (comenzando por 0x).
número real (float): Cualquier número con decimales. Se pueden representar también en notación científica.
cadena de texto o string. Conjuntos de caracteres delimitados por comillas simples o dobles.
null: tipo de dato especial utilizado para señalar que una variable no posee ningún valor asignado.
Cuando necesitamos que una variable sea de un tipo específico podemos forzar la conversión:
<?php
$numeroEnCadena = "10"; // $numeroEnCadena es string que contiene un número
$numero = (int) $numeroEnCadena; // $numero r es un entero con valor 10
?>
Para los tipos de datos simples podemos aplicar las siguientes cambios de tipo:
(int), (integer): forzado a entero. Usos:
Convertir una cadena con número (por ejemplo: "10") a un entero (10)
Convertir un booleano a número: true se convierte en 1 y false se convierte en 0.
Convertir un número real a entero: se elimina la parte decimal.
(bool), (boolean): forzado a booleano. Usos:
Un número real o flotante distinto a cero se convertirá en true.
Un número real o flotante igual a cero se convertirá en false.
También se aplica a cadenas de textos que contienen números (por ejemplo, 10.3 se convertirá a true).
(float), (double) : forzado a número real. Usos:
Convertir una cadena con número real (por ejemplo: "10.34") a un entero (10.34)
Convertir un booleano a número: true se convierte en 1.0 y false se convierte en 0.0.
Convertir un número entero a real. No incrementa su precisión, solo cambia el tipo donde se almacena.
(string): forzado a cadena de texto. Usos:
Cuando se trata de un número simplemente genera una cadena con dicho número: (string)10 generaría "10".
Cuando se convierte un booleano, el valor false se convierte en una cadena vacía y el valor true en una cadena que contiene "1".
Al realizar una operación con variables de diferentes tipos (como suma, resta o división), siempre que sean compatibles, el resultado se generará en el tipo de dato de mayor precisión. Esto implica la conversión automática interna de los datos al tipo más preciso. Por ejemplo, al sumar un número entero con uno real, el entero se transforma a real antes de efectuar la suma:
$mi_entero = 3;
$mi_real = 2.3;
$resultado = $mi_entero + $mi_real;
// La variable $resultado es de tipo float
Por último, es importante que sepas que en PHP las variables pueden usarse también poniendo su nombre entrecomillado entre llaves. Esto resulta extraño pero realmente es sumamente útil en ciertos momentos:
<?php
$numero=10;
print ${'numero'};
Esta facilidad permite almacenar el nombre de una variable en otra variable, como en el siguiente ejemplo:
En todos los lenguajes de programación es necesario definir constantes. Como ya sabrás, una constante hace referencia a un valor que no puede ser modificado. En PHP las constantes se pueden definir de dos formas:
Usando la función define.
Usando la palabra reservada const.
Tanto las constantes creadas con define como las creadas con const no llevan el símbolo $ delante y se suelen escribir en mayúsculas.
La diferencia entre define y const es muy importante. define crea una constante global que es visible en todos los ámbitos. Una vez creada, puede ser usada dentro de funciones y métodos de clase, dado que es global, y además, se crea en tiempo de ejecución, con lo que puedes crear constantes con define a demanda.
Sin embargo las constantes con const no pueden ser creadas a demanda, se puede definir a nivel global (no dentro de una función o método), o bien como atributos de clase, o dentro de un espacio de nombres, y se establecen al compilar el código. Algunos de estos conceptos los estudiaremos en unidades posteriores.
<?php
define('MI_CONSTANTE', 'Hola, Mundo');
function mostrarConstante() {
//Declaro una constante que solo se crea si se ejecuta la función
define ('OTRA_CONSTANTE','Hola, Luna');
// Se puede acceder a MI_CONSTANTE dado que es global
echo MI_CONSTANTE;
}
mostrarConstante(); // Imprime "Hola, Mundo"
echo OTRA_CONSTANTE; // Imprime "Hola, Luna"
El primer parámetro es el nombre de la constante (MI_CONSTANTE y OTRA_CONSTANTE en el ejemplo anterior), el valor es el segundo parámetro, y por último, se puede indicar si la constante puede usarse en minúsculas o mayúsculas, pero normalmente no se usa porque hace el código menos legible. De hecho, siempre se suelen poner en mayúsculas.
Es importante que analices el ejemplo anterior, porque la constante llamada OTRA_CONSTANTE solo se creará cuando se ejecute la función, por lo que si no se ejecuta la función tu código daría un error. Puedes verificar si existe una constante usando la función defined():
if (defined(OTRA_CONSTANTE))
echo OTRA_CONSTANTE;
else
print 'No existe la constante';
En versiones antiguas de PHP las constantes creadas con define sólo podían tener valores de tipo integer, float, string, boolean y null. Sin embargo, a partir de la versión 7 de PHP se permiten constantes creadas con define que contengan arrays:
TobiasD(Licencia Pixabay) Las referencias son un concepto complicado de entender, pero muy importante. Por ello, vamos a verlo de la forma más sencilla posible. Cuando creamos una referencia lo que estamos haciendo es dar varios nombres al mismo dato en memoria. Para crear una referencia a una variable usamos el operador &:
<?php
$dato=9;
$ref1=&$dato; // $ref1 sería otro "nombre" para la variable
$ref1++; //Modificar $ref1 modifica también $dato
echo $dato; //Al mostrar $dato se mostrará "10", porque $ref1 ha sido incremento.
En el ejemplo anterior hemos creado una referencia al hacer $ref1=&$dato. El código anterior mostrará 10 por pantalla, dado que incrementar $ref1 es lo mismo que incrementar $dato... es un dato con dos nombres.
No obstante, aunque la forma más fácil de entender este concepto es quedarnos con la idea de que tiene dos nombres (como cuando llamamos "Pepe" o "Francisco" a una misma persona), realmente lo que ocurre es que ambas variables ($ref1 y $dato) apuntan al mismo espacio de memoria.
Este tipo de técnicas es también aplicables a elementos de arrays. Los arrays los verás más adelante, pero el siguiente ejemplo es muy intuitivo y seguro que no te cuesta trabajo entenderlo:
<?php
$dato=array();
$dato[0]=9;
$dato[1]=11;
$ref1=&$dato[0]; // $ref1 sería otro "nombre" para $dato[0]
$ref2=&$dato[1]; // $ref2 sería otro "nombre" para $dato[1]
$ref1++;//Modificar $ref1 modifica también $dato[0]
$ref2++;//Modificar $ref2 modifica también $dato[2]
echo $dato[0] + $dato[1]; //La suma sería 22 y no 20
También, obviamente, podemos referenciar un array entero, como en el siguiente ejemplo:
<?php
$datos=array();
$datos[0]=9;
$datos[1]=11;
$ref=&$datos; // $ref1 sería otro "nombre" para $dato[0]
$ref[0]++;//Modificar $ref[0] modifica también $dato[0]
$ref[1]++;//Modificar $ref[1] modifica también $dato[1]
echo $datos[0] + $datos[1]; //La suma sería 22 y no 20
A priori, esto puede parecer algo poco útil, pero en realidad es muy útil en funciones y en algunas estructuras, como la estructura foreach.
En PHP existen varias formas incluir texto y contenido en la página web generada dinámicamente. Las formas más habituales son usan las construcciones echo y print. La diferencia entre echo y print es que echo admite múltiples parámetros separados por coma, mientras que print no:
<?php
$a=random_int(1,100);
$b=random_int(1,100);
//echo admite varios parámetros separados por comas
echo 'El primer número al azar es ',$a,'<BR>';
//print solo admite un parámetro
print 'El segundo número al azar es ';
print $b;
print '<BR>';
En ambos casos se pueden con o sin paréntesis dado que no son funciones realmente:
$a=random_int(1,100);
$b=random_int(1,100);
echo ($a.'<BR>'); //es equivalente a echo $a.'<BR>'
print ($b.'<BR>'); //es equivalente a print $b.'<BR>'
Una forma abreviada de proyectar información en la página generada es la sintaxis de PHP abreviada. Esta sintaxis, tremendamente usada, permite proyectar datos a la salida usando la forma <?=... ?>. Vemos un ejemplo de uso:
<?php
$a=random_int(1,100);
$b=random_int(1,100);
?>
Los dos valores elegidos al azar son: <?=$a?> y <?=$b?>
El uso de la forma abreviada de la etiqueta PHP es equivalente al uso de echo en relación a que se pueden pasar varios datos a mostrar separados por comas:
<?php
$a=random_int(1,100);
$b=random_int(1,100);
?>
Los dos valores elegidos al azar son: <?=$a,' y ',$b?>
printf es otra opción para generar una salida desde PHP. Puede recibir varios parámetros, el primero de los cuales es siempre una cadena de texto que indica el formato que se ha de aplicar. Esa cadena debe contener un especificador de conversión por cada uno de los demás parámetros que se le pasen a la función, y en el mismo orden en que figuran en la lista de parámetros. Por ejemplo:
<P>
<?php
$ciclo="DAW"; $curso=2; $modulo="DWES";
printf("%s es un módulo de %d curso de %s", $modulo, $curso, $ciclo);
?>
</P>
Cada especificador de conversión va precedido del carácter `%` y se compone de las siguientes partes:
signo (opcional). Indica si se pone signo a los número negativos (por defecto) o también a los positivos (se indica con un signo +).
Ejemplo: printf("Número con signo: %+d", $numero);
Produce: si el número es -42 genera "-42" si es 42 genera "+42".
relleno (opcional). Indica que carácter se usará para ajustar el tamaño de una cadena. Las opciones son el carácter 0 o el carácter espacio (por defecto se usa el espacio).
Ejemplo: printf("Número con relleno: %05d", $numero);
Produce: si el número es 42 genera 00042.
alineación (opcional). Indica que tipo de alineación se usará para generar la salida: justificación derecha (por defecto) o izquierda (se indica con el carácter -). Es necesario usarlo con el ancho.
Ejemplo: printf("Texto alineado a la izquierda: %-10s!", $cadena);
Produce: si la cadena es "Hola" produce "Texto alineado a la izquierda: Hola !";
ancho (opcional). Indica el mínimo número de caracteres de salida para un parámetro dado.
Ejemplo: printf("Texto alineado a la izquierda: %10s!", $cadena);
Produce: si la cadena es "Hola" produce "Texto alineado a la izquierda: Hola!";
precisión (opcional). Indica el número de dígitos decimales que se mostrarán para un número real. Se escribe como un dígito precedido por un punto.
Ejemplo: printf("Precio: %2.d", $precio);
Produce: si $precio es 102.451 produce "102.45";
tipo (obligatorio). Indica cómo se debe tratar el valor del parámetro correspondiente. En la siguiente tabla puedes ver una lista con todos los especificadores de tipo.
Especificadores de tipo para las funciones printf y sprintf.
Tipo
Significado
b
el argumento es tratado como un entero y presentado como un número binario.
c
el argumento es tratado como un entero, y presentado como el carácter con dicho valor ASCII.
d
el argumento es tratado como un entero y presentado como un número decimal.
u
el argumento es tratado como un entero y presentado como un número decimal sin signo.
o
el argumento es tratado como un entero y presentado como un número octal.
x
el argumento es tratado como un entero y presentado como un número hexadecimal (con minúsculas).
X
el argumento es tratado como un entero y presentado como un número hexadecimal (con mayúsculas).
f
el argumento es tratado como un doble y presentado como un número de coma flotante (teniendo en cuenta la localidad).
F
el argumento es tratado como un doble y presentado como un número de coma flotante (sin tener en cuenta la localidad).
e
el argumento es presentado en notación científica, utilizando la e minúscula (por ejemplo, 1.2e+3).
E
el argumento es presentado en notación científica, utilizando la e mayúscula (por ejemplo, 1.2E+3).
g
se usa la forma más corta entre %f y %e.
G
se usa la forma más corta entre %f y %E.
s
el argumento es tratado como una cadena y es presentado como tal.
%
se muestra el carácter %. No necesita argumento..
Existe una función similar a printf pero que, en vez de generar una salida, retorna la cadena generada permitiendo guardarla en una variable: sprintf.
<?php
$importe_unidad=3.21;
$unidades=24;
$total=$importe_unidad*$unidades;
$texto=sprintf("El total es %.2f €", $total);
//... líneas más tarde
echo $texto;
En PHP es posible usar la constante M_PI para obtener el valor de PI (4.141592...). ¿Cómo podrías imprimir dicho número usando solo dos dígitos con el indicador de signo usando la función printf?
En PHP existen funciones específicas para comprobar y establecer el tipo de datos de una variable. Por ejemplo, gettype permite saber el tipo de la variable que se le pasa como parámetro y devuelve una cadena de texto, que puede ser array, boolean, double, integer, object, string, NULL, resource o unknown <strong>type</strong>.
<?php
$variable1 = array(1, 2, 3); //$variable1 contiene un array
$variable2 = true; //$variable2 contiene un boolean
$variable3 = 3.14; //$variable3 contiene un float
$variable4 = 42; //$variable4 contiene un entero
$variable5 = new DateTime(); //$variable5 contiene un objeto
$variable6 = "Hello, World!"; //$variable6 contiene una cadena
$variable7 = null; //$variable7 contiene null
$variable8 = fopen("php://temp", "r+"); //$variable7 contiene un resource
// Uso de gettype para obtener el tipo de cada variable
echo 'El tipo de $variable1 es: ' . gettype($variable1) . "\n"; // array
echo 'El tipo de $variable2 es: ' . gettype($variable2) . "\n"; // boolean
echo 'El tipo de $variable3 es: ' . gettype($variable3) . "\n"; // double
echo 'El tipo de $variable4 es: ' . gettype($variable4) . "\n"; // integer
echo 'El tipo de $variable5 es: ' . gettype($variable5) . "\n"; // object
echo 'El tipo de $variable6 es: ' . gettype($variable6) . "\n"; // string
echo 'El tipo de $variable7 es: ' . gettype($variable7) . "\n"; // NULL
echo 'El tipo de $variable8 es: ' . gettype($variable8) . "\n"; // resource
Fíjate que para las variables que contienen un float, la función gettype retorna double y no float. También podemos comprobar si la variable es de un tipo concreto utilizando una de las siguientes funciones: is_array(), is_bool(), is_float(), is_integer(), is_null(), is_numeric(), is_object(), is_resource(), is_scalar() e is_string(). Devuelven true si la variable es del tipo indicado.
<?php
$v= "TEST"; //Cualquier dato
$a = is_array($v); // $a será true si $v contiene un array
$b = is_bool($v); // $b será true si $v contiene un booleano
$c = is_float($v); // $c será true si $v contiene un float
$d = is_integer($v); // $d será true si $v contiene un entero
$e = is_null($v); // $e será true si $v contiene NULL
$f = is_numeric($v); // $f será true si $v es integer, float o una cadena que contiene un valor numérico
$g = is_object($v); // $g será true si $v contiene un objeto
$h = is_resource($v); // $h será true si $v contiene un recurso
$i = is_scalar($v); // $i será true si $v contiene un booleano, entero, float o cadena)
$j = is_string($v); // $j será true si $v contiene una cadena de texto
De los casos anteriores son especialmente destacables is_numeric y is_scalar dado que no son específicos a un único tipo de dato, haciéndolo especialmente útiles y potentes.
Análogamente, para establecer el tipo de una variable podemos utilizar la función settype pasándole como parámetros la variable a convertir y una de las siguientes cadenas: boolean, integer, float, string, array, object o null. Tienes que tener en cuenta que no siempre la conversión se puede realizar (no se puede convertir, por ejemplo, un integer en un array). La función settype devuelve true si la conversión se realizó correctamente o false en caso contrario:
$v = "3.1416";
$exito = settype($v, "float"); // $exito será true si se pudo realizar
print "\$v vale $v y es de tipo " . gettype($v) . "\n";
Ten en cuenta que no todos los tipos se pueden convertir a todos los tipos. Cuando se realiza esta operación se intentará hacer la conversión automática de tipos, pero si no es posible, se perderá el valor que se haya almacenado.
Por otro lado, posiblemente más importante, las funciones isset y unset. Si necesitas saber si una variable existe y si su valor es distinto de null, puedes usar la función isset. La función unset destruye la variable o variables que se le pasa como parámetro.
<?php
$a = "3.1416";
$t=isset($a); // la variable $t será true si la variable $a existe y es distinta de null
unset($a); //ahora ya no está definida
Es importante que sepas que isset no debe usarse para determinar si una variable está vacía. Cuando una variable contiene una cadena vacía (""), cero (0, 0.0 o "0"), false, o un array vacío ([]) se considera que la variable está vacía. Para comprobar si una variable está vacía es mejor usar empty.
Es importante no confundir el que una variable esté definida o valga null, con que se considere como vacía debido al valor que contenga. Esto último es lo que nos indica la función empty.
Por último y no menos importante, en PHP existen dos funciones que te facilitarán mucho el trabajo de depuración de tu código: la función print_r, y la función var_dump. La función print_r sirve para mostrar todo el contenido de la variable que le pasamos como parámetro. Si es un array, mostrará también los elementos del mismo.
<?php
$numero = 10;
$cadena = "Hola, mundo!";
$booleano = true;
print_r($numero); //Mostrará 10
print_r($cadena); // Mostrará "Hola, mundo!"
print_r($booleano); //Mostrará 1 (dado que los booleanos se convierten a enteros para mostrarse)
Y por otro lado, la función var_dump nos permitirá no solo ver el contenido de las variables, sino nos dará información extra como por ejemplo el tipo de la variable.
Y por último, aunque son muy útiles, no debería dejarse una vez que hemos terminado la aplicación, dado que mostrar cierta información puede suponer un riesgo de seguridad.
En PHP las expresiones y operadores son muy similares a otros lenguajes de programación (Java, C, C++, JavaScript, etc.), con la salvedad de que las variables siempre comienzan por $. Sin embargo, es cierto que en PHP existen algunos operadores diferentes que hacen a este lenguaje diferente. Veamos primero los comunes:
Los operadores matemáticos más comunes son los siguientes y como puedes observar varían poco o nada con respecto a lenguajes como Java o JavaScript:
$b = 12; $c=3; //Asignación
$a = $b + $c; //Suma y asignación --> $a será 15
$a = $b - $c; //Resta y asignación --> $a será 9
$a = $b * $c; //Multiplicación y asignación --> $a será 36
$a = $b / $c; //División y asignación --> $a será 4
$a = $b % $c; //Resto de la división entera (también llamado módulo) --> $a será 0
$a++; //Post incremento --> $a será 1
$a--; //Post decremento --> $a será 0
$a += 5; //Sumar 5 al valor actual de $a --> $a será 5
$a -= 3; //Restar 5 al valor actual de $a --> $a será 2
$a *= 5; //Multiplicar por 5 el valor actual de $a --> $a será 10
$a /= 2; //Dividir por 5 el valor actual de $a --> $a será 5
$a %= 3; //Resto de la división entera del valor actual de $a entre 5 --> $a será 2
$a = -$b; //Negación aritmética, valor opuesto de $b --> $a será -12
Por otro lado, los operadores de comparación son también muy parecidos a los de otros lenguajes:
<?php
$b = 12; $c = 3;
$r = $b == $c; // Diferente(se realiza conversión de tipos) --> $r será false
$r = $b != $c; // Diferente(se realiza conversión de tipos) --> $r será true
$r = $b <> $c; // Diferente sintaxis alternativa (se realiza conversión de tipos) --> $r será true
$r = $b < $c; // Menor qué --> $r será false
$r = $b <= $c; // Menor o igual qué --> $r será false
$r = $b > $c; // Mayor qué --> $r será true
$r = $b >= $c; // Mayor o igual qué --> $r será true
Además tenemos los operadores lógicos, donde PHP ofrece una sintaxis idéntica a la de otros lenguajes y también una sintaxis alternativa:
$p=true; $q=false;
//Sintaxis tipo C y Java:
$r = $p && $q; // Operación lógica Y --> $r sería false
$r = $p || $q; // Operación lógica O --> $r sería true
$r = !$q; // Negación lógica --> $r sería true
//Sintaxis alternativa ¡¡Cuidado!!
$r = ($p and $q); // Operación lógica Y --> $r sería false
$r = ($p or $q); // Operación lógica O --> $r sería true
En la tabla anterior es especialmente importante que te fijes en el uso de and y or. Fíjate que en la expresión se indican entre paréntesis. Esto es porque los operadores and y or tienen menos precedencia que la asignación. Es decir, si no se ponen los paréntesis primero se realizaría la asignación y después se ejecutaría el operador lógico.
Y por último, no nos olvidemos del operador ternario, donde podemos usar un valor u otro en función de la evaluación de una condición ( ? :):
Si en el apartado anterior revisábamos los operadores similares a otros lenguajes, en este apartado revisaremos aquellos que son propios de PHP y su uso. Una vez revisado lo conocido, nos adentraremos en lo desconocido:
Operadores propios de PHP
Operación
Tipo
Aplicación
Potencia
Aritmética
Calcular $belevado a$ces muy sencillo enPHP:
$b=12;$c=3;$a=$b**$c;//Potencia
Concatenación de texto
Manipulación de texto
La concatenación es básicamente la unión de dos cadenas.
$b='DW';$c='ES';$a=$b.$c;//Concatenación: $a sería 'DWES'$a.=' con PHP';// $a sería 'DWES con PHP'
Al aplicar la concatenación con datos que no son cadenas se convierten a cadenas de forma automática (siempre que sea posible):
$b='Mi número favorito es ';$c=7;$a=$b.$c;// $a sería 'Mi número favorito es 7'
Fusión denull
Comparación
El operador de fusión denulles un operador sumamente potente. Si una variable no existe o esnull, se usa el literal o variable indicada a la derecha:
$c=10;$a=$b??7+$c;
En el ejemplo anterior se sumarán7 + 17dado que$bno existe. Estos operadores se suelen utilizar mucho para ofrecer valores por defecto cuando un dato no existe. Además, se pueden concatenar:
$c=10;$a=($b??$c??0)*2;//$a sería 20, porque $c si existe.
Idéntico ($b===$c)
Comparación
Esta es otra de esas operaciones mega-importantes dePHP. Existe también en otros lenguajes (como Javascript), pero no en los lenguajes fuertemente tipados (como Java o C). Comparará dos valores o variables en valor y tipo, es decir, serátruecuando el valor y el tipo coinciden. Por ejemplo:
$c='10';$b=10;//Uso del operador "Igual"$a=$c==$b;//$a sería true por la conversión automática//Uso del operador "IDENTICO"$a=$c===$b;//$a sería false, porque son de tipos diferentes aunque tengan el mismo valor
El objetivo de esta operación es comparar valor y tipo, recuerda quePHPrealiza conversión automática de tipos y muchas veces no es deseable. Siempre que tengas sobre el resultado de la conversión automática usa el operador===:
$c='';$b=0;//Uso del operador "Igual"$a=$c==$b;//$a sería true PHP<8 y false en PHP>=8//Uso del operador "IDÉNTICO"$a=$c===$b;//$a sería false, porque son de tipos diferentes
No idéntico ($b!==$c)
Comparación
Serátruecuando ambos operandos tengan distinto valor, o bien, sean de distinto tipo:
$c='10';$b=10;$d=11;$a=$c!==$b;//$a sería true, porque son de distinto tipo$a=$b!==$d;//$a sería true, porque tienen distinto valor
Nave espacial ($a <=> $b)
Comparación
Generará un número menor de cero si el primer operando es menor que el segundo, cero si son iguales y un número mayor de cero si el primero es mayor que el segundo:
$b=10;$c=7;$d=7;$a=$c<=>$b;//$a sería -1, puesto que 7<10$a=$c<=>$d;//$a sería 0, puesto que 10=10$a=$b<=>$d;//$a sería 1, puesto que 10
O exclusivo (XOR)
Lógico
La operación O exclusiva o XOR está también otros lenguajes, si se incluye aquí es por lo atípico de su sintaxis. Esta operación producirá true solo sí los operandos tienen valores booleanos diferentes:
Al igual que ocurría con el operador AND y OR, el operador XOR tiene menos prioridad que la asignación, de ahí que sea necesario usarla con paréntesis en algunos casos.
Como ya imaginarás, en una misma expresión se pueden acumular varias operaciones, y que al realizar las operaciones se aplica precedencia de operadores:
<?php
$c=10; $b="7";
$a=$c+$b*$c;
En el ejemplo anterior, la multiplicación tiene más prioridad que la suma, por lo que se realiza primero. También seguramente sabrás que si necesitas que una operación se haga antes que otra (por ejemplo, la suma antes que la multiplicación en el ejemplo anterior), puedes aplicar paréntesis:
<?php
$c=10; $b="7";
$a=($c+$b)*$c; //La suma se realizará antes
En PHP la precedencia de operadores es similar a la de lenguajes como Java, aunque en PHP hay algunos operadores diferentes. Veamos que operaciones tiene más prioridad (de mayor a menor):
Operaciones aritméticas de autoincremento y negación: ++, --, !.
Operaciones aritméticas de multiplicación *, división / y módulo %.
Operaciones de suma, resta y concatenación.
Operaciones de comparación (<, >, ==, etc.).
Operador &&.
Operador ||.
Operador ternario (? :)
Operaciones de asignación (=, +=, .=, etc.).
Operador and.
Operador xor.
Operador or.
La precedencia de operadores en PHP permite hacer cosas complejas y singulares en pocas líneas de código. Por ejemplo, podemos condicionar la ejecución de un código al valor de una condición:
<?php
$r = random_int(1,10);
$r<5 and print 'El valor de $r es menor de 5' or print 'El valor de $r es mayor o igual a 5' ;
En el ejemplo anterior, se mostrará un texto u otro en función de si $r es menor de 5 o no, pero podría realizarse una asignación u otra operación:
<?php
$r = random_int(1,10);
$r<5 and $cad='El valor de $r es menor de 5' or $cad='El valor de $r es mayor o igual a 5';
echo $cad;
Otro ejemplo de código anidado que aprovecha la precedencia de operadores en PHP puede ser el siguiente:
<?php
echo 'El número '.($b=random_int(1,10))*($c=random_int(1,10)).' se puede obtener multiplicando '. $b.' por '.$c;
//Generará cadenas como "El número 40 se puede obtener multiplicando 8 por 5"
El ejemplo anterior se aprovecha, por ejemplo, de que la concatenación tiene menor precedencia que la multiplicación, que se haría antes. Y también del hecho de que la asignación al ponerla entre paréntesis se evalúa antes que la multiplicación y la concatenación.
Photodisc CD-DVD Num. V07. Imagen adquirida por el Ministerio de Educación para su uso en materiales educativos para FP a Distancia.(Todos los derechos reservados)
Es muy raro el programa que utilice solo tipos simples, y más en PHP. Carlos ya ha asumido que tendrá que utilizar arrays para casi cualquier código que haga. La información del servidor, los datos que introduce el usuario, o las cadenas de texto. Gran parte de las variables que se usan en un programa están en forma de array.
Por tanto, el siguiente paso está claro: hay que dominar los arrays. Crearlos, utilizarlos, recorrerlos... Y como acaba de aprender, antes de ponerse a programar le echará un vistazo a las funciones que ya existen para manejarlos. Si las puede aprovechar en sus programas, ¡mejor!
Un tipo de datos compuesto es aquel que te permite almacenar más de un valor. En PHP puedes utilizar dos tipos de datos compuestos: el array y el objeto. Los objetos los veremos más adelante.
En PHP los arraysson una estructura muy flexible. Se comportan como listas en las que podemos almacenar varios valores de diferente tipo, pero también como mapas, donde podemos asociar los elementos del array a una clave o keyque podemos usar posteriormente para acceder al valor. Cada miembro del array se almacena en una posición a la que se hace referencia utilizando un valor clave. Las claves pueden ser numéricas o asociativas, dado lugar a dos usos: arrays indexados y arrays asociativos.
Arrays indexados
En PHP podemos crear un array de muchas formas:
Usando la función array a la que pasamos una lista de valores.
Usando la sintaxis compacta de llaves ['a','b','c'].
Creando un array vacío y rellenándolo.
A continuación tienes algunos ejemplos de uso:
<?php
$array1=array(1,2,'tres',4.0);
$array2=[1,2,'tres',4.0]; //Sintaxis compacta de creación de arrays
$array3=array(); //Creamos el array vacío y vamos añadiendo elementos indexados
$array3[0]=1;
$array3[1]=2;
$array3[2]='tres';
$array3[3]=4.0;
$array4=[]; //Creamos el array vacío y vamos añadiendo elementos a modo de pila
$array4[]=1; //Guarda 1 en $array[0]
$array4[]=2; //Guarda 2 en $array[1]
$array4[]='tres'; //Guarda 'tres' en $array[2]
$array4[]=4.0; //Guarda 4.0 en $array[3]
En el último ejemplo ($array4[]) los elementos se van almacenando en posiciones indexada consecutivas (0, 1, 2, 3, ...), sin necesidad de indicar la posición. Además, en PHP no es necesario que indiques el tamaño del array antes de crearlo y ni siquiera es necesario indicar que una variable concreta es de tipo array. Simplemente puedes comenzar a asignarle valores:
$array5[0]='A';
$array5[1]='B';
$array5[2]='C';
Para saber el tamaño de un array podemos usar la función count:
<?php
$array1=array(1,2,'tres',4.0);
echo 'El tamaño del array es ';
echo count($array1); // Mostrará 4
Y como ya imaginarás, los ejemplos anteriores donde trabajamos con arrays indexados, los elementos son accesibles por su posición:
Pero como ya se ha comentado antes, en PHP los arrays también pueden ser asociativos, es decir, su posición se puede acceder por una clave. Crearlos es muy sencillo, simplemente indicamos la clave con la que se puede acceder a cada elemento:
<?php
//Crear un array asociativo usando la función "array"
$array1=array('lunes'=>7.3,'martes'=>3,'miércoles'=>12);
//Crear un array asociativo usando corchetes de inicialización
$array2=['lunes'=>7.3,'martes'=>3,'miércoles'=>12];
//Crear un array asociativo directamente
$array3['jueves']=15;
$array3['viernes']=16;
La forma de mostrar los elementos es idéntica a la versión indexada, simplemente en vez de usar un índice numérico, usamos la clave.
echo $array3['jueves'] + $array3['viernes']=16;
Sin embargo hay una peculiaridad que debes conocer. En realidad un array en PHP es asociativo e indexado simultáneamente. Un array en PHP puede tener claves que sean texto o números de forma indiferente:
Por otro lado, es importante que sepas que cuando se añade un nuevo elemento a un array sin especificar un índice, PHP utiliza el mayor índice numérico existente y lo incrementa en 1 para determinar el nuevo índice. En el ejemplo siguiente, el mayor índice numérico es 99, por lo que el siguiente índice disponible es 100. Al añadir $array[] = 10;, PHP asigna el valor 10 al índice 100 del array:
<?php
$array=array('lunes'=>7.3,99=>3,'miércoles'=>12);
$array[]=10; //Creara $array[100] y guardará ahí el valor 10
echo $array[100]; //Mostrará 10
En PHP es tremendamente habitual encontrar arrays anidados, es decir, arrays dentro de arrays (tanto indexados como asociativos), en dos o más niveles:
Este tipo de estructura es tremendamente común, especialmente al usar bases de datos, donde los resultados de las consultas SELECT suelen tener un aspecto como el siguiente:
En el caso de los arrays indexados o numéricos, eliminar un elemento significa que las claves del mismo ya no estarán consecutivas. En el caso anterior, si mostraros el contenido del $arrayIndexado tras la eliminación veremos el hueco que deja el elemento eliminado:
$arrayIndexado=array('a', 'b', 'c', 'd', 'e');
unset ($arrayIndexado[1]); //Elimina $arrayIndexado[1] y el elemento 'b' almacenado
unset ($arrayIndexado[3]); //Elimina $arrayIndexado[3] y el elemento 'd' almacenado
print_r($arrayIndexado);
/* Mostrará:
Array
(
[0] => a
[2] => c
[4] => e
)
*/
La función count realiza un recuento de los elementos del array y su valor no tiene correspondencia directa con el último índice numérico. En el ejemplo anterior, tras la eliminación de los elementos 1 y 3 la función count($arrayIndexado) retornaría 3 y no estaría relacionado con el último índice numérico que sería 4.
En PHP las cadenas de texto pueden definir usando tanto comillas simples ($cadena='ejemplo') como comillas dobles ($cadena="ejemplo"). Sin embargo hay una diferencia importante entre usar comillas simples o comillas dobles.
Las cadenas con comillas dobles son procesadas y tienen un coste computacional superior porque en ellas se expanden los nombres de las variables y se transforman las secuencias de escape, cosa que no se realiza en cadenas con comillas simples. Por ejemplo:
<?php
$modulo="DWES";
print "<p>Las siglas de este módulo son $modulo</p>"
La variable $modulo se reconoce dentro de las comillas dobles, y se sustituye por el valor "DWES" antes de generar la salida. Si esto mismo lo hubieras hecho utilizando comillas simples, no se realizaría sustitución alguna.
Al usar las comillas dobles también se realiza sustitución de secuencias de escape. En esta tabla puedes ver las secuencias de escape que se pueden utilizar, y cuál es su resultado.
Secuencias de escape en cadenas con comillas dobles.
Secuencia
Resultado
\\
se muestra una barra invertida.
\'
se muestra una comilla simple.
\"
se muestra una comilla doble.
\<code>n
se muestra un avance de línea (LF o 0x0A (10) en ASCII).
\r
se muestra un retorno de carro (CR o 0x0D (13) en ASCII).
\t
se muestra un tabulador horizontal (HT o 0x09 (9) en ASCII).
NOTA: HTML convertirá el tabulador en espacio salvo si se mete entre etiquetas
y
ej: print "
prueba prueba
";
\v
se muestra un tabulador vertical (VT o 0x0B (11) en ASCII).
\f
se muestra un avance de página (FF o 0x0C (12) en ASCII).
\$
se muestra un signo del dólar.
Sin embargo cuando se usan comillas simples, sólo se realizan dos sustituciones dentro de la cadena: cuando se encuentra la secuencia de caracteres \', donde se muestra en la salida una comilla simple; y cuando se encuentra la secuencia \\, donde se muestra en la salida una barra invertida.
Recuerda que en PHP la concatenación de cadenas se realiza con el operador "punto" (.), y que con el operador (.=) puedes concatenar y realizar una asignación de forma simultanea:
Cuando es necesario escribir cadenas muy largas tenemos dos opciones. Fragmentar la cadena y concatenarla:
$a = 'El módulo de Desarrollo de Aplicaciones Web en entorno Servidor '.
' es del ciclo de Desarrollo de Aplicaciones Web';
print $a;
O bien usar las sintaxis heredoc y nowdoc. Consiste en poner el operador <<< seguido de un identificador de tu elección, y a continuación y empezando en la línea siguiente la cadena de texto en una o varias líneas sin utilizar comillas. La cadena finaliza cuando escribes el identificador en una nueva línea. Esta línea de cierre no debe llevar más caracteres, ni siquiera espacios o sangría (debe escribirse a la izquierda del todo), salvo quizás un punto y coma después del identificador.
//Ejemplo de uso de HEREDOC
$ciclo='Desarrollo de Aplicaciones Web';
$a = <<<FINCADENA
El módulo de Desarrollo de Aplicaciones Web en entorno Servidor
es del ciclo de $ciclo
FINCADENA;
echo $a;
//Ejemplo de uso de NOWDOC
$a = <<<'FINCADENA'
El módulo de Desarrollo de Aplicaciones Web en entorno Servidor
es del ciclo de Desarrollo de Aplicaciones Web
FINCADENA;
echo $a;
La diferencia entre heredoc y nowdoc es que el identificador en el segundo caso va entre comillas simples. En heredoc el texto se procesa de igual forma que si fuera una cadena entre comillas dobles, expandiendo variables y secuencias de escape. Sin embargo, en el caso de nowdoc no se realizará ninguna expansión de variables, dado que se comporta como el entrecomillado simple.
Las cadenas de texto son el principal tipo de dato usado en cualquier aplicación web. Ten en cuenta que la información transmitida entre un cliente HTTP y el servidor HTTP es siempre texto. Tanto es así que cuando se envía un dato numérico a través de HTTP se envía como cadena de texto ($a='10';) y no como número en formato binario ($b=10;), y es necesaria realizar una conversión de tipo o aprovecharnos de la conversión automática de tipos de PHP.
Es por ello que conocer como realizar las operaciones básicas de tratamiento de cadenas con PHP es fundamental. A continuación tienes los casos principales:
Conocer la longitud de una cadena
Para conocer la longitud de una cadena debemos hacer uso de la funciónstrlen:
<?php
$cadena='Bienvenido al módulo de Desarrollo Web en Entorno Servidor';
echo 'La longitud de la cadena es:';
echo strlen($cadena);
Extraer un carácter de la cadena
A la hora de extraer un carácter de una cadena podemos tratar esta como si fuera un array, donde el primer elemento está en la posición cero y el último en longitud - 1:
<?php
$cadena='Bienvenido al módulo de Desarrollo Web en Entorno Servidor';
echo $cadena[0]; //Imprimirá 'B', el primer carácter
echo $cadena[strlen($cadena)-1]; //Imprimirá 'r', el último carácter
También es posible modificar un carácter concreto usando la operación anterior:
A veces es necesario partir una cadena en varias cadenas usando un delimitador. El delimitador será el carácter que se usará para partir la cadena. Esta operación, por otro lado muy común, podemos realizarla usando la función explode:
<?php
$cadena="Bienvenido a DWES";
//dividimos la cadena usando como delimitador el espacio
$partes=explode(' ',$cadena);
//Mostramos los dos últimos fragmentos
echo $partes[1]; //Mostrará "a"
echo $partes[2]; //Mostrará "DWES"
Como puedes observar en el ejemplo anterior, la función explode generará un array con las diferentes partes.
Unión de fragmentos de cadenas
Otra operación frecuente es la unión de fragmentos de cadenas almacenados en un array usando un texto de unión. Para realizar esto podemos usar la funciónimplodeo la funciónjoin, ambas funciones hacen exactamente lo mismo:
En numerosas ocasiones encontrarás necesario extraer una sección de una cadena. El método substr es un método específico para extraer fragmentos de cadenas. Su uso es muy sencillo:
substr($cadena, $posicion_inicio, $longitud)
Básicamente, se indica la posición de inicio donde se desea empezar a extraer (teniendo en cuenta que la primera posición es la cero) y el número de caracteres a extraer ($longitud). Por ejemplo:
A la hora de usar este método también nos pueden ayudar los métodos strpos y strrpos, que nos permiten encontrar una posición de una cadena dentro de otra.
Imagina que tienes una cadena como la siguiente: 12/12/2023 que contiene una fecha y quieres separarla en diferentes subcadenas (una para el día, otra para el mes y otra para el año). Aunque en este caso podríamos usar la función explode, vamos a usar substr y strpos para ello. Para ello, vamos a seguir los siguientes pasos:
Encontrar la posición dentro de la cadena del separador con strpos.
Extraer de la cadena el texto entre el comienzo de la cadena (posición 0) y la posición del separador, usando para ello substr.
La función strpos retorna la posición del separador (o subcadena) dentro de la cadena. Esta función admite un tercer parámetro: strpos($cadena,$separador,$inicio); el parámetro $inicio permite indicar a partir de qué posición se empieza a buscar. Jugando un poco con las matemáticas podemos extraer todas las partes de la fecha usando strpos y substr, veamos como:
Otra operación extremadamente común es la de quitar espacios anteriores y posteriores en una cadena de texto. Para esta misión puedes usar la función trim:
<?php
$cadena=' Bienvenidos al DWES ';
$cadenaLimpia=trim($cadena);
echo $cadenaLimpia; //Mostraría "Bienvenidos a DWES"
Comparar cadenas
Comparar cadenas es muy fácil en PHP, dado que el uso de los operadores <, <=, ===, >= y >. Cuando estos operadores de comparación son usados con cadenas se realiza una comparación lexicográfica. Por ejemplo:
<?php
$cadena1='_A2';
$cadena2='B_3';
if ($cadena1>$cadena2)
{
echo "$cadena1 va después de $cadena2 lexicográficamente";
}
elseif ($cadena1===$cadena2)
{
echo "$cadena1 y $cadena2 son iguales lexicográficamente";
}
else
{
echo "$cadena1 va antes de $cadena2 lexicográficamente";
}
Es importante que tengas en cuenta que las mayúsculas son anteriores lexicográficamente a las minúsculas. Esto quiere decir que A es anterior a a. Si no es este el efecto que deseas, deberás normalizar las cadenas, convirtiéndolas a mayúsculas o minúsculas antes de hacer la comparación usando $cadenaMayusculas=strtoupper($cadena) o $cadenaMinusculas=strtolower($cadena).
Para comparar cadenas también puedes usar la función strcmp (comparar diferenciando mayúsculas de minúsculas) y strcasecmp (comparar sin diferenciar mayúsculas y minúsculas), que retornarán un número mayor de cero si la primera cadena es posterior a la segunda, cero si son iguales, o un número menor de cero si la primera cadena es anterior a la segunda. A continuación tienes un ejemplo de su uso:
<?php
$cadena1='XYZ';
$cadena2='def';
$comp=strcasecmp($cadena1,$cadena2);
if ($comp>0)
{
echo "$cadena1 va después de $cadena2";
}
elseif ($comp==0)
{
echo "$cadena1 y $cadena2 son iguales";
}
else
{
echo "$cadena1 va antes de $cadena2";
}
La comparación lexicográfica en PHP compara cadenas carácter por carácter según sus valores ASCII, similar a cómo se ordenan las palabras en un diccionario, considerando letras, números y otros símbolos. Por ejemplo, el número '1' (valor ASCII 49) es lexicográficamente anterior a la letra '7' (valor ASCII 55), y ambos son anteriores lexicográficamente a la letra 'A' (valor ASCII 65) y a la letra 'a' (valor ASCII 97).
PHP incluye unas cuantas variables internas predefinidas que pueden usarse desde cualquier ámbito, dentro de una función o método de una clase sin necesidad de pasarlas por parámetro y sin tener que usar la palabra reservada global. Por ese motivo reciben el nombre de variables superglobales.
Cada una de estas variables es un array que contiene un conjunto de valores. Las variables superglobales disponibles en PHP son las siguientes:
$_SERVER: Contiene información sobre el entorno del servidor web y de ejecución. Entre la información que nos ofrece esta variable, tenemos:
Principales valores de la variable $_SERVER
Valor
Contenido
$_SERVER['PHP_SELF']
guion que se está ejecutando actualmente.
$_SERVER['SERVER_ADDR']
dirección IP del servidor web.
$_SERVER['SERVER_NAME']
nombre del servidor web.
$_SERVER['DOCUMENT_ROOT']
directorio raíz bajo el que se ejecuta el guion actual.
$_SERVER['REMOTE_ADDR']
dirección IP desde la que el usuario está viendo la página.
$_SERVER['REQUEST_METHOD']
método utilizado para acceder a la página ('GET', 'HEAD', 'POST' o 'PUT')
$_GET y $_POST: contienen los datos que se han pasado al script actual utilizando respectivamente los métodos HTTP GET (como parámetros en la URL) y HTTP POST (como datos de formulario). Estos se pondrán en uso más adelante en esta unidad.
$_COOKIE: que será un array que contendrá las cookies recibidas del navegador, algo que veremos en unidades posteriores.
$_REQUEST: que es un array asociativo donde se une en un solo lugar todo el contenido de los tres arrays anteriores: $_GET, $_POST y $_COOKIE.
$_ENV: contiene las variables que se puedan haber pasado a PHP desde el entorno en que se ejecuta.
$_FILES: contiene los ficheros que se puedan haber subido al servidor utilizando el método HTTP POST, y que veremos también más adelante en esta unidad.
$_SESSION: contiene las variables de sesión disponibles para el guión actual. Esta variable superglobal la usaremos mucho en próximas unidades.
Y por otro lado tendremos las constantes mágicas. Son constantes que su valor es dependiente de donde se utilicen, de ahí que se llamen constantes mágicas. Un ejemplo es la constante __LINE__, que contendrá el número del línea dentro del script, por ejemplo:
Stockbyte. CD-DVD Num. CD165.. Imagen adquirida por el Ministerio de Educación para su uso en materiales educativos para FP a Distancia.(Todos los derechos reservados)
¡Bien! Ya están claros los fundamentos del lenguaje.
Pero con lo visto hasta el momento, sólo es posible hacer programas muy sencillos. Para poder empezar a programar, Carlos sabe qué debe estudiar a continuación. Una de las partes más importantes de cualquier lenguaje es la que permite tomar decisiones, es decir, las sentencias que se pueden usar para indicar bajo qué condiciones se debe ejecutar una instrucción o un bloque de instrucciones. Y como no, también las sentencias para repetir la ejecución de ciertas líneas de código.
Cuando domine esas estructuras, podrá empezar a probar todo lo que lleva aprendido.
En PHP los guiones se construyen en base a sentencias simples. Utilizando llaves { ... }, puedes agrupar las sentencias en conjuntos, los cuales se comportan como si fueran una única sentencia un bloque de sentencias. Por ejemplo:
<?php
$a=10; //Sentencia simple
{ //Inicio de bloque de sentencias
$a++;
echo "$a";
echo "<BR>";
} //Fin de bloque de sentencias
Para definir el flujo de un programa en PHP, al igual que en la mayoría de lenguajes de programación, existen dos tipos de estructuras de control: condicionales, que permiten definir las condiciones bajo las que debe ejecutarse una sentencia o un bloque de sentencias ({ ... }); y bucles, con los que puedes definir si una sentencia o bloque de sentencias se repite o no y bajo qué condiciones. En este apartado vamos a abordar como son estas estructuras de control en PHP.
En cualquier caso, tienes que tener en cuenta que estas estructuras de control (condicionales y bucles) pueden trabajar con una sentencia o con un bloque de sentencias:
$a=random_int(1,10);
$condicion=$a>=2 && $a<=6;
if ($condicion)
{ //Bloque de sentencias ejecutado de forma condicional
$a++;
echo "$a";
}
if ($condicion)
$b=$a; //Sentencia simple ejecutada de forma condicional
Pero antes de adentrarnos en las estructuras de control, debes saber que en PHP puedes usar también (aunque no es recomendable) la sentencia goto, que te permite saltar directamente a otro punto del programa que indiques mediante una etiqueta.
<?php
$a = 1;
goto salto;
$a++; //esta sentencia no se ejecuta
salto:
echo $a; // el valor obtenido es 1
?>
=$a)" escrito en una libreta y rodeado de un circulo." title="Un verdadero if" width="250" height="152" />
Elaboración propia.(Dominio público)
La sentencia if permite la ejecución condicional de código. Un código solo se ejecutará si se cumple una condición dada:
<?php
if (...condicion...)
{
... acción...
}
En PHP se puede usar la siguiente sintaxis alternativa:
<?php
if (...condicion...):
... acción...
endif;
La condición debe ser una expresión que produzca un booleano (true o false), por ejemplo: $a<5 && $b<5. Solo si la expresión se evalúa a true se ejecuta el código anexo. A continuación puedes ver un ejemplo (código tradicional y sintaxis alternativa de PHP):
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5)
{
echo "$a y $b son menores de 5<BR>";
}
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5):
echo "$a y $b son menores de 5<BR>";
endif;
Cuando el resultado de la expresión sea false, es decir, cuando no se cumpla la condición, puedes utilizar else para indicar una sentencia o grupo de sentencias a ejecutar en ese caso:
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5)
{
echo "$a y $b son menores de 5<BR>";
}
else
{
echo "$a o $b o ambos son mayores de 5<BR>";
}
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5):
echo "$a y $b son menores de 5<BR>";
else:
echo "$a o $b o ambos son mayores de 5<BR>";
endif;
Cuando necesitamos encadenar varios else if, porque hay que tratar condiciones excluyentes, puedes usar el constructo elseif de PHP equivalente a concatenar varias estructuras else if seguidas. Observa los siguientes ejemplos:
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5)
echo "$a y $b son menores de 5<BR>";
else if ($a<5 && $b>=5)
echo "$a es menor de 5 pero $b es mayor o igual a 5<BR>";
else if ($a>=5 && $b<5)
echo "$a es mayor o igual a 5 pero $b es menor de 5<BR>";
else
echo "$a y $b son mayores de 5<BR>";
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5)
echo "$a y $b son menores de 5<BR>";
elseif ($a<5 && $b>=5)
echo "$a es menor de 5 pero $b es mayor o igual a 5<BR>";
elseif ($a>=5 && $b<5)
echo "$a es mayor o igual a 5 pero $b es menor de 5<BR>";
else
echo "$a y $b son mayores de 5<BR>";
<?php
$a=random_int(0,10);
$b=random_int(0,10);
if ($a<5 && $b<5):
echo "$a y $b son menores de 5<BR>";
elseif ($a<5 && $b>=5):
echo "$a es menor de 5 pero $b es mayor o igual a 5<BR>";
elseif ($a>=5 && $b<5):
echo "$a es mayor o igual a 5 pero $b es menor de 5<BR>";
else:
echo "$a y $b son mayores de 5<BR>";
endif;
Cuando, como sucede en los ejemplos anteriores, la sentencia if elseif o else actúe sobre una única sentencia, no será necesario usar llaves. No obstante, cuando usas la sintaxis alternativa (if:) no hay que poner llaves como puedes observar.
Por otro lado, otra estructura de control condicional es la sentencia switch. Es similar a enlazar varias sentencias if comparando una misma variable con diferentes valores. Cada valor va en una sentencia case. Cuando se encuentra una coincidencia, comienzan a ejecutarse las sentencias siguientes hasta que acaba el bloque switch o hasta que se encuentra una sentencia break. Si no existe coincidencia con el valor de ningún case, se ejecutan las sentencias del bloque default (si existe). Ten en cuenta que el bloque default no es obligatorio:
<?php
$a=random_int(0,2);
switch ($a) {
case 0:
print 'a vale 0';
break;
case 1:
print 'a vale 1';
break;
default:
print 'a no vale 0 ni 1';
}
<?php
$a=random_int(0,2);
switch ($a):
case 0:
print 'a vale 0';
break;
case 1:
print 'a vale 1';
break;
default:
print 'a no vale 0 ni 1';
endswitch;
Y por último, a partir de PHP 8 podemos usar la expresión match, donde la idea no es realizar una acción, sin que el operador retorne un valor cuando se encuentra una coincidencia de valor y tipo (===):
Imagina que tienes que hacer un programa que compruebe si dos números al azar entre 1 y 49 son iguales o no. ¿Cómo lo implementarías usando if, switch y match? Para elegir un número al azar puedes usar la función random_int(1,49). La idea es que muestre un mensaje coherente cuando son iguales y cuando son distintos.
Veamos ahora como son los bucles en PHP. Como ya sabes, los bucles se ejecutan mientras la condición de permanencia sea true. Cuando la condición de permanencia es false entonces el bucle termina. Veamos como serían en PHP:
Tabla comparativa de sintaxis tradicional y alternativa de bucles en PHP
Tipo de estructura
Sintaxis tradicional
Sintaxis alternativa
Bucle Mientras
while (/*condición de permanencia*/)
{
//código
}
while (/*condición de permanencia*/):
//código
endwhile;
En los bucles while la condición de permanencia es también una condición de entrada. Es decir, si la condición de permanencia no se cumple antes de empezar el bucle, el bucle no se ejecutará ni una sola vez.
Bucle Hacer Mientras
do {
//código
} while (/*condición de permanencia*/)
NO EXISTE
A diferencia del bucle while, en los bucles do-while el código se ejecuta al menos una vez.
Bucle For
for (/*expr1*/;/*Condición de permanencia*/;/*expr3*/)
{
//código
}
for (/*expr1*/;/*Condición de permanencia*/;/*expr3*/):
//código 1
endfor;
En los bucles for la expr1 suele ser una inicialización (como $i=0) y expr3 suele una operación aritmética destinada a actualizar el valor inicializado (como $i++);
Una vez revisada la sintaxis, veamos algunos ejemplos. En los bucles while puedes por tanto hacer que un bloque se ejecute mientras se cumpla la condición de permanencia. La condición de permanencia se evalúa antes de comenzar cada iteración del bucle.
<?php
$a = random_int(0,99);
$b = random_int($a+1,100);
$suma=0;
$c=$a;
while ($c <= $b)
{
$suma+=$c;
$c++;
}
print "La suma de los números desde $a hasta $b es $suma";
En el ejemplo anterior, tal y como está diseñado, siempre se va a ejecutar una vez (dado que $b siempre será mayor que $a). Quizás sea buena idea utilizar un bucle do-while. Es un bucle similar al anterior, pero la condición de salida se evalúa al final, con lo cual se asegura que la sentencia o conjunto de sentencias del bucle se ejecutan al menos una vez:
<?php
$a = random_int(0,99);
$b = random_int($a+1,100);
$suma=0;
$c=$a;
do
{
$suma+=$c;
$c++;
} while($c <= $b);
print "La suma de los números desde $a hasta $b es $suma";
Y por supuesto, el ejemplo anterior también se puede hacer con un bucle for, y aunque parezcan fáciles es mejor revisarlos en profundidad, dado que pueden resultar liosos en numerosas ocasiones. En los bucles suelen aparecer tres expresiones for (expr1; expr2; expr3), veamos que significa cada una:
La primera expresión, expr1, se ejecuta solo una vez al comienzo del bucle, por ello se le llama de inicialización. En esta expresión puede inicializarse una variable ($i=0) o varias variables (separadas por comas: $i=0,$j=0).
La segunda expresión, expr2, se evalúa al comienzo de cada iteración para saber si se debe ejecutar o no la sentencia o conjunto de sentencias. Por ello se le llama condición de permanencia. Si la condición de permanencia se evalúa a false, el bucle termina. Si el resultado es true, se ejecutan la sentencia o bloque de sentencias anexos.
Y por último, al finalizar cada iteración, se ejecuta la tercera expresión, expr3, que está destinada a actualizar las variables que determinan la finalización del bucle, es por ello que se le llama actualización. En la actualización también puede actualizarse una variable ($i++) o varias variables separando cada sentencia por coma ($i++,$j--). Después de actualizar las variables, se vuelve al paso anterior donde se evalúa expr2 (condición de permanencia).
El ejemplo anterior en un bucle for podría hacerse así:
<?php
$a = random_int(0,99);
$b = random_int($a+1,100);
for ($c=$a,$suma=0;$c<=$b;$c++)
{
$suma+=$c;
}
print "La suma de los números desde $a hasta $b es $suma";
O incluso así:
<?php
$a = random_int(0,99);
$b = random_int($a+1,100);
for ($c=$a,$suma=0;$c<=$b;$suma+=$c,$c++);
print "La suma de los números desde $a hasta $b es $suma";
PHP, como otros lenguajes, tienen bucles específicos para recorrer estructuras iterables. Las estructuras iterables por excelencia en PHP son los arrays y los objetos, aunque hay más (cualquier clase que implemente la interfaz Iterable). Los bucles foreach de PHP son un claro ejemplo de ello, los cuales permiten recorrer un array elemento a elemento:
$dias=['lunes'=>'monday', 'martes'=>'tuesday', 'miércoles'=>'wednesday',
'jueves'=>'thursday', 'viernes'=>'friday', 'sábado'=>'saturday',
'domingo'=>'sunday'];
echo "Repasemos los días en inglés: ";
foreach ($dias as $diaeng)
{
echo "$diaeng ";
}
echo "<BR>";
Como puedes ver en el ejemplo la variable $diaeng irá tomando cada uno de los valores del array, en este caso, los nombres de los días en inglés. Si además, necesitamos saber cual es la clave de cada elemento (ya sea numérica o un texto), podemos realizar lo siguiente poner lo siguiente:
$dias=['lunes'=>'monday', 'martes'=>'tuesday', 'miércoles'=>'wednesday',
'jueves'=>'thursday', 'viernes'=>'friday', 'sábado'=>'saturday',
'domingo'=>'sunday'];
foreach ($dias as $diaesp=>$diaeng)
{
echo "$diaesp en inglés se escribe $diaeng<br>";
}
Con lo que, resumiendo, la estructura de los bucles foreach es la que se muestra a continuación (sintaxis normal y sintaxis alternativa):
foreach ($array as $clave => &$valor)
{
//... código
}
foreach ($array as $clave => &$valor):
//... código
endforeach;
Como has visto en ejemplos anteriores, la sección $clave => es opcional, y con ella iremos recogiendo las diferentes claves del array, y con la variable $valor podemos recoger los diferentes valores. Como puedes observar en la estructura anterior, podemos utilizar una referencia al valor de cada elemento, indicando &$valor (es opcional). Si se usa, podemos modificar los elementos del array (de otra forma, no podríamos). Por ejemplo:
<?php
$numeros=[1,2,3,4,5];
foreach ($numeros as &$numero)
{
$numero++;
}
print_r($numeros); //mostrará un array con los números: 2, 3, 4, 5 y 6
Si dentro de un bucle foreach necesitamos eliminar un elemento, podemos hacerlo de forma segura:
<?php
$numeros=[6,7,1,2,5];
foreach ($numeros as $posicion=>$numero):
if ($numero%2===0) unset($numeros[$posicion]);
endforeach;
print_r($numeros); //mostrará un array con los impares: 7, 1, 5
Haz una página PHP que utilice foreach para mostrar todos los valores del array $_SERVER en una tabla con dos columnas. La primera columna debe contener el nombre de la variable y la segunda su valor.
Pero en PHP también hay otra forma de recorrer los valores de un array. Cada array mantiene un puntero interno, que se puede utilizar con este fin. Utilizando funciones específicas, podemos avanzar, retroceder o inicializar el puntero, así como recuperar los valores del elemento (o de la pareja clave / elemento) al que apunta el puntero en cada momento. Algunas de estas funciones son:
Funciones para recorrer arrays.
Función
Descripción
reset
Sitúa el puntero interno al comienzo del array.
Ejemplo:
$array=[1,2,3];
$primerElemento=reset($array); //Siempre va al primer elemento y lo retorna
En el ejemplo anterior $primerElemento tendría el valor 1. El puntero interno se establece a la posición 0.
next
Avanza el puntero interno una posición y retorna el valor en dicha posición.
$array=[1,2,3];
$primerElemento=reset($array); //$primerElemento sería 1, puntero posición 0
$segundoElemento=next($array); //$segundoElemento sería 2, puntero posición 1
prev
Mueve el puntero interno una posición hacia atrás y retorna el elemento en dicha posición.
$array=[1,2,3];
$primerElemento=reset($array); //$primerElemento sería 1 y el puntero 0
$segundoElemento=next($array); //$segundoElemento sería 2 y el puntero 1
$primerElemento=prev($array); //$segundoElemento sería 1 y el puntero 0
end
Sitúa el puntero interno al final del array y retorna el valor en dicha posición.
<?php
$array=[1,2,3];
$tercerElemento=end($array); //$tercerElemento sería 3 y el puntero 2
current
Devuelve el elemento de la posición actual sin modificar el puntero.
$array=[1,2,3];
$primerElemento =reset($array); //$primerElemento sería 1 y el puntero 0
$segundoElemento=next($array); //$segundoElemento sería 2 y el puntero 1
$actual=current($array); //$actual sería 2 y el puntero sigue siendo 1
key
Devuelve la clave de la posición actual, muy útil con arrays asociativos:
$array=['a'=>1,'b'=>2,'c'=>3];
$primerElemento=reset($array); //$primerElemento sería 1
$keyPrimerElemento=key($array); //$keyPrimerElemento sería 'a'
$segundoElemento=next($array); //$segundoElemento sería 2
$keySegundoElemento=key($array); //$keyPrimerElemento sería 'b'
each
Esta función está obsoleta desde PHP 7.2.0 y no debería usarse. Devuelve un array con la clave y el elemento de la posición actual. Además, avanza el puntero interno una posición.
Recuerda, las funciones reset, next, prev y end, además de mover el puntero interno devuelven, al igual que current, el valor del nuevo elemento en que se posiciona. Si al mover el puntero te sales de los límites del array (por ejemplo, si ya estás en el último elemento y haces un next), cualquiera de ellas devuelve false.
Esto plantea algunos problemas, si el array contiene solo valores booleanos, al comprobar el valor devuelto no serás capaz de distinguir si te has salido de los límites del array, o si estás en una posición válida del array que contiene el valor false.
En cualquier caso, la comparación para saber se si se ha llegado al final debe hacerse siempre con la comparación idéntico === y no con una igualdad normal.
Por otro lado, la función key devuelve null si el puntero interno está fuera de los límites del array.
Cuando se trata de array en PHP recorrerlo tiene sus peculiaridades. Es habitual encontrar en Internet y otras fuentes códigos como el siguiente, aunque no siempre es ni el mejor ni el más adecuado:
<?php
$array=[10, 15, 20];
$array[]=25;
unset($array[1]);
$array[]=30;
//FORMA NO RECOMENDADA DE RECORRER UN ARRAY EN PHP
for ($i=0;$i<count($array);$i++)
{
echo $array[$i];
}
LaformaanteriorgeneraríaerrorPHPtipoNoticedadoqueelelemento$i=1noexiste(dehechosehaeliminadoenlalínea4).Una mejor forma y mucho más conveniente de recorrer el array es usando los métodos next y reset(yopcionalmentecurrent). Por ejemplo:
Haz una página PHP que utilice las funciones reset(...), key(...), next(...), etc. vistas en este apartado para mostrar una tabla con todos los datos del array $_SERVER (claves y valores).
Tal y como ocurre en otros lenguajes, en PHP, puedes anidar estructuras de control. Por ejemplo, en el siguiente código se muestran solo los elementos pares de un array:
$array = [10,11,12,13,14,15];
for ($i=reset($array);$i!==false;$i=next($array))
{
if ($i%2===0)
{
echo $i.'<br>';
}
}
También podemos anidar un bucle dentro de otro. En el siguiente código realiza la suma acumulativa de los elementos del array anterior (por ejemplo, la suma acumulativa del elemento $array[3] sería $array[0]+$array[1]+$array[2]+$array[3]). Ese cálculo se podría realizar con el siguiente guión PHP donde se anidan un bucle foreach dentro de otro:
$array = [10,11,12,13,14,15];
$resultado=[];
foreach ($array as $k1=>$v1)
{
$resultado[$k1]=$v1;
foreach ($array as $k2=>$v2)
{
if ($k2<$k1)
$resultado[$k1]+=$v2;
}
}
print_r($resultado);
Para este escenario, se ha puesto un if en el segundo bucle que limita el cálculo de la suma de forma que no se añadan a la suma números que no corresponden. El código anterior es mejorable, dado que el array es indexado y podríamos abortar la ejecución en el segundo bucle cuando ya sabemos que no hay elementos que sumar. Esto podemos hacerlo usando un simple break;
$array = [0,1,2,3,4,5];
$resultado=[];
foreach ($array as $k1=>$v1)
{
$resultado[$k1]=$v1;
foreach ($array as $k2=>$v2)
{
if ($k2<$k1)
$resultado[$k1]+=$v2;
else
break;
}
}
print_r($resultado);
El código anterior genera el mismo resultado pero de forma mucho más eficiente. Imagina ahora que lo que deseamos es que se sumen como máximo los dos números anteriores (por ejemplo, para el elemento $array[3] sería $array[1]+$array[2]+$array[3]). Ese código se podría usando la sentencia continue:
$array = [10,11,12,13,14,15];
$resultado=[];
foreach ($array as $k1=>$v1)
{
$resultado[$k1]=$v1;
foreach ($array as $k2=>$v2)
{
if ($k2<$k1-2) continue;
if ($k2<$k1)
$resultado[$k1]+=$v2;
else
break;
}
}
print_r($resultado);
La diferencia entre break y continue es que el primero rompe la ejecución del bucle, saliendo del mismo, mientras que el segundo detiene esa iteración y, sin salir del bucle, continua con la siguiente iteración.
break y continue aceptan un parámetro numérico que indica cuantas estructuras iterativas deben romper o saltar. Por defecto es 1, que hace referencia a la estructura iteractiva más inmediata. Si por ejemplo, deseamos que un break rompa la estructura iterativa de nivel superior podríamos indicarlo así:
<?php
for ($i = 1; $i <= 5; $i++) {
for ($j = 1; $j <= 5; $j++) {
if ($j == 4) {
break 2; // Sale de ambos bucles
}
echo "i = $i, j = $j<BR>\n";
}
}
echo "Salió de ambos bucles con break 2.\n";
En el ejemplo anterior se mostrará: i = 1, j = 1<BR>, i = 1, j = 2<BR> y i = 1, j = 3<BR> y se detendrá la ejecución. Puedes consultar más información sobre el uso de break y continue aquí:
Conforme vayan creciendo los programas que hagas, verás que resulta trabajoso encontrar determinadas partes del código dentro de aplicación web. Es por ello que resulta útil agrupar ciertos grupos de funciones o bloques de código y ponerlos en un fichero aparte. Posteriormente, puedes hacer referencia a esos ficheros para que PHP incluya su contenido como parte del programa actual.
Para incorporar a tu programa contenido de un archivo externo, tienes varias posibilidades:
include: Evalúa el contenido del fichero que se indica y lo incluye como parte del fichero actual, en el mismo punto en que se realiza la llamada. La ubicación del fichero puede especificarse utilizando una ruta absoluta, pero lo más usual es con una ruta relativa. En este caso, se toma como base la ruta que se especifica en la directiva include_path del fichero php.ini. Si no se encuentra en esa ubicación, se buscará también en el directorio del guión actual y en el directorio de ejecución.
include_once: Si por equivocación incluyes más de una vez un mismo fichero, lo normal es que obtengas algún tipo de error (por ejemplo, al repetir una definición de una función). include_once funciona exactamente igual que include, pero solo incluye aquellos ficheros que aún no se hayan incluido.
require: Si el fichero que queremos incluir no se encuentra, include da un aviso y continua la ejecución del guión. La diferencia más importante al usar require es que en ese caso, cuando no se puede incluir el fichero, se detiene la ejecución del guión.
require_once. Es la combinación de las dos anteriores. Asegura la inclusión del fichero indicado solo una vez, y genera un error si no se puede llevar a cabo.
A la hora de indicar la ruta del archivo a incluir ten en cuenta dos cosas:
Como separador de directorio suele usarse siempre / independientemente del sistema operativo. Esto hace que tu aplicación funcione tanto en sistemas Windows como Unix/Linux. No obstante, PHP tiene predefinida la constante DIRECTORY_SEPARATOR que se sustituirá por el separador concreto que use tu sistema operativo:
Por ejemplo: include '..'.DIRECTORY_SEPARATOR.'config.php' será equivalente a include '../config.php' en Unix/Linux y a include '..\config.php' en Windows.
Es común usar la constante mágica __DIR__ para establecer rutas desde el archivo actual. Esto facilita encadenar archivos PHP que se incorporan unos a otros y gestionar las dependencias.
Por ejemplo: include __DIR__.'\..\config.php' cargará el archivo config.php que está justo en el directorio padre del guión PHP que se está ejecutando en ese momento.
Muchos programadores utilizan la doble extensión .inc.php para aquellos ficheros en lenguaje PHP cuyo destino es ser incluidos dentro de otros, y nunca han de ejecutarse por sí mismos.
Es importante que sepas que cuando se comienza a evaluar el contenido del fichero externo, se abandona de forma automática el modo PHP y su contenido se trata en principio como etiquetas HTML. Por este motivo, es necesario marcar el inicio del código PHP que contendrá nuestro archivo externo utilizando el delimitador <?php:
Ejemplo de inclusión de un guión
Archivo index.php
Archivo src/ejemplo.php
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejemplo</title>
</head>
<body>
<?php
//Carga el archivo ejemplo.php en el directorio src
include __DIR__.'/src/ejemplo.php';
?>
</body>
</html>
<?php
echo "Hola mundo!";
Cuando el archivo importado contenga solo funciones o código PHP es recomendable NO cerrar el script o guión PHP con un ?>. El motivo principal es evitar que haya espacios en blanco y saltos de línea al final que puedan alterar la salida, lo cual es especialmente importante en algunos casos. Además, esto facilita la gestión del código y proporciona un código más limpio y acorde a las recomendaciones de la documentación oficial. También es recomendable que todos los ficheros de texto estén codificados en UTF-8.
Por otro lado, tienes que tener en cuenta que las variables de ámbito global creadas en el script o guión PHP principal que inicia la inclusión de otro serán también visibles en el script secundario incluido. Y además, también serán visibles las variables de ámbito global creadas en el script incluido secundario en el script principal. Fíjate en el siguiente ejemplo:
Visibilidad de variables entre scripts incluidos
Archivo index.php
Archivo src/ejemplo.php
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejemplo</title>
</head>
<body>
<?php
//Carga el archivo ejemplo.php en el directorio src
$bienvenida='Hola Mundo! ';
include __DIR__.'/src/ejemplo.php';
//Mostramos la variable $despedida creada en ejemplo.php
echo $despedida;
?>
</body>
</html>
<?php
//Mostramos la variable $bienvenida creada en index.php
echo $bienvenida;
//La variable $despedida también se podrá usar en index.php
$despedida='Vuelve pronto!';
Es importante que tengas en cuenta lo anterior, porque las inclusiones de nuevos scripts y el uso indiscriminado de variables puede afectar de un script a otro.
Por último es importante que tengas en cuenta que un script incluido puede usar return para abortar la ejecución o retornar un valor calculado. Para abortar la ejecución de un script sin retornar ningún valor simplemente indica "return;" a secas. Fíjate en el siguiente ejemplo:
Visibilidad de variables entre scripts incluidos
Archivo index.php
Archivo src/sumar.php
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Ejemplo</title>
</head>
<body>
<?php
//Carga el archivo ejemplo.php en el directorio src
$a=10;
$b=20;
$resultado=include __DIR__.'/src/sumar.php';
//La variable $mensaje e crea en el script sumar.php
echo $mensaje . $resultado;
?>
</body>
</html>
<?php
$mensaje="El resultado de la suma es: ";
return $a + $b;
Cuando necesitamos componer la salida de un script o guión utilizando partes de HTML o CSS que están en otros archivos y que no contienen PHP alguno, es mejor usar las funciones readfile o file_get_contents en vez de usar include y sus variantes.
El motivo es sencillo: include y sus variantes procesarán el archivo en busca de código PHP, lo que conlleva un gasto de cómputo innecesario si el archivo solo contiene HTML o CSS. La función readfile enviará el archivo pasado por parámetro directamente al navegador y la función file_get_contents cargará su contenido en una variable para su posterior uso, ambas sin procesar el archivo en busca de código PHP inexistente.
Consulta la documentación de ambas funciones, dado que su uso es muy conveniente:
Juan observa con agrado los progresos que va haciendo Carlos en su aprendizaje del lenguaje PHP. Con la ilusión que está poniendo, se integrará sin problemas en el nuevo proyecto. Cuantos más puedan colaborar, mejor.
Tras lo que ya ha visto, le recomienda que aprenda a crear y utilizar funciones. Sabe que no sólo es muy importante saber usarlas, sino también conocer todas las que hay disponibles en el lenguaje, o al menos, saber cómo buscarlas. En un lenguaje abierto como PHP, si sabes utilizar el código que ya hay programado, puedes ahorrarte una gran parte del trabajo.
Cuando quieres repetir la ejecución de un bloque de código, puedes utilizar un bucle. Las funciones tienen una utilidad similar: nos permiten asociar una etiqueta (el nombre de la función) con un bloque de código a ejecutar. Además, al usar funciones estamos ayudando a estructurar mejor el código. Como ya sabes, las funciones permiten crear variables locales que no serán visibles fuera del cuerpo de las mismas.
Como programador puedes aprovecharte de la gran cantidad de funciones disponibles en PHP. De éstas, muchas están incluidas en el núcleo de PHP y se pueden usar directamente. Otras muchas se encuentran disponibles en forma de extensiones y se pueden incorporar al lenguaje cuando se necesitan.
Con la distribución de PHP se incluyen varias extensiones. Para poder usar las funciones de una extensión tienes que asegurarte de activarla mediante el uso de una directiva extension en el fichero php.ini:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Cada extensión lleva asociado un binario que se carga al iniciar el servidor web responsable de cargar el motor PHP. Si se modifica el archivo php.ini es necesario reiniciar el servidor para que se vuelvan a cargar las extensiones.
Aunque muchas de las extensiones van instaladas o son instalables (por ejemplo en como paquetes de cualquier distribución). Muchas otras extensiones no se incluyen con la distribución estándar de PHP y antes de poder utilizarlas tienes que descargarlas e incluso compilarlas.
Para obtener extensiones para el lenguaje PHP puedes utilizar PECL. PECL es un repositorio de extensiones para PHP. En el siguiente enlace puedes encontrar información sobre la instalación de extensiones a través de PECL:
Un conjunto de funciones muy utilizado en PHP son las de acceso a base de datos. En las distribuciones de PHP usadas para Windows es común encontrar las extensiones necesarias para acceder a la base de datos ya instaladas, sin embargo, en Linux es común que se instalen como paquetes independientes para poder hacer nuestro sistema más óptimo. Por ejemplo, instalar la extensión que permite acceder a bases de datos MySQL desde PHP en Ubuntu se suele realizar con el siguiente comando:
sudo apt install php-mysql
En el siguiente enlace tienes una guía completa (en inglés) sobre como instalar extensiones PHP en Ubuntu:
Ya sabes que para hacer una llamada a una función, basta con poner su nombre, y entre paréntesis, los argumentos que dicha función necesita (si es que los necesita). Por ejemplo:
<?php
//Mostrar información sobre la instalación de PHP
phpinfo();
Para crear tus propias funciones, deberás usar la palabra reservada function seguido del nombre de la función, y entre paréntesis, el listado de argumentos que tu función necesita:
En el ejemplo anterior se utiliza la sentencia return. Como es conocido en otros lenguajes de programación y como se puede deducir del mismo ejemplo, la sentencia return concluye la ejecución del código de la función y, opcionalmente, puede devolver un valor. Si una función contiene una sentencia return con un valor asociado, esta finaliza su ejecución y retorna el valor especificado. Si no se especifica un valor de retorno en el return, la función simplemente termina su ejecución en ese punto sin retornar nada (en realidad retornará null). No obstante, no es necesario que una función retorne un valor, de hecho, si no retorna un valor no es necesario usar return.
Por otro lado, en PHP no es necesario definir una función antes de utilizarla, excepto cuando está condicionalmente definida como se muestra en el siguiente ejemplo:
Ejemplo 1) En el ejemplo siguiente se muestra que la función si existe y se ejecuta la misma:
<?php
$precio_sin_iva=10;
if (function_exists('precio_con_iva'))
{
echo "La función precio_con_iva SI existe. <BR>";
$pvp=precio_con_iva($precio_sin_iva);
printf ("El precio del producto IVA incluido es: %.2f €",$pvp);
}
else
{
echo "La función precio_con_iva no existe";
}
function precio_con_iva($precio) {
$precio_iva = $precio * 1.21;
return $precio_iva;
}
Ejemplo 2) En el siguiente ejemplo se muestra que la función no existe, porque la definición de la función está condicionada:
<?php
$precio_sin_iva=10;
if (function_exists('precio_con_iva'))
{
echo "La función precio_con_iva SI existe. <BR>";
$pvp=precio_con_iva($precio_sin_iva);
printf ("El precio del producto IVA incluido es: %.2f €",$pvp);
}
else
{
echo "La función precio_con_iva no existe";
}
if (isset($precio_sin_iva)) {
function precio_con_iva($precio) {
$precio_iva = $precio * 1.21;
return $precio_iva;
}
}
En el ejemplo anterior, la función function_exists permite comprobar si una función existe o no. Cuando la existencia de una función está condicionada, la definición de la función debe ser procesadas antes de ser llamada. Por tanto, la definición de la función debe estar antes de cualquier llamada a la misma:
<?php
$precio_sin_iva=10;
if (isset($precio_sin_iva)) {
function precio_con_iva($precio) {
$precio_iva = $precio * 1.21;
return $precio_iva;
}
}
$pvp=precio_con_iva($precio_sin_iva);
printf ("El precio del producto IVA incluido es: %.2f €",$pvp);
En PHP, al igual que en otros lenguajes, podemos tener funciones anónimas. Por ejemplo:
<?php
$precio_sin_iva=10;
$pvp=(function ($a) { return $a*1.21; })($precio_sin_iva);
echo "El precio con IVA del producto es $pvp";
En el ejemplo anterior, el código : "function ($a) { return $a*1.21; }" representa una función anónima (también conocida como cierre o closure); y tal y como está usada en el ejemplo, se invoca en ese momento con el parámetro que necesita. Quizás te resulte un poco confuso el ejemplo anterior y quizás escrito de la siguiente forma te resulte más familiar:
<?php
$precio_sin_iva=10;
$funcion=function ($a) { return $a*1.21; }; //Almacenar la función anónima en una variable
$pvp=$funcion($precio_sin_iva);
echo "El precio con IVA del producto es $pvp";
En el ejemplo anterior hemos almacenado la función en la variable $funcion. Por último, un aspecto curioso de las funciones en PHP es que se pueden escribir "entre comillas" a la hora de invocarlas, es decir, el nombre de la función puede ser una cadena de texto. Por ejemplo:
$precio_sin_iva=10;
function calcularIvaNormal ($a) { return $a*1.21; };
$pvp = 'calcularIvaNormal' ($precio_sin_iva); //El nombre de la función puede ser una cadena
echo "El precio con IVA del producto es $pvp";
Esto permite escribir código como el siguiente:
<?php
$precio_sin_iva=10;
function calcularIvaNormal ($a) { return $a*1.21; };
function calcularIvaReducido ($a) { return $a*1.10; };
$tipoIva='IvaReducido';
$pvp=('calcular'.$tipoIva) ($precio_sin_iva);
echo "El precio con IVA del producto es $pvp";
En el código anterior, el contenido de la variable $tipoIva se concatena a la hora de invocar la función, de forma que al realizar la concatenación 'calcular'.$tipoIva se conforma el nombre de la función calcularIvaReducido, que es la que finalmente se ejecuta. Si pruebas a cambiar el contenido de $tipoIva a 'IvaNormal' verás como se ejecuta la otra función.
El uso de global dentro de una función para acceder a variables creadas en el ámbito global es una práctica muy desaconsejada y que no debes emplear salvo circunstancias muy específicas y muy justificadas.
En PHP los argumentos o parámetros de las funciones se especifican, como has podido ver en los ejemplos de la sección anterior, entre los paréntesis:
function sumar ($inicio, $fin)
{
$suma=false;
for ($i=$inicio;$i<=$fin;$i++) $suma+=$i;
return $suma;
}
Sin embargo, la función anterior solo tiene sentido cuando se usa con números enteros, pero tal y como está definida realmente se puede usar con cualquier tipo de datos. Por suerte, en las últimas versiones de PHP es posible indicar el tipo en los parámetros de las funciones (concretamente desde PHP 7.0):
function sumar (int $inicio, int $fin)
{
$suma=false;
for ($i=$inicio;$i<=$fin;$i++) $suma+=$i;
return $suma;
}
Además, es posible también como será el valor retornado:
function sumar (int $inicio, int $fin): int|bool
{
$suma=false;
for ($i=$inicio;$i<=$fin;$i++) $suma+=$i;
return $suma;
}
En el ejemplo anterior se especifica que la función sumar puede retornar un entero o un booleano. De esta forma, si alguien intenta usar la función sumar con valores no numéricos dará un error y no permitirá su ejecución, y además, podrá saber exactamente que retornará. Progresivamente en PHP se han dado soportes a más tipos de datos y situaciones:
Evolución de la forma de indicar los parámetros en las funciones en PHP
Tipos de datos admitidos como parámetros y como valores de retorno
Ejemplos
A partir de PHP 5: se podía indicar que un parámetro debía ser un array o una instancia de una clase concreta (lo que se explorará en unidades posteriores).
function ejemplo(array $arr):array {
// código
}
A partir de PHP 7.0: se puede indicar que un parámetro debe ser int, string, bool o boolean o float.
PHP 7.1: se puede indicar que un parámetro debe ser iterable, y con void que una función no retorna nada.
function ejemplo1 (iterable $iter) {
// foreach ($iter as ...)
}
function ejemplo2 (array $ar): void {
//
}
PHP 7.2: se puede indicar que un parámetro debe ser un objeto (object), algo que veremos en unidades posteriores.
function ejemplo(object $obj) {
// código
}
PHP 8.0: permite indicar unión de tipos (por ejemplo: int|bool) que permite indicar que se admiten dos o más tipos de datos, y el tipo mixed para indicar que se admite cualquier tipo de dato.
function ejemplo1 (int|string $param) {
// $param será entero o cadena
}
function ejemplo2(mixed $param) {
// $param podrá ser cualquier tipo de dato
}
Además, desde PHP 7.1 es posible indicar usando el prefijo ? que un parámetro puede tener el valor null o que una función puede retornar un valor null:
<?php
function ejemplo (?string $cadena):?int
{
//$cadena puede ser string o null<br /><br /> return 2; //Podrá retornar un entero o null
}
Por otro lado, como ocurre en otros lenguajes de programación, al definir una función puedes indicar valores por defecto para los argumentos de forma que cuando hagas una llamada a la función no tienes porque indicar obligatoriamente de determinados argumentos:
function precio_con_iva(float $precio, float $iva = 0.21) : float {
return $precio * (1 + $iva);
}
$precio = 10;
$precio_iva = precio_con_iva($precio);
print "El precio con IVA es ".$precio_iva;
Puede haber valores por defecto definidos para varios argumentos, pero en la lista de argumentos de la función todos ellos deben estar a la derecha de cualquier otro argumento sin valor por defecto.
En los ejemplos anteriores los argumentos se pasaban por valor. Esto es, cualquier cambio que se haga dentro de la función a los valores de los argumento no se reflejará fuera de la función. Si quieres que esto ocurra debes definir el parámetro para que su valor se pase por referencia, añadiendo el símbolo & antes de su nombre:
<?php
function precio_con_iva(float &$precio, float $iva=0.18):void {
$precio *= (1 + $iva);
}
$precio = 10;
precio_con_iva($precio);
print "El precio con IVA es ".$precio;
En el ejemplo anterior la función no retorna nada (retorna void), lo que ocurre es que el parámetro $precio se pasa por referencia y las modificaciones del mismo dentro de la función afectan al valor de la variable fuera de la función.
Por último, a partir de PHP 8.0 es posible invocar una función usando el nombre de los argumentos. Esto permite cambiar el orden de los parámetros, veamos un ejemplo:
function precio_con_iva(float &$precio, float $iva=0.18):void {
$precio *= (1 + $iva);
}
$p=60;
//Invocación usando "argumentos o parámetros nombrados (named arguments)"
precio_con_iva( iva:0.10, precio:$p);
print "El precio con IVA es ".$p;
Fíjate que en cada parámetro o argumento se indica el nombre del mismo, y a continuación tras los dos puntos, el valor o variable usada como dicho parámetro.
A partir de PHP 5.6 es posible utilizar ...$var para indicar que una función acepta un número variable de argumentos:
function lista(...$items){
echo "<UL>";
foreach ($items as $item) echo "<LI>$item</LI>";
echo "</UL>";
}
lista(1,2,3);
//Mostrará : <UL><LI>1</LI><LI>2</LI><LI>3</LI></UL>
Cuando se usa esta característica los argumentos son tratados como un array. Para esta y otras características adicionales consulta el siguiente enlace:
Como ya sabes, en PHP puedes utilizar variables en cualquier lugar de un programa. Si una variable aún no existe, la primera vez que se utiliza se reserva espacio para ella. En ese momento, dependiendo del lugar del código donde se crea, se puede acceder a ella desde diferentes partes del programa. A esto se le llama ámbito o alcance de la variable.
A la variables creadas fuera de una función (en el código principal) se las considera variables de ámbito global, mientras que las variables que aparecen por primera vez dentro de una función se consideran de ámbito local.
Cuando una misma variable aparece en diferentes ámbitos locales (en diferentes funciones) o en el ámbito global (código principal), se le considerará variables diferentes. Desde un ámbito no pueden verse variables de otros ámbitos. Por ejemplo:
$a = 1; //Ámbito global
$b = 7;
function prueba()
{
$a = 5; //Ámbito local
//La variable $b no es visible aquí, es de otro ámbito.
}
prueba();
echo $a; //Mostrará 1 (ámbito global)
Si en la función anterior quisieras utilizar la variable $b del ámbito global en la función prueba() no podrías usarla externa (salvo que usaras global algo que no se recomienda y que se considera una mala práctica).
Ten en cuenta además que en PHP se pueden crear funciones dentro de funciones y cada función tendrá su propio ámbito independiente:
function a()
{
$a=3;
function b()
{
echo $a??'NO EXISTE';
}
b();
}
a(); //Mostrará NO EXISTE
Las variables locales a una función desparecen cuando acaba la función y su valor se pierde. Si quisieras mantener el valor de una variable local entre distintas llamadas a la función, deberás declarar la variable como estática utilizando la palabra static:
Las variables estáticas deben inicializarse en la misma sentencia en que se declaran como estáticas. De esta forma, se inicializan sólo la primera vez que se llama a la función.
Por otro lado, es importante que sepas que las funciones anónimas, también llamadas closures y cierres, permiten desde PHP 7.4 hacer uso de variables declaradas en un ámbito inmediatamente superior. Esto es sumamente útil en muchos momentos y tiene una sintaxis muy sencilla:
<?php
$etiqueta='STRONG';
$envolver = function ($texto) use ($etiqueta) {
echo "<$etiqueta>$texto</$etiqueta>";
};
$envolver('ejemplo'); //mostrará <STRONG>ejemplo</STRONG>
Dentro de la sección use ($etiqueta) se ha especificado que se hará uso de una variable del ámbito superior. Si es necesario usar más de una variable se pondrán separadas por comas. Además, puedes pasar la variable en cuestión por referencia (use (&$etiqueta)), lo que permite incluso modificarla o adaptarse a cambios en su valor:
$etiqueta='STRONG';
$envolver = function ($texto) use (&$etiqueta) {
echo "<$etiqueta>$texto</$etiqueta>";
};
$envolver('ejemplo'); //mostrará <STRONG>ejemplo</STRONG>
$etiqueta='EM';
$envolver('ejemplo'); //mostrará <EM>ejemplo</EM>
Por último, en PHP existen las conocidas funciones flecha. Son funciones que están destinadas a hacer cálculos breves que serán retornados de forma inmediata. Su sintaxis es muy sencilla:
fn (... argumentos ...) => ... expresión a retornar ....
donde fn es una palabra reservada (y no el nombre de la función). Las funciones flecha de PHP pueden usar variables de un ámbito superior sin especificarlo. En el siguiente ejemplo la función creada es similar a la vista en los ejemplos anteriores:
Carlos ha tenido que combinar varios arrays bidimensionales, lo cual le ha resultado muy difícil. Por eso, Carlos, que no tiene toda la experiencia que le gustaría en PHP, ha pedido a Juan que le eche un vistazo a su código por si ve algún error. Juan ve que podría hacer su código más sencillo si aplicara algunas funciones de PHP para manejar arrays:
- Oye, Juan, ¿puedes revisar el código PHP que hice? Tuve que combinar varios arrays bidimensionales y fue bastante complicado. No estoy seguro de si lo hice bien. - pregunta Carlos.
- Claro, Carlos. Déjame echarle un vistazo. - contesta Juan.
Juan se toma un tiempo revisando el código y contesta:
- Veo lo que has hecho. No está mal, pero creo que podrías simplificar bastante tu código usando algunas funciones de PHP para manejar arrays.
- ¿En serio? ¿Qué funciones podría usar?
- Por ejemplo, podrías usar array_merge para combinar arrays sin tener que escribir tanto código. También array_map puede ser muy útil para aplicar una función a cada elemento de los arrays.
- ¡No conocía esas funciones! ¿Podrías mostrarme cómo usarlas en mi código?
- Por supuesto. Mira, en lugar de hacer todo manualmente, podrías hacer algo así...
Juan le muestra a Carlos cómo reescribir una parte del código usando array_merge y array_map.
- ¡Wow! Eso hace que el código sea mucho más limpio y fácil de entender. Gracias, Juan. - dice Carlos.
- De nada, Carlos. Aprender estas funciones te ahorrará mucho tiempo y esfuerzo en el futuro. ¡Sigue practicando! - contesta Juan.
Esta función permite crear un array asociativo partiendo de variables existentes. Es la operación contraria a list y normalmente se le denomina "empaquetado".
Observa que se le proporciona el nombre de cada variable entre comillas sin indicar el símbolo $.
Otro grupo importante de funciones son aquellas que nos permiten usar los arrays como estructuras de pila (el último que entra es el primero que sale) y cola (el primero que entra es el primero que sale):
Funciones para usar arrays como pilas y colas
Función
Descripción
Ejemplo
Función array_push(&$array, $value)
Permite agregar uno o más elementos al final de array.
Cuando es necesario que un array tenga un número específico de elementos y dicho array tiene menos, podemos completar el array agregando elementos con array_pad. El parámetro $tam sería el tamaño de array deseado y $elem el elemento a agregar.
$array = ['Lunes', 'Martes', 'Miércoles'];
$ultimo = array_pop($array);
// $array ahora es ['Lunes', 'Martes']
// y $ultimo es 'Miércoles'
Función $array=array_fill($inicio,$tam,$valor)
Crea un array indexado de tamaño $tam relleno del valor especificado ($valor) empezando el contador de posición en $inicio.
Otras funciones importantes son las que permiten comprobar extraer y buscar claves y valores de un array:
Funciones para buscar y extraer claves y valores de un array
Función
Descripción
Ejemplo
Función in_array($valor, $array, $estricto=false)
Permite comprobar si un valor ($valor) está dentro de un array ($array). Permite indicar si se hace una comprobación estricta (valor y tipo) o no (solo valor realizando conversión automática de tipos).
Retornará true si se encuentra el valor o false si no se encuentra.
Busca la posición de un valor ($valor) dentro de un array ($array). Permite indicar si se hace una comprobación estricta (valor y tipo) o no (solo valor realizando conversión automática de tipos).
Retornará el índice o clave de la posición del valor buscado, o false si no se encuentra.
$array = ['Lunes', 'Martes', 'Miércoles'];
$primero = array_shift($array);
// $primero es 'Lunes'
// y $array ahora es ['Martes', 'Miércoles']
Función array_key_exists($clave, $array)
Permite comprobar si un array tiene una clave concreta. Retornará true si se encuentra la clave o false si no se encuentra.
Esta función obtiene un array con los valores del array proporcionado ignorando las claves o índices numéricos que pudiera haber. El array retornando tendrá los índices reindexados de cero en adelante.
En este apartado veremos funciones que nos van a permitir transformar un array de golpe. En PHP, y en otros lenguajes, es especialmente útil el uso de algunas funciones que nos van permitir aplicar una función a cada elemento del array sin la necesidad de implementar un bucle para ello. El objetivo de estas funciones suele ser:
recorrer un array y aplicar a cada elemento una función (uso de array_walk)
generar un nuevo array partiendo de uno o más arrays originales (uso de array_map y array_filter)
reducir un array a un solo valor aplicando (uso de array_reduce).
Uso de array_walk
Con array_walk se aplica una función a cada elemento del array. La sintaxis es la siguiente:
Como puedes ver, el array que se recorrerá se pasa como referencia, por lo que es posible modificarlo. Como segundo argumento, se necesita una función que procesará cada elemento y opcionalmente modificará cada elemento, y por último, podemos especificar algunos datos a pasar a la función.
En los siguientes ejemplos se visualiza dos formas en la que podemos proporcionar la función que modificará cada elemento del array (en el segundo caso se proporciona una función anónima):
No es necesario modificar los elementos, a veces, simplemente se recorren para mostrarlos:
$array = [1, 2, 3, 4];
function mostrar ($elemento, $clave, $elem) {
echo "<{$elem[0]} class='{$elem[1]}'> La clave o indice "
.htmlentities($clave)
." tiene el valor "
.htmlentities($elemento)
."</{$elem[0]}>";
};
echo '<ul>';
array_walk($array, 'mostrar', ['li','destacado']);
echo '</ul>';
Fíjate que en el ejemplo anterior, cuando necesitamos pasar más de un argumento a la función que se ejecutará para cada elemento, lo que hacemos es utilizar un array. El código anterior generará un código HTML como el siguiente:
<ul>
<li class='destacado'> La clave o indice 0 tiene el valor 1</li>
<li class='destacado'> La clave o indice 1 tiene el valor 2</li>
<li class='destacado'> La clave o indice 2 tiene el valor 3</li>
<li class='destacado'> La clave o indice 3 tiene el valor 4</li>
</ul>
Uso de array_map
Esta función recorre el array original elemento a elemento aplicando una función (como array_walk) pero siempre genera un array nuevo con el resultado. Es decir, la función que e aplica a cada elemento debe retornar el nuevo valor. La firma de la función es la siguiente:
En primer lugar, se proporciona la función que generará el nuevo elemento y en segundo lugar todos los arrays a utilizar, los cuales deberían de ser todos de la misma longitud. Veamos dos ejemplos de uso:
Ejemplo 1) Generar un array con el doble de cada elemento:
En el ejemplo anterior $elemento1 y $elemento2 irán tomando elementos de $array1 y $array2 de forma sucesiva.
Uso de array_filter
La función array_filter está pensada para generar un array con solo aquellos elementos que pasen un cribado o filtrado, es decir, permite quedarnos solo con aquellos elementos del array que cumplan con alguna condición concreta. La sintaxis de esta función es la siguiente:
En primer lugar, recibe el array sobre el que se aplicará el filtrado, en segundo lugar la función filtro que determinará si cada elemento es aceptado o no, y en tercer lugar, opcionalmente, si la función filtro recibirá solo el valor de cada elemento (opción por defecto), si recibirá tanto el valor como la clave de cada elemento del array (ARRAY_FILTER_USE_BOTH) o si recibirá solo la clave (ARRAY_FILTER_USE_KEY).
La función filtro deberá retornar true si el elemento debe ser incluido o false en caso contrario. Veamos dos ejemplos de uso:
La función array_reduce está pensada, como su nombre dice, para reducir un array a un solo valor. Por ejemplo: obtener el mínimo de un array, el máximo, la suma de todos los elementos, el producto de todos los elementos, la cadena de texto más corta, los números pares, etc.
Como puedes observar la función admite en primer lugar un array (que no se modificará), en segundo lugar la función que calculará el resumen resultado de la reducción y en tercer lugar el valor inicial usado para la reducción (que por defecto será null).
La función reductora a invocar deberá tener dos argumentos: reductor(mixed $acumulado, mixed $valor): mixed
$acumulado: Será el valor que se vaya arrastrando al aplicar iterativamente la función a cada elemento del array, es decir, el valor acumulado de operación a operación.
$valor: será cada elemento del array.
Esta función deberá retornar el valor acumulado para la siguiente operación. Veamos un ejemplo de uso:
$array = [1, 2, 3, 4];
function sumar($acumulado, $numeroDelArray) {
return $acumulado + $numeroDelArray;
}
$total = array_reduce($array, 'sumar', 0);
echo "La suma es $total"; //Mostrará "La suma es 10"
Nota: para el caso anterior existe la función array_sum que hace exactamente lo mismo. También existen funciones como min (obtener el mínimo de un array), max (obtener el máximo de un array) o array_product (multiplicar todos los elementos de un array entre sí).
Por último, y no menos importantes, a continuación tienes algunas funciones de transformación de arrays sumamente interesantes:
Funciones para manejar la estructura del array
Función
Descripción
Ejemplo
Función$f=array_flip ($array)
Esta función genera un array con los valores y claves del array intercambiados.
Esta función genera un nuevo array donde se casan las claves y valores de los arrays proporcionados.
$claves=['a','b','c'];$valores=[1,2,3];$c= array_combine($claves,$valores);//$c es ['a'=>1,'b'=>2,'c'=>3]
Función$ac=array_column($array,$columna)
Esta función es útil cuando tenemos arrays bidimensionales (los elementos de cada array son a su vez arrays). Nos permite extraer los datos de una clave como si se tratase de una tabla de una hoja de cálculo.
Opcionalmente, como tercer argumento, se puede indicar una columna del array que haga las veces de clave de la columna extraída.
Como ya hemos comentado en apartados anteriores, en PHP los arrays son, de lejos, las estructuras más utilizadas. PHP tiene un conjunto de funciones destinadas a tratar los arrays como conjuntos, y sobre ellos, poder hacer las típicas operaciones de unión, intersección y diferencia de conjuntos.
Estas operaciones son tremendamente útiles y te pueden ahorrar muchísimo trabajo en determinados momentos:
Unión de arrays
La operación de unión de arrays en PHP se puede realizar utilizando el operador + y también con la función array_merge, con notables diferencias entre una forma y la otra.
El operador + sobre arrays combina las claves de dos o más arrays y mantiene los valores de los elementos del primer array en caso de que alguna clave esté repetida. Esto quiere decir que no genera en realidad un array con la unión de todos los valores, sino con la unión de las claves:
El funcionamiento de la suma de arrays es por tanto peculiar. Al unir dos arrays con el operador + solo se tienen en cuenta los elementos del segundo array con índices o claves que no existan previamente en el primer array. Su uso en arrays indexados arroja posiblemente un resultado diferente a lo que nos gustaría:
En el ejemplo anterior, el primer array tiene los índices [0=>1, 1=>1, 2=>3] y el segundo los índices [0=>3, 1=>4, 2 => 3, 3 => 6]. El único índice que no existe en el primer array es el índice [3] y es el lo que se agrega al segundo array, generando [0 => 1, 1 => 2, 2 => 3, 3 => 6].
Cuando se usa array_merge la situación es muy diferente. Con arrays asociativos se comporta como la operación suma (+) de arrays pero preservando el valor en el segundo array en caso de claves repetidas (y no el del primer array), y con arrays indexados se comporta como la unión de valores (repitiendo incluso los que aparezcan en ambos arraysveces):
<?php
$array1 = ['a' => 'Lunes', 'b' => 'Miércoles'];
$array2 = ['b' => 'Martes', 'c' => 'Jueves'];
$result = array_merge($array1, $array2);
print_r($result);
/*
Muestra [a] => Lunes, [b] => Martes, [c] => Jueves
Fíjate que [b] conserva el valor del segundo array ("Martes")
y no el del primer array ("Miércoles")*/
<?php
$array1=[1,2,3]; //Indices: 0, 1 y 2
$array2=[3,4,5,6]; // Indices: 0, 1, 2 y 3
$result=array_merge($array1, $array2);
print_r($result);
/*Muestra:
[0] => 1, [1] => 2, [2] => 3, [3] => 3,
[4] => 4, [5] => 5, [6] => 6
Fíjate que el 3 está dos veces por estar en ambos arrays
*/
Intersección de arrays
La operación intersección nos permitirá obtener los elementos comunes de varios arrays. Para ello, PHP nos ofrece varias funciones:
Uso de array_intersect
Esta función devuelve un array que contiene todos los valores del primer array que están presentes en todos los demás arrays.
En este ejemplo, 'c' es el único valor presente en los tres arrays.
Uso de array_intersect_key
Esta función devuelve un array que contiene todas las claves del primer array que están presentes en todos los demás arrays, preservando solo los valores del primer array para las claves comunes:
En este ejemplo, las claves 'a' y 'b' están presentes en los tres arrays. Es importante que observes que se preservan los valores del primer array en el resultado de la intersección, descartando el resto.
Uso de array_intersect_assoc
Esta función devuelve un array que contiene todos los valores del primer array que están presentes en todos los demás arrays pero dónde además las claves también coinciden. Es decir, genera un array donde se retornan todas las parejas clave/valor coincidentes. En el siguiente ejemplo hay dos claves y valores que coinciden en los dos arrays:
En este ejemplo, la clave 'a' está presente en $array1 pero no en $array2.
Uso de array_diff_assoc
Esta función devuelve un array que contiene todos los valores del primer array que no están presentes en ningún otro array, pero dónde además las claves también coinciden. Es decir, genera un array donde se retornan todas las parejas clave/valor del primer array que no están en los otros arrays. En el siguiente ejemplo hay una clave y valor que coinciden en los dos arrays:
En este ejemplo, las parejas 'b' => 2 y 'c' => 3 de $array1 no están presentes en $array2 con las mismas claves y valores. La clave b está en ambos arrays, pero observa que tienen valores diferentes en ambos arrays.
La afirmación anterior es falsa, no es correcta. La función array_intersect_assoc compara tanto claves como valores para realizar la intersección, no tiene nada que ver con que sean arrays asociativos o indexados.
Carlos está viendo que el esfuerzo que le dedica al aprendizaje del nuevo lenguaje empieza a dar sus frutos. Hace unos días casi no sabía ni que existía PHP, y ahora ya es capaz de realizar programas sencillos por sí mismo.
Para poder avanzar aún más, sabe cuál ha de ser su siguiente paso: obtener y utilizar información de un usuario. De esta forma, los programas que haga no serán lineales, sino que tendrán un comportamiento u otro en función de los datos que aporte el usuario.
Como le ha comentado Juan, para obtener información de un usuario, en PHP se utilizan los formularios HTML. ¡A por ellos!
Cuando desarrollamos una aplicación web esta no se ejecuta de forma aislada, sino que se produce una interacción con el usuario final. Esto implica que nuestra aplicación, igual que envía documentos HTML y otros tipos de datos al navegador a través del protocolo HTTP, recibirá del navegador datos que son fruto de la interacción con el usuario. Además de esos datos que recibe de la interacción del usuario con el navegador, puede recibir también datos de otras fuentes. Vamos a revisar de forma general cuales son estas fuentes de datos:
Usuario final. El usuario final será, en la mayor parte de los casos, el origen de los datos que manejará nuestra aplicación. Estos datos pueden venir de varias formas:
Parámetros de URL o de ruta. Es común encontrar en la misma URL datos que usará nuestra aplicación web y que condicionarán su comportamiento. Por ejemplo: http:\\localhost\index.php?dato1=test; en el caso anterior hay una ruta que contiene un parámetro de ruta, llamado dato1.
Formularios web. En general, cuando un usuario envía un formulario al servidor web los datos de dicho formulario son enviados en el cuerpo de la petición HTTP. PHP permite procesar estos datosde forma cómoda y sencilla.
Cookies. Las cookies son datos que almacena el navegador temporalmente y que vuelve a enviar al servidor web en cada petición HTTP mientras la cookie no caduque. La gestión de cookie se verá en futuras unidades.
Archivos. Es común que nuestra aplicación tenga que acceder a archivos para diferentes propósitos. El más común es proveer de información de configuración de la aplicación web.
Bases de datos y otros servicios.
En este apartado nos vamos a centrar en lo que denominamos parámetros de URL o ruta y en los formularios web.
En esta unidad no vamos a explicar como trabajar con archivos en PHP, pero en realidad se trata simplemente de usar el conjunto de funciones que tiene PHP para ello. El uso de funciones en si es uno de los aspectos que debes dominar, así como la utilización de documentación oficial. El el siguiente enlace puedes ver más información sobre como manejar archivos de PHP:
Una URL está dividida en varios segmentos, el que nos interesa ahora son los parámetros (parameters). Una de las forma más habituales en las que se reciben datos en una aplicación web PHP es a través parámetros de URL. Por ejemplo:
En el ejemplo anterior el fragmento de texto de la URL siguiente contiene los parámetros de ruta: ?parametro1=ejemplo1¶metro2=ejemplo2. La cantidad de información que podemos incluir en la URL a través de este mecanismo es limitada, depende del navegador en sí y del servidor web donde se despliega la aplicación web. Normalmente, puedes contar con aproximadamente unos 2000 caracteres.
Tal y como deducirás, en el ejemplo anterior hay embebidos en la ruta 2 parámetros (parametro1 y parametro2) con sus respectivos valores (ejemplo1 y ejemplo2). En PHP la información recibida en dichos parámetros de ruta es accesible a través del array asociativo $_GET. Esta forma de acceso es independiente del método empleado en la petición HTTP. Esto quiere decir que en peticiones HTTP tipo POST puede haber parámetros de ruta que también pueden ser recogidos a través del array $_GET.
El valor de cada parámetro es accesible de la forma siguiente $_GET['parametro1'], sin embargo, antes de acceder a cada uno de los datos tenemos que tener en cuenta que las claves correspondientes a cada uno de los parámetros (parametro1 y parametro2 en el ejemplo) pueden no existir. Por lo que es necesario verificar su existencia antes de usar los datos o proporcionar un valor por defecto en función de las exigencias del programa:
<?php
//URI de ejemplo: http://ejemplo.juntadeandalucia.es/pagina.php?parametro1=ejemplo1¶metro2=ejemplo2
if (isset($_GET['parametro1']) //Comprobamos que existe el key en el array asociativo
{
echo $_GET['parametro1'];
}
echo $_GET['parametro2']??'No existe'; /*Usamos el operador de coalescencia nula para usar un valor por defecto en caso de que no exista */
Si en un script necesitamos obtener la ruta completa indicada en la petición HTTP (incluidos parámetros de ruta) podrías utilizar $_SERVER['REQUEST_URI']. Por ejemplo, si para acceder a un script PHP se usa la ruta: http://localhost/ejemplo1/pagina.php?a=1&b=2, y dentro de ese script escribes echo $_SERVER['REQUEST_URI'];, se mostrará: /ejemplo1/pagina.php?a=1&b=2.
Por otro lado, es importante que sepas que en una URL hay ciertos caracteres que tienen un significado especial y que no pueden usarse directamente como nombre de parámetro ni como su valor. Por ejemplo, el mismo símbolo & usado para separar dos parámetros de ruta, o el símbolo igual (=), entre otros muchos. Para poder incluir ese tipo de caracteres no permitidos en la URL es necesario codificarlos siguiendo lo que llamamos percent encoding o URL encoding.
Es por ello que cuando necesitamos componer una URL desde nuestro código PHP necesitamos funciones especiales de PHP para generar la URL adecuadamente: urlencode y http_build_query. Veamos ejemplos de uso:
$variable='valor&de=la%variable';
$datoCodificado=urlencode($variable);
echo "<a href='destino.php?dato=$datoCodificado'>Enlace con datos en URL</a>";
El resultado que se mostraría sería algo como lo siguiente:
<a href='destino.php?dato=valor%26de%3Dla%25variable'>Enlace con datos en URL</a>
La función urlencode es normal usarla cuando tienes que encapsular un parámetro o dos a lo sumo en la URL. Sin embargo, cuando tienes que encapsular múltiples parámetros en la URL es mejor usar la función http_build_query. Veamos un ejemplo de uso:
$datosUrl['dato1']='valor&1';
$datosUrl['dato2']='valor=2';
$datosUrl['dato3']='valor\'3';
$datosUrl['dato4']='valor"4';
$queryString=http_build_query($datosUrl);
echo "<a href='destino.php?$queryString'>Enlace con datos en URL</a>";
El resultado que se mostraría sería algo como lo siguiente:
<a href='destino.php?dato1=valor%261&dato2=valor%3D2&dato3=valor%273&dato4=valor%224'>Enlace con datos en URL</a>
Por último, es importante que sepas que, aunque los datos en la URL vayan codificados usando percent encoding no es necesario aplicar la operación inversa (urldecode) sobre los mismos en tu script PHP, dado que PHP al generar el array $_GET ya realizará la decodificación de los datos de forma automática por nosotros. La función urlencode es para usarla en otros contextos (por ejemplo cuando se procesa a mano el contenido de $_SERVER['REQUEST_URI']).
Si quieres conocer con más detalle las partes de una URL y el esquema que siguen, no dudes en visitar la siguiente página de la documentación oficial de Mozilla:
Otra de las formas en las que nuestra aplicación web recibirá datos externos es a través de formularios que embebemos en las páginas web.
Los formularios HTML van encerrados siempre entre las etiquetas <<strong>FORM</strong>> </<strong>FORM</strong>>. Dentro de un formulario se incluyen los elementos sobre los que puede actuar el usuario, principalmente usando las etiquetas <INPUT>, <SELECT>, <OPTION>, <TEXTAREA> y <BUTTON>.
Un ejemplo muy simplificado puede ser el siguiente:
En el formulario anterior caben destacar los siguientes aspectos:
Se indica el recurso del servidor al que se enviarán los datos (en este caso nuestro script PHP). En el caso del ejemplo el destino de los datos es: action="ejemplo.php".
Se indica el método HTTP con el que el navegador enviará los datos que el usuario ha rellenado al servidor web:
Método de envío HTTP POST. Es el caso del ejemplo anterior y se indica añadiendo a la etiqueta form lo siguiente method="post". Los datos en este caso irán codificados en el cuerpo de la petición HTTP. Este mecanismo permite enviar gran cantidad de datos al servidor.
Método de envío HTTP GET. Se indica añadiendo method="get" a la etiqueta form. En este caso los datos que el usuario ha rellenado se envían como parámetros de ruta o de URL, por ejemplo: destino.php?nombre=datoindicadoporelusuario. Este método hace que los datos enviados sean visibles en la URL, lo cual la mayor parte de las veces no es deseable, y además, tiene un tamaño limitado que puede variar y que suele ser de 2000 caracteres.
Cuando el método es POST (method="post"), se puede indicar la forma en la que el navegador codificará los datos en el cuerpo del mensaje:
Codificación <span>application/x-www-form-urlencoded</span>. Esta es la codificación por defecto cuando se usa el método POST (method="post"). En este caso los datos se envían en el cuerpo del mensaje codificados usando percent encoding o URL encoding. No es obligatorio indicarlo, pero si se desea se puede poner a través de del atributo enctype : enctype="<span>application/x-www-form-urlencoded</span>".
Codificación multipart/form-data. A diferencia de la codificación <span>x-www-form-urlencoded</span>, la codificación multipart tiene una estructura que permite enviar tanto texto plano como datos binarios, con lo que es común su utilización para enviar archivos desde el navegador al servidor.
En la siguiente imagen puede observarse como se produce el intercambio de datos entre cliente y servidor usando el método POST (method="post") y la codificación <span>application/x-www-form-urlencoded</span>:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Es importante destacar los siguientes aspectos:
El navegador recibirá un formulario donde se indicará el método en el que se tienen que retornar los datos al servidor (method="post").
El usuario rellenará los datos del formulario.
El navegador, al enviar los datos del formulario encapsulará los datos en el cuerpo del mensaje HTTP.
A continuación veamos como sería esa misma comunicación usando el método GET para enviar el formulario:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Veamos las peculiaridades de este ejemplo:
En este segundo ejemplo en el formulario se indica explicitamente que se usará el método GET (method="get").
El usuario rellena los datos igual que en el formulario anterior.
Los datos se envían como parte de la URL (/ejemplo.php?nombre=ABCD&apellido=12345&edad=30), lo que hace dichos datos visibles en la barra del navegador.
El atributo action del formulario se puede dejar vacío (<form action="" method="POST">). En ese caso el "destinatario" de los datos del formulario será la misma URL que mostró el formulario.
Por ejemplo, si el formulario se mostró con la URL http://www.juntadeandalucia.es/formulario.php y si no se indica nada en el action, los datos se recibirán en el mismo script que los generó (/formulario.php).
Ese código hace el mismo efecto que usar $_SERVER['PHP_SELF'] como destino de los datos:
En el caso anterior el script que recibirá los datos también será el script que generó el formulario en primera instancia. Tienes que tenerlo en cuenta, dado que es muy común que un script en PHP muestre un formulario y que también sea el encargado de procesarlos.
Para no tener problemas al programar en PHP, debes conocer el lenguaje HTML, concretamente los detalles relativos a la creación de formularios web. Puedes consultar esta información por ejemplo en la documentación oficial de Mozilla:
El objetivo de esta sección es que sepas diseñar formularios de forma adecuada para luego poder procesar los datos adecuadamente en PHP.
Antes de continuar tienes que saber como recoger los datos recibidos vía POST. Si recuerdas de apartados anteriores, indicábamos que los datos encapsulados en la URL con la codificación percent encoding (conocidos como parámetros de ruta) se podían recoger en el array $_GET.
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
De forma similar, PHP encapsulará los datos recibidos vía POST (tanto para la codificación application/x-www-form-urlencoded como para la codificación multipart/dataform) en un array asociativo superglobal llamado $_POST.
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Tal y como enviará el navegador los datos al servidor, la clave del array asociativo $_POST coincidirá con el valor del atributo name de cada campo del formulario. Esto quiere decir que un campo en el formulario con el código HTML <INPUT type="text" name="nombre"> cuando se reciba en PHP podrá ser accesible a través de $_POST['nombre'].
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Nuevamente, al igual que ocurría con los datos recibidos en la URL (parámetros de ruta), antes de usar los datos recibidos vía POST deben verificarse su existencia de forma adecuada:
Formas de verificar la existencia de datos en $_POST
Opción 1) Facilitar un valor por defecto
//Por defecto $nombre será null
$nombre=$_POST['nombre']??null;
if ($nombre!==null)
{
echo "El nombre es $nombre";
}
else
{
echo 'No se ha especificado el nombre';
}
Opción 2) Verificar que existe el dato con isset o similar.
if (isset($_POST['nombre']))
{
echo "El nombre es {$_POST['nombre']}";
}
else
{
echo 'No se ha especificado el nombre';
}
Opción 3) Verificar que existe la clave en el array asociativo $_POST.
if (array_key_exists('nombre',$_POST))
{
echo "El nombre es {$_POST['nombre']}";
}
else
{
echo 'No se ha especificado el nombre';
}
En PHP existe el array asociativo super global llamado $_REQUEST. Este array contiene por defecto los datos recibidos en $_GET, $_POST y también las cookies (que se verán en unidades posteriores). Si por ejemplo existe $_GET['nombre'], también existirá $_REQUEST['nombre'].
Sin embargo su uso está desaconsejado por lo siguientes motivos:
El contenido de este array puede ser configurado en php.ini por lo que es aconsejable no utilizarlo (puede que en el servidor donde se despliegue la aplicación web no esté configurado como se ha configurado en el servidor de desarrollo).
Si en $_GET y en $_POST existen parámetros que comparten nombre, uno de los dos se pierde. Por ejemplo, si existe $_GET['nombre'] y $_POST['nombre'], uno de los dos se perderá en función de la configuración del archivo php.ini.
Es rotundamente FALSO. No es suficiente con realizar dicha comprobación, dado que con esa comprobación solo puedes saber el tipo de petición HTTP que ha realizado el navegador, pero no se puede garantizar que se han enviado todos los datos esperados.
En general, los elementos de entrada de los formularios, salvo excepciones que veremos, permiten insertar solo un dato. El caso más representativo son los campos para entrada de texto.
Los campos para entrada de texto son los que admiten datos de tipo alfanumérico. Esto comprende a campos tipo text, pero también a campos con tipo date, datetime, email, tel, password, etc. Su uso es como hemos visto en apartados anteriores. En la siguientes tablas puedes observar como podría ser un formulario (izquierda) y como recoger dichos datos:
Campos de formulario para introducción de texto
Ejemplo de formulario (archivo ejemplo.html)
Ejemplo de procesado de datos en PHP (ejemplo.php)
<?php
if (isset($_POST['descripcion'])) { echo $_POST['descripcion'].'<BR>'; }
Los campos tipo range, color, month, week, date y similares, en realidad son de tipo texto, simplemente el navegador muestra una interfaz más amigable al usuario para rellenar los datos.
Es importante que sepas que, aunque el tipo de dato pueda especificarse en el HTML (por ejemplo, <input type="number" name="edad" min="1" max="99">) los datos se reciben siempre en nuestro script PHP como texto. Además, debes saber que es muy sencillo eliminar la restricción impuesta de tipo en el formulario ( type="number" en el ejemplo anterior) y enviar datos saltándose las restricciones el navegador, por lo que nunca debes confiar en los datos recibidos.
Otro tipo de elementos de formulario que suelen encontrarse, a diferencia de los anteriores, son los de elección múltiple. Es decir, se ofrecen varias opciones y el usuario puede elegir solo una opción entre todas las disponibles. Los casos más característicos son: botones tipo radio y desplegables tipo select multiple . Veamos como sería su uso:
Campos de formulario para elección múltiple
Ejemplo de formulario (archivo ejemplo.html)
Ejemplo visual del formulario
Ejemplo de procesado de datos en PHP (ejemplo.php)
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
<?php
define('OPCIONES', [1, 0, -1]);
if (isset($_POST['voto']))
{
if (in_array($_POST['voto'],OPCIONES))
{
echo "Se ha recibido {$_POST['voto']}";
}
else
{
echo 'El voto no tiene un valor válido';
}
}
else
{
echo 'El dato no se ha recibido';
}
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Como puedes observar, el tratamiento en el caso de campos tipo radio y campos tipo select el procesamiento es el mismo. Los datos recibidos deberían tener un conjunto limitado de valores, por lo que cualquier valor fuera de los valores permitidos se consideraría erróneo. En el ejemplo se coteja el dato recibido con los valores posibles que puede tener, cualquier valor recibido fuera de los esperados se considera erróneo. Este tipo de verificaciones es necesaria puesto que modificar los formularios en el navegador es sumamente sencillo.
Otro tipo de campos muy comunes son los campos de selección múltiple. En este tipo de campos, a diferencia de los anteriores, al usuario se le ofrecen varias opciones y el usuario puede seleccionar múltiples opciones entre todas las disponibles. Los casos más característicos son: botones tipo checkbox y desplegables tipo select multiple.
A diferencia de un campo normal, los campos múltiples envían varios datos asociados a un mismo parámetro, lo que se transforma transformará en un array de datos en PHP. Es por ello que se indica el nombre de la variable agregando unas llaves al final name="colores[]". Veamos un par de ejemplos:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
En ambos casos, el dato recibido se tratará en PHP como un array. Esto quiere decir que se recibirá un dato como el siguiente $_POST['colores'] que será un array de cadenas. En el ejemplo anterior el array recibido en $_POST['colores'] podría ser ['blue','green','pink'] si se seleccionan las opciones "Azul", "Verde" y "Rosa". Veamos un ejemplo general de como tratar dichos datos:
$colores_permitidos = ['red', 'blue', 'yellow', 'green', 'orange', 'pink'];
if (isset($_POST['colores']) && is_array($_POST['colores']))
{
if (empty(array_diff($_POST['colores'], $colores_permitidos)))
{
echo 'Los colores recibidos están dentro de los esperados y son: '.implode(', ',$_POST['colores']);
}
else
{
echo 'Se han recibido colores no esperados';
}
}
else
{
echo 'No se han recibido los colores o no es del tipo esperado.';
}
La función array_diff en este caso genera un array nuevo con los elementos resultantes de eliminar del primer array los elementos del segundo. Al hacer esta operación sobre el array recibido ($_POST['colores']) y sobre el array que contiene los valores posibles ($colores_permitidos) debería salir un array con cero elementos, si no sale un array con cero elementos es porque hay valores no esperados.
Permitir que un usuario suba archivos a nuestra aplicación web a través de un formulario es siempre una acción peligrosa y delicada, aunque también es un procedimiento muy habitual. Vamos a revisar como se podría programar esta acción.
En primer lugar, necesitamos revisar la configuración de PHP para que sea posible subir archivos. Para ello deberíamos revisar el archivo php.ini y verificar ciertas directivas:
; Activación de la caracteristica de subir archivos (on=activo - off=inactivo)
file_uploads = on
; Número máximo de archivos que se pueden subir a la vez por petición HTTP
max_file_uploads = 4
; Tamaño máximo de los archivos que se pueden subir
upload_max_filesize = "2M"
Una vez estemos seguros de que nuestro PHP permite subir archivos, el siguiente paso es proveer de un formulario a través del cual se puedan subir archivos. Esto se realiza con un formulario como el siguiente:
En el formulario anterior hay varias cosas importantes que tienes que tener en cuenta:
El método HTTP a utilizar debe ser siempre POST (method="post") y la codificación siempre debe ser datos de formulario multiparte (enctype="multipart/form-data").
El elemento HTML que permite subir archivo es un input tipo file (). El nombre del campo (name="archivo") se utilizará en PHP para poder acceder a los datos del archivo.
Es posible indicarle al navegador el tamaño máximo del archivo permitido ( <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
), sin embargo, esto no garantiza que el navegador vaya a restringir el tamaño. Además, un usuario puede saltarse con facilidad dicha restricción.
Visto lo anterior, veamos como sería ahora el archivo action="ejemplo.php" que recibiría los datos POST del formulario anterior. Para acceder a la información del archivo enviado deberíamos hacer uso del array `$_FILES`. Como el nombre del elemento anterior es `archivo` (<input type="file" name="archivo" id="">) en `$_FILES` aparecerá $_FILES['archivo'] que contendrá lo siguiente:
$_FILES['archivo']['name']: Nombre del archivo en el ordenador del usuario que lo envío. No suele ser un dato muy usado.
$_FILES['archivo']['type']: Tipo MIME que identifica al contenido del archivo según el navegador. El navegador enviará junto al archivo el tipo MIME que identifica el tipo de archivo enviado (por ejemplo, `image/jpeg' identifica una imagen). Este dato puede ser falseado por un usuario con facilidad, por lo que no es un dato confiable.
$_FILES['archivo']['size']: Tamaño en bytes del archivo subido.
$_FILES['archivo']['tmp_name']: Nombre temporal asignado al archivo. El archivo subido por el usuario no se almacena con su nombre real en el servidor, sino que se le da un nombre temporal y aleatorio. Usaremos este dato para acceder al archivo subido.
$_FILES['archivo']['error']: Errores que se hayan podido producir al subir el archivo. Existen una serie de constantes que pueden ser valor de ese campo, veamos las más relevantes:
UPLOAD_ERR_OK: no hay errores, por lo que el archivo se ha subido bien.
UPLOAD_ERR_NO_FILE: el archivo no se ha subido.
UPLOAD_ERR_PARTIAL: el archivo se ha subido parcialmente.
UPLOAD_ERR_INI_SIZE: el archivo excede el tamaño indicado en la directiva upload_max_filesize del archivo php.ini.
UPLOAD_ERR_CANT_WRITE: el archivo no se ha podido escribir en disco, generalmente por un problema de permisos del usuario con el que se ejecuta el servicio web.
UPLOAD_ERR_FORM_SIZE: el archivo supera el tamaño indicado en el campo hidden configurado en el formulario (por ejemplo: <input type="hidden" name="MAX_FILE_SIZE" value="30000" />). Insistir nuevamente en que este mecanismo es poco o nada fiable, dado que un usuario puede modificar dicho dato con facilidad en el navegador.
De los valores anteriores, los que realmente usaremos son: error (para verificar que efectivamente el archivo se ha subido), tmp_name (para acceder al archivo subido por el usuario) y size (para conocer el tamaño real del archivo subido por el usuario). Veamos un ejemplo de uso en un hipotético archivo ejemplo.php:
<?php
define('MAX_ARCHIVO_SIZE',20000);
//Comprobamos si se ha recibido el archivo
if (isset($_FILES['archivo'])) {
//Comprobamos que no ha habido ningún error
if ($_FILES['archivo']['error'] == UPLOAD_ERR_OK) {
//Comprobamos que no se ha superado el tamaño máximo
if ($_FILES['archivo']['size']>MAX_ARCHIVO_SIZE)
{
echo "El archivo ha superado el máximo permitido.";
}
//Comprobamos si el tipo del archivo es el esperado
elseif (!mime_content_type($_FILES['archivo']['tmp_name']!=='image/jpeg'))
{
echo "El tipo de archivo no es el esperado";
}
else
{
//Movemos el archivo a una ubicación donde no se borre.
$resultado = move_uploaded_file($_FILES['fichero_usuario']['tmp_name'], $newtmpname);
if ($resultado)
{
echo "Gracias por subir el archivo!";
}
}
}
}
En el código anterior hay dos aspectos relevantes, aparte del uso de los datos de $_FILES['archivo']. Son los siguientes:
Implementación de un mecanismo para identificar el tipo de archivo real que el usuario ha subido: mime_content_type($_FILES['archivo']['tmp_name']!=='image/jpeg'. A través de la función mime_content_type podemos identificar el tipo de archivo que el usuario ha subido. Ese método nos retornará el tipo MIME del archivo y nos permitirá tomar una acción si el tipo de archivo recibido no es el esperado.
Copiar el archivo recibido a una carpeta del sistema: move_uploaded_file($_FILES['fichero_usuario']['tmp_name'], $newtmpname). La función move_uploaded_file moverá el archivo subido a una nueva ubicación y con un nuevo nombre (indicado en $newtmpname). Esto es necesario para salvaguardar el archivo, dado que si no se copia el archivo temporal se eliminará tras la ejecución del script.
Las medidas anteriores son necesarias para garantizar un mínimo de seguridad (comprobar el tamaño y tipo reales del archivo), no obstante, son unas medidas mínimas, y posiblemente en un escenario real tengas que implementar medidas adicionales que permitan cerciorarte de que el archivo subido no es un archivo malicioso que pueda comprometer la aplicación web o el servidor, o los equipos de otros usuarios.
Los formularios en HTML permiten incluir lo que denominamos campos ocultos o hidden. Esto significa que el valor de estos campos no aparecerán en la interfaz de usuario pero si se recibirán en el PHP del servidor.
Los campos tipo hidden se suelen usar en diferentes contextos, pero siempre el objetivo es el mismo, propagar información necesaria para llevar a cabo un acción posterior. En los siguiente ejemplos puedes ver, por un lado, un formulario con un campo tipo hidden que envía un dato al script ejemplo.php y por otro el script que recibe el dato y que simplemente lo muestra. Si lo pruebas verás como el formulario no muestra el dato en el campo hidden, sin embargo, dicho dato si se recibe en el script ejemplo.php.
Ejemplo de formulario con un campo hidden
Los campos hidden tienen sentido cuando se utiliza el método POST, dado que si se utiliza el método GET el dato finalmente se va a ver en la URL. Utilizar un campo hidden es muy sencillo, simplemente indicamos hidden en el tipo del elemento input de HTML:
El uso de los valores de los campos hidden en PHP no varía con respecto de otros campos del formulario.
Es importante que tengas en cuenta que el hecho de que esos datos vayan "ocultos" no garantiza su recepción ni que sean inalterables, por lo que es necesario verificar siempre que son correctos y que se han recibido. Dado que son datos que se reciben desde el cliente, no tenemos control sobre posibles alteraciones de los formularios.
<?php
if (isset ($_POST['dato_oculto']))
{
echo "El dato oculto recibido es {$_POST['dato_oculto']}";
}
Imagina, por ejemplo, que estás diseñando una web donde los usuarios pueden hacer comentarios sobre los productos que están visualizando. Los usuarios pueden ver los detalles del producto al acceder a un script que has diseñado (llamado por ejemplo detalleproducto.php). En ese script, al poner el id de producto como parámetro de URL: detalleproducto.php?idproducto=298; el usuario puede ver los detalles del producto junto a un formulario para añadir un comentario:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Detalles del Producto</title>
</head>
<body>
<h1>Detalles del Producto</h1>
<?php
// Verificar si se ha proporcionado un ID de producto válido
if(isset($_GET['idproducto']) && is_numeric($_GET['idproducto'])) {
$id_producto = $_GET['idproducto'];
// Función que obtendría los detalles del producto
$detalles_producto = obtenerDetallesProducto($id_producto);
if($detalles_producto) {
echo "<h2>{$detalles_producto['nombre']}</h2>";
echo "<p>Precio: {$detalles_producto['precio']}</p>";
echo "<p>Descripción: {$detalles_producto['descripcion']}</p>";
// Formulario para añadir un comentario
echo "<h3>Añadir Comentario</h3>";
echo "<form action='procesar_comentario.php' method='POST'>";
echo "<input type='hidden' name='id_producto' value='{$id_producto}'>";
echo "<textarea name='comentario' rows='4' cols='50'></textarea><br>";
echo "<input type='submit' value='Enviar Comentario!!'>";
echo "</form>";
} else {
echo "<p>El producto no existe.</p>";
}
} else {
echo "<p>No se ha proporcionado un ID de producto válido.</p>";
}
?>
</body>
</html>
En el ejemplo anterior, el script de destino del formulario procesar_comentario.php va a necesitar, aparte del texto del comentario (campo <textarea name='comentario'...></textarea>), el identificador del producto con el que debe asociarse el comentario en cuestión. Para ese dato concreto, tal y como muestra el código de ejemplo, lo mejor es utilizar un campo oculto: <input type='hidden' name='id_producto' value='{$id_producto}'>, puesto que es información que necesitamos propagar de un script (detalleproducto.php) a otro (procesar_comentario.php) de forma transparente al usuario.
Nota: en el script anterior se utiliza una función llamada obtenerDetallesProducto que no está implementada. Es función generalmente obtendría los datos de una base de datos, algo que se verá en próximas unidades.
Como se ha indicado con anterioridad, no hay que confiar plenamente en los datos recibidos a través de campos hidden, dado que pueden ser modificados con facilidad en el cliente web. Por lo tanto, en un potencial script procesar_comentario.php que usara los datos anteriores, deberían tomarse las precauciones adecuadas para verificar que los datos recibidos en el campo oculto son correctos. Por ejemplo, en este caso concreto, deberíamos como mínimo verificar que id_producto es un entero y que efectivamente corresponde con un producto existente:
<?php
//Ejemplo de verificación de campo oculto en procesar_comentario.php
if(isset($_POST['id_producto']) && is_numeric($_POST['id_producto'])) {
$id_producto = intval($_POST['id_producto']);
if(productoExiste($id_producto)) {
//Verificar comentario y, si es correcto, añadir comentario al producto
}
}
Nota: en el script anterior la función productoExiste no está implementada. Por lo general buscaría si el identificador de producto existe realizando consultas a la base de datos.
Hasta ahora hay un hecho que posiblemente no te has planteado y que es sumamente importante. En una página web, ¿puedo mostrar cualquier texto? La verdad es que si, pero con precauciones. Vamos a plantear una serie de escenarios que te ayudarán a entender porqué hay que tener precaución.
Imagina que un usuario se ha puesto el nombre de usuario $nombre='<<JUAN>>'. ¿Sabes lo que ocurre cuando intentas mostrar la cadena anterior? Intenta ejecutar el siguiente código y ver como se visualiza en el navegador:
Habrás comprobado que muestra solo <>. Resulta que el navegador no va a mostrar bien el nombre porque interpreta que <JUAN> es una etiqueta HTML.
Imagina ahora, que estamos haciendo un formulario para editar el nombre de un producto, y que el nombre del producto es, por ejemplo: $nombreProducto='Memoria USB "SUPERRAPIDA"';. A alguien se le ha ocurrido poner unas comillas dentro del nombre del producto, ¿esto es problemático? La respuesta es SI. Esto, que puede ser de lo más normal del mundo, puede causar estragos si realizamos un formulario sin el cuidado adecuado:
Fíjate que en el formulario actual se indica: value="<?=$nombre_actual?>". Claro, la idea es que el usuario pueda modificar el valor existente eliminando o añadiendo lo que necesite. Sin embargo, el resultado es que no se mostrará adecuadamente, porque el código generado por PHP será el siguiente:
<input name="nombre" id="nombre" value="Memoria USB "SUPERRAPIDA"">
Y se visualizará así (no aparece parte del contenido del nombre del producto):
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
Estos casos son problemáticos porque afectan a la interfaz de usuario o a la edición de los datos, pero pueden haber casos mucho más graves y problemáticos, y que incluso puedan suponer un problema de seguridad. Por ejemplo, ¿qué pasa si un usuario introduce código Javascript en un formulario introduciendo <script>...</script>? Si hablamos de, por ejemplo, un comentario sobre un producto que otros usuarios también van a poder ver en sus navegadores, dicho comentario contendría código javascript que se ejecutaría en los navegadores de cualquiera que visitara la página... esto es un problema GRAVE.
Este y otros escenarios se pueden evitar tomando medidas de filtrado y saneado de datos (como se verán más adelante), y también aplicando una transformación a los datos antes de mostrarlos: cambiar los caracteres que tienen un significado en HTML a sus respectivas entidades HTML.
Por ejemplo, el símbolo < se puede mostrar en HTML usando la entidad HTML <. De esta forma, símbolos que podrían "romper la interfaz de usuario" y causar problemas graves, pueden evitarse. Para realizar esta transformación en PHP hay dos funciones fundamentales: htmlentities y htmlspecialchars.
Estas funciones sirven para lo mismo, aunque tienen una notable diferencia. htmlspecialchars solo convierte los caracteres especiales en entidades HTML, mientras que htmlentities convierte todos los caracteres aplicables a sus equivalentes en entidades HTML. Veamos un ejemplo:
Ejemplos de aplicación de las funciones htmlspecialchars y htmlentities
Ejemplo de código con transformación de entidades HTML
Ejemplo de salida
<?php
//...resto de código
$nombre_actual='¡¡Memoria USB "SUPERRÁPIDA"!!';
?>
...
<input name="nombre" id="nombre"
value="<?=htmlspecialchars($nombre_actual);?>">
...
...
<input name="nombre" id="nombre"
value="¡¡Memoria USB "SUPERRÁPIDA"!!">
...
<?php
//...resto de código
$nombre_actual='¡¡Memoria USB "SUPERRÁPIDA"!!';
?>
...
<input name="nombre" id="nombre"
value="<?=htmlentities($nombre_actual);?>">
...
...
<input name="nombre" id="nombre"
value="¡¡Memoria USB "SUPERRÁPIDA"!!">
...
IMPORTANTE: aunque se haga uso de htmlentities y htmlspecialchars para reinyectar datos en formularios, no es necesario ejecutar después html_entity_decode ni htmlspecialchars_decode sobre los datos recibidos.
Hemos aprendido hasta ahora: cómo recoger los datos de un formulario y como mostrar los datos recibidos en diferentes escenarios. Vamos a completar este aprendizaje viendo como se reinyectarían los datos recibidos a un formulario dependiendo del elemento de formulario HTML usado.
Imagina que un usuario está editando su comentario sobre un producto y el usuario comete algunos errores por ejemplo al valorar el producto, lo ideal sería que se volviera a mostrar el formulario con los datos que previamente, por ejemplo:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
La idea es por tanto que después de procesar los datos y revisar si se han recibido y si son correctos, volver a mostrar los datos correctos en el formulario ya rellenado junto con los errores encontrados. Recoger los datos de un formulario es algo que ya sabemos hacer, puesto que lo hemos visto en apartados anteriores. Pero, ¿cómo reinyectamos los datos? Algo hemos visto en apartados anteriores, pero vamos a concretar el ejemplo un poco más. Imagina que tienes un formulario como el siguiente en el archivo mostrar_formulario.php:
<?php
$id_producto = $id_producto ?? $_GET['id_producto'] ?? null;
if (!is_numeric($id_producto)) {
die('ERROR: el formulario de comentarios no se ha accedido de forma adecuada.');
}
?>
<form action='procesar_comentario.php' method='POST'>
<input type='hidden' name='id_producto' value='<?= $id_producto ?>'>
¿Cuántas estrellas le das al producto?<BR><BR>
<label>1 <input type="radio" name="estrellas" value="1" id=""></label>
<label>2 <input type="radio" name="estrellas" value="2" id=""></label>
<label>3 <input type="radio" name="estrellas" value="3" id=""></label>
<label>4 <input type="radio" name="estrellas" value="4" id=""></label>
<label>5 <input type="radio" name="estrellas" value="4" id=""></label>
<BR><BR>
<label for="comentario">Introduce tu comentario:<BR>
<textarea name='comentario' rows='4' cols='50'></textarea></label><br><BR>
<input type='submit' value='Enviar Comentario!!'>
</form>
La idea del ejemplo anterior es insertar un comentario en un producto añadiendo un parámetro de ruta, por ejemplo: http://localhost/mostrar_formulario.php?id_producto=10. No vamos a guardar el comentario, pero nos sirve para simularlo.
En el script de destino: procesar_comentario.php; tendremos que programar la validación de los datos recibidos. Aunque esto se puede realizar de muchas formas, lo ideal es ir recopilando los datos correctos en una variable para así descartar los incorrectos. El código del archivo procesar_comentario.php podría ser así:
<?php
if (is_numeric($_POST['id_producto']??null))
$datosCorrectos['id_producto']=$_POST['id_producto'];
else
$errores[]="ERROR: los datos recibidos no son los esperados.";
if(is_numeric($_POST['estrellas']??null) && in_array(intval($_POST['estrellas']),range(1,5)))
{
$datosCorrectos['estrellas']=intval($_POST['estrellas']);
}
else
$errores[]="ERROR: No has marcado las estrellas que le darías al producto.";
if(!empty($_POST['comentario']??''))
{
$datosCorrectos['comentario']=$_POST['comentario'];
}
else
$errores[]="ERROR: No se ha rellenado el comentario.";
if (!empty($errores))
{
$id_producto=$datosCorrectos['id_producto']??null;
include 'mostrar_formulario.php';
}
else
{
//... guardar el comentario ...
echo "EXITO! El comentario se ha guardado.";
}
?>
En el ejemplo anterior se comprueban que los datos existan y que tengan un mínimo de seguridad. Fíjate que los errores se van acumulando en el array $errores y que los datos válidos en el array $datosCorrectos. Y lo más importante, ¿qué ocurre si hay errores? Fíjate que se vuelve a incluir el archivo mostrar_formulario.php. ¡Claro! La idea es que se rellene el formulario con los datos que son correctos y que se muestren los mensajes de error. Pero para ello debemos modificar el formulario inicial:
<?php
$id_producto = $id_producto ?? $_GET['id_producto'] ?? null;
if (!is_numeric($id_producto)) {
die('ERROR: el formulario de comentarios no se ha accedido de forma adecuada.');
}
if (isset($datosCorrectos['estrellas']))
${"estrellas".$datosCorrectos['estrellas']}='checked';
?>
<?php if (!empty($errores)): ?>
<ul>
<?php foreach($errores as $error): ?>
<li><?=$error?></li>
<?php endforeach;?>
</ul>
<?php endif; ?>
<form action='procesar_comentario.php' method='POST'>
<input type='hidden' name='id_producto' value='<?= $id_producto ?>'>
¿Cuántas estrellas le das al producto?<BR><BR>
<label>1 <input type="radio" name="estrellas" value="1" id="" <?=$estrellas1??''?>></label>
<label>2 <input type="radio" name="estrellas" value="2" id="" <?=$estrellas2??''?>></label>
<label>3 <input type="radio" name="estrellas" value="3" id="" <?=$estrellas3??''?>></label>
<label>4 <input type="radio" name="estrellas" value="4" id="" <?=$estrellas4??''?>></label>
<label>5 <input type="radio" name="estrellas" value="4" id="" <?=$estrellas5??''?>></label>
<BR><BR>
<label for="comentario">Introduce tu comentario:<BR>
<textarea name='comentario' rows='4' cols='50'><?=htmlentities($datosCorrectos['comentario']??'');?></textarea></label><br><BR>
<input type='submit' value='Enviar Comentario!!'>
</form>
En el script anterior mostrar_formulario.php se han introducido algunas mejoras notables. Veamos:
Se muestran los errores que pudiera haber (solo si existe la variable $errores)
Se muestra el texto del comentario (solo si existe $datosCorrectos['comentario']).
Si existe $datosCorrectos['estrellas'] la opción marcada se vuelve a marcar.
El ejemplo anterior es un claro ejemplo de reinyección de datos, donde se vuelven a mostrar los datos introducidos. A continuación tiene el código del ejemplo completo para que puedas analizarlo, aunque obviamente, existen muchas formas de solucionar el mismo problema:
Y por último, un pequeño recordatorio de como rellenar datos previos en los elementos de formulario más comunes:
Rellenar valores previos en campos y areas de texto
Rellenar los datos previos en un campo de texto (type="text", type="number", type="email", etc.) y en un campo de área de texto (<textarea></textarea>) requiere insertar los datos previos usando htmlentities o htmlspecialchars:
Rellenar valores previos en campos de elección tipo <select>
Cuando tenemos campos tipo <select> lo más habitual es tener la información a mostrar en cada opción en un array asociativo. En el ejemplo siguiente los valores a mostrar en cada opción están almacenados en un array asociativo, y la opción que marco el usuario previamente en la variable $opSeleccionada. Fíjate que volver a marcar la opción que previamente marcó el usuario es simplemente poner selected en el elemento HTML <option> adecuado:
Rellenar valores previos en campos de elección tipo <input type="radio">
Cuando tenemos campos tipo <input type="radio"> , nuevamente, lo más habitual es tener la información a mostrar en cada opción en un array asociativo. En el ejemplo siguiente la opción que selecciono el usuario previamente está almacenada en la variable $opSeleccionada. Fíjate que volver a marcar la opción que previamente marcó el usuario es, en este caso, simplemente poner checked:
Rellenar valores previos en campos de elección tipo <input type="checkbox">
A diferencia de otros campos, en los campos tipo <input type="checkbox"> el usuario puede marcar varias casillas. En el ejemplo siguiente las casillas que selecciono previamente el usuario están almacenadas en un array llamado variable $opsSeleccionada. Fíjate que volver a marcar todas las casillas que previamente marcó el usuario es, en este caso, poner checked. Sin embargo, el código cambia ligeramente, porque deberemos verificar si cada opción está o no en el array de casillas marcadas seleccionadas previamente:
Perdón por insistir, pero... IMPORTANTE: aunque se haga uso de htmlentities y htmlspecialchars para reinyectar datos en formularios, no es necesario ejecutar después html_entity_decode ni htmlspecialchars_decode sobre los datos recibidos.
En los apartados anteriores has visto la base para recibir datos procedentes del navegador a través de parámetros de URL y formularios. La recepción de datos puede conllevar la creación de uno o varios scripts PHP con el objetivo de: mostrar formularios o enlaces, recoger los datos externos y validarlos, mostrar posibles errores o procesar los datos recibidos.
Estos pasos suelen ser siempre los mismos, pero la estrategia de implementación puede cambiar. Podemos por ejemplo tener un script que muestre el formulario (por ejemplo mostrar_formulario.php) y otro que, por ejemplo, recoja los datos recibidos y los valide, que muestre posibles errores junto con el formulario para corregir dichos errores, y si no hay errores, pues simplemente que los procese (por ejemplo procesar_formulario.php). En la siguiente imagen puedes verlo gráficamente:
Elaboración propia - Salvador Romero Villegas(CC BY-NC-ND)
Sin embargo, este esquema es bastante optimizable. Si te fijas en el esquema anterior hay código repetido, concretamente el bloque correspondiente a "Mostrar formulario". Esto puede solucionarse de mil formas diferentes. Una posible solución sería crear un tercer script (por ejemplo llamado formulario.php) cuyo objetivo podría ser solamente mostrar los errores (si los hay) y el formulario, de forma que nos ahorramos el código repetido:
Elaboración propia - Salvador Romero Villegas(CC BY-NC-ND)
En este esquema se usa un script comodín (llamado formulario.php) para reutilizar código y es una posible solución bastante óptima, dado que permite separar claramente la funcionalidad de cada script y el código es bastante fácil de entender.
Otra posible solución, muy común dicho sea de paso, sería crear un único script para mostrar y procesar el formulario (llamado por ejemplo mostrar_y_procesar_formulario.php). Es decir, realizar todo el procesamiento en un único script. A continuación puedes ver un posible esquema de funcionamiento:
Elaboración propia - Salvador Romero Villegas(CC BY-NC-ND)
En el modelo anterior primero se comprueba si hay datos POST, si los hay se recogen y validan, y en función de la validación se muestran errores y el formulario para corregir los errores. En cambio, si no hay datos POST simplemente se muestra el formulario. En este escenario el formulario del script dirige la acción sobre si mismo.
El caso anterior, a veces, puede simplificarse, separando una parte en otro script. Por ejemplo, si el formulario es muy complejo, podríamos separar dicho formulario en otro script para simplificar el código:
Elaboración propia - Salvador Romero Villegas(CC BY-NC-ND)
Lo importante ahora es que tengas en mente que pueden existir multitud de variantes y que, en función de las necesidades y del proyecto es posible que se realice de una forma u otra. Los elementos clave son:
¿Cómo determinamos si hay datos POST o GET?
Determinar si hay datos POST o GET es tan fácil como verificar si el array $_GET o $_POST tiene datos o está vacío. Puedes por ejemplo, usar la función count:
if (count($_POST)>0) {
//Hay datos POST
}
if (count($_GET)>0) {
//Hay datos GET
}
Aunque realmente, cuando un array contiene datos, al ponerlo directamente en una condición, se evaluará a true, con lo que verificar si un array tiene datos es tan sencillo como:
if ($_POST) {
//Hay datos POST
}
if ($_GET) {
//Hay datos GET
}
¿Qué significa recoger y validar datos?
Significa, básicamente, ir recopilando los datos correctos de $_POST o $_GET en un array aparte, así como los errores que se hayan podido producir:
if (isset($_POST['nombre']) && strlen($_POST['nombre'])>5)
$datos['nombre']=$_POST['nombre'];
else
$errores[]='El nombre no se ha proporcionado o no es correcto.';
Este proceso es necesario para descartar posibles datos $_POST y $_GET no deseados, así como para realizar una validación de los mismos. Más adelante se verá la importancia de validar y, además, sanear esos datos.
¿Cómo puedo comprobar si hay errores en los datos recibidos?
Este punto es importante porque hay que garantizar que no se ejecute el código inadecuado cuando los datos recibidos son erróneos. Si has seguido un procedimiento como el anterior, donde los erroes se han acumulado en un array, saber si hay errores es simplemente verificar si el array $errores tiene elementos:
if (isset($_POST['nombre']) && strlen($_POST['nombre'])>5)
$datos['nombre']=$_POST['nombre'];
else
$errores[]='El nombre no se ha proporcionado o no es correcto.';
//... resto de comprobaciones
if (count($errores)>0)
{
//... código previsto cuando hay errores
}
else
{
//... código previsto cuando no hay errores
}<br style="clear: both;" />
Este es un mecanismo sencillo y fácil de implementar.
En este apartado se explican algunas prácticas comunes. Sin embargo, es importante que sepas que hay múltiples formas de solucionar un mismo problemas de forma eficiente, por lo que como futuro programador o futura programadora tienes que tener la mente abierta a aprender nuevas buenas prácticas. Eso solo lo aprenderás escribiendo tu propio código, analizando soluciones y viendo cómo otros programadores y otras programadoras lo han solucionado.
Carlos está viendo que el esfuerzo que le dedica al aprendizaje del nuevo lenguaje empieza a dar sus frutos. Hace unos días casi no sabía ni que existía PHP, y ahora ya es capaz de realizar programas sencillos por sí mismo.
Para poder avanzar aún más, sabe cuál ha de ser su siguiente paso: obtener y utilizar información de un usuario. De esta forma, los programas que haga no serán lineales, sino que tendrán un comportamiento u otro en función de los datos que aporte el usuario.
Como le ha comentado Juan, para obtener información de un usuario, en PHP se utilizan los formularios HTML. ¡A por ellos!
Después de unos días, Carlos ya domina la creación de formularios HTML y la captura de datos usando el método POST en PHP. Decide compartir su progreso con Juan, quien ha estado trabajando en un problema más avanzado: la validación de datos recibidos a través de formularios.
Juan le explica a Carlos que está validando los datos de los formularios para asegurarse de que sean correctos antes de procesarlos. Le muestra un ejemplo de cómo usa filter_input() para validar correos electrónicos y preg_match() para verificar números de teléfono.
Carlos, impresionado, ve cómo Juan limpia y valida los datos antes de procesarlos, previniendo errores y mejorando la seguridad. Motivado, Carlos decide implementar estas validaciones en sus propios proyectos.
Los problemas derivados de una incorrecta o insuficiente validación y saneado de datos en una aplicación web pueden derivar en graves problemas de seguridad. Aplicar estas técnicas es imprescindible.
¿Qué es la validación de datos?
La validación de datos es un procedimiento que consiste en asegurar que los datos recibidos son los esperados y tienen el formato esperado. Dentro de este procedimiento podemos distinguir lo siguiente:
Recopilar los datos esperados (y rechazar los no esperados). Como ya sabes, una aplicación web puede recibir datos vía POST y/o GET. Nuestra aplicación deberá estar preparada tanto para recoger esos datos, como para no verse afectada por datos recibidos que no son necesarios y que han sido enviados con intenciones cuanto menos sospechosas. Nada impide a un usuario añadir tantos parámetros en la URL o añadir datos POST como quiera, solo necesita un mínimo de conocimientos en informática.
Analizar cada dato y comprobar que tiene el formato esperado. Aparte de lo anterior, ocurre que en múltiples ocasiones los datos que envía un usuario pueden no tener el formato esperado. Puede que un dato concreto (por ejemplo, $_POST['edad']), se espere como un número, pero que el usuario por error o de forma malintencionada, haya puesto un dato no numérico. Es un nuestro trabajo evitar que esos escenarios puedan afectar a nuestro código.
Aunque HTML provee de algunas ayudas para evitar que el usuario introduzca datos no esperados (como por ejemplo: <input type="number" name="edad">), tienes que saber que esas restricciones no son suficientes y no se puede confiar plenamente en ellas, dado que es extremadamente sencillo saltarse dichas barreras.
Es un proceso por el cual se elimina de los datos información no pertinente o esta se convierte a un formato concreto.
Para entender la necesidad de saneamiento veamos un ejemplo. Imagina que en un formulario el usuario puede introducir comentarios sobre un producto y que el usuario escribe: <STRONG>Fantástico producto!</STRONG>. El usuario, con buenas intenciones (o no, quizás esté probando si la aplicación tiene agujeros de seguridad), ha escrito una etiqueta HTML en el comentario. Esto puede afectar de muchas maneras, por ejemplo, puede hacer que la interfaz de usuario se vea de forma no prevista. ¿Qué hacemos? Baneamos el comentario o eliminamos las etiquetas HTML. La opción de eliminar las etiquetas HTML sería un saneado de datos.
Otro escenarios comunes son:
Cuando se introducen espacios accidentalmente antes o después del texto.
Cuando necesitamos que un dato esté siempre en mayúsculas o minúsculas. No rechazamos los datos cuando no son lo esperado, simplemente aplicamos la transformación.
Cuando necesitamos que un dato tenga un formato canónico o normalizado. Por ejemplo, cuando un usuario introduce el DNI en formato 12345678-a pero nosotros lo tenemos que almacenar como 12345678A.
Cuando se reciba una fecha en formato dd/mm/aaaa pero por requerimientos de la base de datos debe almacenarse como aaaammdd.
Dependiendo de las exigencias de la aplicación, cuando se reciben datos $_GET o $_POST (o incluso cookies) podemos ser más o menos severos a la hora de procesar la solicitud:
Opción más restrictiva: desechar todas las peticiones que no tengan exactamente los datos esperados.
Opción menos restrictiva: ignorar los datos recibidos que no sean los esperados.
Por ejemplo, imagina que tienes el siguiente formulario:
En el script ejemplo.php podríamos, por ejemplo, aceptar los datos cuando $_POST está vacío o bien, cuando contiene exactamente los datos POST nombre, apellidos y edad del formulario (opción más restrictiva):
<?php
$camposEsperados=['nombre','apellidos','edad'];
if ($_POST
&& count($_POST)!=count($camposEsperados)
|| !empty(array_diff(array_keys($_POST),$camposEsperados)))
{
die("Datos no esperados!");
}
En el ejemplo anterior, si el número de campos recibidos no coincide con el número esperado ( count($_POST)!=count($camposEsperados) ) o si hay campos inesperados (!empty(array_diff(array_keys($_POST),$camposEsperados))), muestra un mensaje de error y detiene la ejecución.
O bien, podríamos filtrar los datos recibidos descartando aquellos que no sean los esperados (opción menos restrictiva):
El uso en este caso de array_intersect_key calcula la intersección de ambos arrays basándonos en la clave, quedándonos solamente con los datos que tienen un key común entre ambos arrays, pero con los valores del primero ($_POST).
Estos filtrados iniciales son útiles pero no suficientes. Posiblemente el segundo ejemplo (opción menos restrictiva) es la más común, pero su aplicación dependerá de las restricciones de la aplicación a desarrollar. Para completar estos filtrados es imprescindible analizar cada dato recibido y validar que están conforme a lo esperado.
Los datos recibidos pueden ser de lo más variopintos y explicar aquí todas las posibles casuísticas es imposible. Lo que si puedes es tener en mente cuales son las técnicas más habituales para verificar los datos:
Comprobación de longitud mínima o máxima de cadena. En ella se comprueba que la cadena de texto recibida tiene una longitud mínima o máxima. Por ejemplo: strlen($_POST['nombre')<50. Este tipo de comprobaciones es habitual cuando tenemos que almacenar el dato posteriormente en una base de datos.
Comprobación de tipo de dato numérico. Cuando esperamos un dato numérico es común usar la función is_numeric: por ejemplo, is_numeric($_POST['edad']); esta función comprobará si la cadena de texto contiene un número o si es de un tipo de dato numérico.
Conjuntos finito de opciones. Cuando necesitamos comprobamos si un dato está o no en un conjunto de valores concreto y finito podemos utilizar funciones como in_array: por ejemplo: in_array($_POST['carnet'],['si','no']);. En el caso de que el dato sea un array de valores dentro de un conjunto finito (un subconjunto de un conjunto finito de valores) podríamos usar la función array_diff.
Comprobación de cadenas de texto con estructuras concretas. En este caso la opción más habitual es el uso de expresiones regulares.
De todas las anteriores, las tres primeras son básicas y seguramente ya las intuirás o las conocerás de ejemplos anteriores. Sin embargo, ¿qué ocurre con datos con cadenas de texto que deben tener una estructura concreta? Por ejemplo: la hora del día (hh:mm) o un correo electrónico. Ahí estamos obligados a usar expresiones regulares, amadas y odiadas a partes iguales.
El uso de las expresiones regulares es sencillo, lo difícil es diseñarlas. La idea detrás de una expresión regular es verificar si una cadena sigue un patrón concreto. A continuación tienes un ejemplo de una expresión regular que define el patrón de la hora:
Elaboración propia - Salvador Romero Villegas(CC BY-SA)
La expresión regular anterior se usaría para verificar la hora y tendría el siguiente significado:
Los símbolos / al comienzo y al final indican cuando acaba y finaliza la expresión regular.
El símbolo ^ al comienzo indica que el texto coincidirá en inicio con la expresión regular. En caso de no indicarlo, la coincidencia podría darse en cualquier parte del texto, pudiendo haber cualquier texto antes de la coincidencia buscada.
El símbolo $ al final indica por otro lado que el texto coincidirá en el fin con la expresión regular. En este caso, en caso de no indicarlo, podría haber cualquier texto detrás del texto buscado.
Los paréntesis ([01]\d|2[0-3]) representan un grupo y el símbolo | indica alternancia. Quiere decir que es válido encontrar la primera parte [01]\d o bien la segunda 2[0-3];
Los corchetes [] por otro lado delimitan lo que llamamos grupos de caracteres. Con [0-5] por ejemplo se indica que se espera un carácter que sea 0, 1, 2, 3,4 o 5.
Por otro lado, \d es también un grupo de caracteres, que es como es muy común tienen una expresión más corta que denominamos tipos de caracteres. El tipo \d es básicamente cualquier dígito numérico.
Y por último, el símbolo ":" es un literal. Es decir, es un símbolo que se espera si o si en esa posición.
Por tanto esa expresión regular se podría explicar con el siguiente texto: "Un número entre 00 y 19 o bien entre 20 y 23, seguido de dos puntos, y después seguido de un número entre 00 y 59".
Para verificar si una cadena de texto sigue un patrón usamos la función preg_match. Por ejemplo:
if (preg_match('/^([01]\d|2[0-3]):[0-5]\d$/',$_POST['hora']??''))
{
echo "La hora es correcta.";
}
else
{
echo "La hora no es correcta";
}
A continuación tienes una tabla con los elementos más comunes de las expresiones regulares en PHP:
Elementos más comunes en las expresiones regulares
Elemento
Significado en la expresión regular
Metacaracteres
Son símbolos que tienen un significado especial en la expresión regular, como por ejemplo: \ (carácter de escape), ^ ancla de inicio, $ ancla de fin, [ inicio de definición de una clase de carácter, etc.
Los metacaracteres no pueden ser usados como parte de una expresión regular salvo que se use el carácter de escape. Por ejemplo: \*
Literales
Coinciden exactamente con el mismo carácter en la cadena. Por ejemplo, /abc/ encajará con cualquier cadena que contenga la cadena "abc", como es el caso de bcabcbc o abcabc.
Cuando necesitamos poner un metacaracter como parte de un literal tenemos que usar el carácter de escape. Por ejemplo:
La expresión regular /abc.d/ permitiría cualquier carácter entre la c y la d dado que el punto es un metacaracter que significa "cualquier caracter".
Pero la expresión regular /abc\.d/ encajaría con cualquier cadena que contenga exactamente la cadena "abc.d", como es el caso de bcabc.dbc o abc.dabc.
Clases de caracteres
Con una clase se indica que en un lugar dado se espera un caracteres de un tipo dado. Por ejemplo: \[abc]\ indica que se espera un carácter que sea a, b o c como parte de la cadena de texto. Si por el contrario queremos indicar que se espera un carácter que no sea ninguno de ellos sería \[^abc]\ , es decir, se espera un carácter que no sea ni a ni b ni c. En las clases de caracteres se pueden usar rangos, como por ejemplo: \[0-5]\ ; donde se indicaría que se espera un número entre 0 y 5.
Tipos de caracteres genéricos
Son secuencias de escape con significados especiales que representan un conjunto de caracteres, los más comunes son:
\d: Coincide con cualquier dígito decimal [0-9].
\s: Coincide con cualquier espacio en blanco.
\w: Coincide con cualquier carácter de palabra alfanumérico [a-zA-Z0-9_].
Especifican cuántas veces se debe repetir un carácter o un grupo de caracteres.
*: Coincide con cero o más repeticiones del carácter o grupo anterior. Por ejemplo: /A*B/ admitiría una cadena que texto que contenga una secuencia de cero o más A y una B como por ejemplo CAAAAAB o ABC o XBC.
+: Coincide con una o más repeticiones del carácter o grupo anterior. Por ejemplo: /A+B/ admitiría una cadena que texto que contenga al menos una A seguido de una B como por ejemplo CAAAAAB o ABC o XABC.
?: Coincide con cero o una repetición del carácter o grupo anterior. Por ejemplo: /(AX)?B/ admitiría una cadena que texto que contenga opcionalmente AX antes de una B como por ejemplo CAXB o CB.
{n}: Coincide exactamente con n repeticiones. Por ejemplo: /A{10}B/ admitiría una cadena que texto que contenga al 10 A seguido de una B como por ejemplo CAAAAAAAAAAB.
{n,}: Coincide con al menos n repeticiones. Por ejemplo: /[0-9]{3,}B/ admitiría una cadena que texto que contenga como mínimo 3 dígitos numéricos seguidos de una B como por ejemplo C123B o C12345B.
{n,m}: Coincide con al menos n y como máximo m repeticiones.
Anclas
Representan posiciones en la cadena de texto. Las más habituales son, como se ha explicado antes:
^: Delante de la coincidencia no se permite ningún carácter. Por ejemplo: /^[0-9]{3,}B/ admitiría 123B pero no admitiría C12345B.
$: Detrás de la coincidencia no se permite ningún carácter. Por ejemplo: /[0-9]{3,}B$/ admitiría CDE123B pero no admitiría 123BCDE.
Grupos de captura
Los grupos se definen con paréntesis (subpatron). Sirven para dos cosas fundamentalmente:
Definir un bloque de caracteres que se pueden repetir o donde puede haber alternancias:
Para expresar repetición se usaría simplementa añadiendo un repetidor tras el bloque, por ejemplo: (AB)+; que encajaría con AB, ABAB, ABABAB, ...
Para expresar alternancia se usaría el símbolo |, por ejemplo ([01]\d|2[0-3]) donde se indica que puede coincidir con [01]\d o bien con 2[0-3].
Definir un grupo que una vez detectado, se quiere extraer de la cadena.
Para ilustrar este último caso, vamos a ver un pequeño ejemplo:
$captura=[];
if (preg_match('/^([01]\d|2[0-3]):([0-5]\d)$/',$_POST['hora']??'',$captura))
{
echo "La hora indicada es {$captura[1]} y los minutos indicados son {$captura[2]}";
}
else
{
echo "La hora no es correcta";
}
En el ejemplo anterior, si el texto encaja con la expresión regular, el array $captura contendría los datos capturados en cada grupo.
En este apartado se muestra un pequeño resumen de como usar expresiones regulares. Si quieres saber más sobre como usarlas en PHP y su sintaxis completa puedes revisar el siguiente apartado de la documentación de PHP:
La validación de fechas es un asunto peliagudo por diversos motivos, el principal es que no existe una expresión regular que garantice que la fecha es correcta. Por ejemplo, el día 29/02/2020 existe porque 2020 fue un año bisiesto, pero no existe en cambio el 29/02/2021, porque el año 2021 no fue bisiesto. Este es posiblemente el ejemplo más claro.
La validación de fecha podemos realizarla de varias formas, pero siempre requiere el uso de funciones o clases específicas que permitirán realizar una verificación certera, y que harán las comprobaciones pertinentes para asegurar que una fecha es válida. A continuación vamos a explorar dos formas: usando una expresión regular y la función checkdate, y por otro lado, usando la función date_parse_from_format de PHP. No obstante, esto no quita que puedan utilizarse otras técnicas diferentes para garantizar que la fecha sea correcta.
Método 1) Usando una expresión regular y la función checkdate
En primer lugar, diseñaremos una expresión regular que nos permita, por lo menos, garantizar que la fecha tiene los números en su orden. Por ejemplo: /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})/; que espera la fecha en formato dd/mm/aaaa como por ejemplo 10/02/2024.
Fíjate que en la expresión regular anterior solo busca que haya tres números de determinadas longitudes separados por el símbolo \ (se indica \/ porque es un metacaracter y para poder se usado como literal es necesario escaparlo). No obstante, como podrás deducir, la expresión regular anterior permite fechas como 32/13/2021 que son claramente incorrectas. Para averiguar si esa fecha es correcta haremos uso de la función checkdate.
$fechaRecibida='10/02/2024';
$regexp='/^([0-9]{2})\/([0-9]{2})\/([0-9]{4})/';
$partes=[];
if (preg_match($regexp,$fechaRecibida,$partes))
{
$mes=$partes[2];
$dia=$partes[1];
$año=$partes[3];
if (checkdate($mes,$dia,$año))
{
echo "La feha proporcionada es correcta";
}
else
{
echo "La fecha proporcionada no existe";
}
}
else
{
echo "Fecha no tiene el formato esperado";
}
Aquí es especialmente importante que prestes atención al uso de checkdate, donde se espera que los parámetros vayan en el orden: mes, día y año. Es un fallo común poner día primero en vez de el mes.
Método 2) Usando la función date_parse_from_format
La función date_parse_from_format de PHP permite parsear una fecha a partir de una cadena de formato de fecha. Esto permite, entre otras cosas, adaptar nuestra aplicación rápidamente a diferentes formatos de fecha.
En España, por ejemplo, el formato de fecha es normalmente dd/mm/aaaa sin embargo en Estados Unidos el formato de fecha normal habitual es mm/dd/aaaa. Lidiar con estas situaciones requiere el uso de diferentes expresiones regulares para cada caso con función de las preferencias del usuario. Si el usuario indica que es estadounidense podemos procesar la fecha de una forma, pero si indica que es español o española podemos procesarla de otra forma.
La función date_parse_from_format permite especificar el formato de la fecha usando parámetros de formato, los más usado son:
d indica el día con dos dígitos, es decir, con un cero delante para completar los dos dígitos (de 01 a 31).
j indica el día sin ceros delante (de 1 a 31).
m indica el mes con ceros delante (de 01 a 12).
n indica el mes sin ceros delante (de 1 a 12).
Y indica el año con cuatro dígitos.
Por ejemplo, el parámetro de formato para la fecha dd/mm/aaaa sería d/m/Y mientras que para la fecha mm/dd/aaaa sería m/d/Y. Bien, ¿cómo lo aplicamos una vez sabemos como es la cadena de formato de fecha? Veamos un ejemplo:
El código anterior genera un array asociativo con los datos de la fecha y los posibles errores que se hayan podido producir. El contenido de $datosFecha anterior sería:
Cuando se analiza una fecha hay que revisar tanto warning_count como error_count para asegurar que la fecha no tiene errores. Por ejemplo:
$fechaRecibida='31/02/2024';
$formatoFecha='d/m/Y';
$datosFecha=date_parse_from_format($formatoFecha,$fechaRecibida);
if ($datosFecha['warning_count']+$datosFecha['error_count']>0)
echo "La fecha es errónea";
else
echo "La fecha es correcta";
Manipulación y comparación de fechas
En algunas ocasiones es necesario hacer procesamiento de fechas más avanzado, como por ejemplo, comprobar si dos fechas proporcionadas son una anterior a la otra, comprobar si una fecha es posterior o anterior al día en curso o comprobar si entre dos fechas dadas hay más de un número determinado de días. Estas comprobaciones son comprobaciones complejas pero PHP proporciona una serie funciones y métodos que te serán de utilidad. Son muchas las funciones pero vamos a revisar las más usadas:
Funciones más usada en el tratamiento de las fechas
Función
Descripción
time()
Genera un número entero que contiene el momento actual pero en segundos transcurridos desde el 1 de Enero de 1970. A los segundo de tiempo transcurridos desde 1 de Enero de 1970 se le suele denominar sello de tiempo Unix o timestamp Unix.
<a class="html" href="https://www.php.net/manual/es/function.getdate.php" target="_blank" title="Haz clic para ver la documentación de la función getdate" rel="noopener">getdate</a>($timestamp = time())
Se utiliza para generar un array asociativo con el día, mes, año, etc. de la fecha numérica. Por ejemplo:
<?php
$infoFecha = getdate();
echo "Hoy es {$infoFecha['mday']}/{$infoFecha['mday']}/{$infoFecha['year']}";
<a class="html" href="https://www.php.net/manual/es/function.date.php" target="_blank" title="Haz clic para ver la documentación de la función date" rel="noopener">date</a>($format, $timestamp = time())
Se utiliza para generar una cadena de texto partiendo de un sello de tiempo Unix, por ejemplo: date("d/m/Y",time()) genera la fecha del día en curso en formato dd/mm/aaaa.
<a class="html" href="https://www.php.net/manual/es/function.mktime.php" target="_blank" title="Haz clic para ver la documentación de la función mktime." rel="noopener">mktime</a> ($hour, $minute, $second, $month, $day, $year)
Se utiliza para obtener un sello de tiempo unix a partir de una fecha y horas dada. Cada argumento es un número entero.
<a class="html" href="https://www.php.net/manual/es/function.strtotime.php" target="_blank" title="Haz clic para ver la documentación de la función strtotime" rel="noopener">strtotime</a>(string $time)
Permite convertir una fecha en formato inglés (AAAA-MM-DD) a un sello de tiempo. Por ejemplo:
$timestamp=strtotime('2024-02-03',time()); //Convierte a sello de tiempo
echo date('d/m/Y',$timestamp); //Muestra 03/02/2024
A esta función se pueden aplicar operaciones simples para añadir días después o anteriores entre otras cosas:
//Procesamos la fecha 3 de febrero de 2024 + 7 días
$timestamp=strtotime('2024-02-03 +7 days',time());
echo date('d/m/Y',$timestamp); //Muestra 10/02/2024
La clase DateTime ofrece un catalogo enorme de métodos para tratar las fechas y operaciones sobre ellas. No trataremos esta clase en esta unidad porque requiere conocer la programación orientada a objetos en PHP.
Partiendo de las funciones anteriores puedes comparar fechas convirtiéndolas a un sello de tiempo o formato inglés. Las fechas en formato inglés son comparables como si fueran una cadena de texto: "2024-10-02"<"2024-10-01" será false y "2024-10-02">"2024-10-01" será true. Esto es porque las fechas en ese formato están ordenadas lexicográficamente y PHP cuando compara cadenas realiza una comparación lexicográfica.
Imagina que tienes dos fechas proporcionadas por el usuario que deben distar entre sí 7 días. Para simular este escenario vamos a imaginar que ambas fechas están almacenadas en variables: $fecha1='10/01/2025' y $fecha2='17/01/2025'. ¿Cómo podrías comprobar si se cumple la condición usando las funciones parse_str_from_format, mktime, date y/o strtotime?
En el apartado anterior se menciona la función date, que te permite obtener una cadena de texto a partir de una fecha y hora, con el formato que tú elijas. En este apartado vamos a profundizar en su uso.
El primer apartado de la función date es una cadena que especifica el formato de la fecha y la hora a obtener, el segundo parámetro es un sello de tiempo opcional (timestamp) generados con funciones como time() o mktime(). Si no se especifica usará el sello de tiempo del momento en el que se invoca la función.
Lo importante, no obstante, es que conozcas los diferentes especificadores de formato que se pueden usar:
Función date: caracteres de formato para fechas y horas.
Carácter
Resultado
d
día del mes con dos dígitos.
j
día del mes con uno o dos dígitos ( sin ceros iniciales ).
z
día del año, comenzando por el cero ( 0 = 1 de enero ).
N
día de la semana ( 1 = lunes, ..., 7 = domingo ).
w
día de la semana ( 0 = domingo, ..., 6 = sábado ).
l
texto del día de la semana, en inglés ( Monday, ..., Sunday ).
D
texto del día de la semana, solo tres letras, en inglés ( Mon, ..., Sun ).
W
número de la semana del año.
m
número del mes con dos dígitos.
n
número del mes con uno o dos dígitos ( sin ceros iniciales ).
t
número de días que tiene el mes.
F
texto del día del mes, en inglés ( January, ..., December ).
M
texto del día del mes, solo tres letras, en inglés ( Jan, ..., Dec ).
Y
número del año.
y
dos últimos dígitos del número del año.
L
1 si el año es bisiesto, 0 si no lo es.
h
formato de 12 horas, siempre con dos dígitos.
H
formato de 24 horas, siempre con dos dígitos.
g
formato de 12 horas, con uno o dos dígitos ( sin ceros iniciales ).
G
formato de 24 horas, con uno o dos dígitos ( sin ceros iniciales ).
i
minutos, siempre con dos dígitos.
s
segundos, siempre con dos dígitos.
u
microsegundos.
a
am o pm, en minúsculas.
A
AM o PM, en mayúsculas.
r
fecha entera con formato RFC 2822.
Por otro lado, para que el sistema pueda darte información sobre tu fecha y hora, es recomendable indicarle la zona horaria. Puedes hacerlo con la función date_default_timezone_set. Por ejemplo, para establecer la zona horaria en España peninsular debes indicar:
date_default_timezone_set('Europe/Madrid');
Así, por ejemplo, para obtener la fecha y la hora del momento en el que se ejecuta el script en diferentes zonas horarias podríamos ejecutar:
<?php
date_default_timezone_set('Europe/Madrid');
$fechaYHora = date("d/m/Y h:s");
echo "Hora en Europa/Madrid:".$fechaYHora."<BR>";
date_default_timezone_set('Australia/Sydney');
$fechaYHora = date("d/m/Y h:s");
echo "Hora en Australia/Sydney:".$fechaYHora."<BR>";
Haz una página web que muestre la fecha del día de hoy en castellano, incluyendo el día de la semana, con un formato similar al siguiente: "Miércoles, 14 de Octubre de 2015".
El saneado de datos en PHP es una medida básica y crucial para proteger cualquier aplicación web contra ataques como inyecciones SQL y XSS (cross-site scripting) entre otros. Además, proporciona una forma de evitar problemas comunes en datos que pueden contener irregularidades no esperadas. En este apartado vamos a revisar algunas técnica básicas para sanear datos.
De forma general el saneamiento de datos puede definirse como el proceso por el que se identifican, corrigen y/o eliminan posibles errores en los datos recibidos que pueden causar duplicados, inconsistencias o incongruencias de datos o en el formato de los mismos. En unidades posteriores los datos recibidos de formularios webs los almacenaremos en bases de datos para su posterior uso, es por ello que tenemos que asegurar que no se producen situaciones anómalas.
Los procesos de saneado de datos suelen perseguir los siguientes objetivos entre otros:
Simplificación: eliminación de contenido de los datos no necesario o redundante. Por ejemplo, eliminación de espacios anteriores o posteriores en cadenas de texto.
Normalización: al realizar una normalización transformamos los datos a una forma estándar o normalizada. Por ejemplo, cuando convertimos cualquier fecha recibida al formato AAAA-MM-DD o transformar las cadenas que contienen un número a su versión numérica ($edad=intval($_POST['edad'])).
Veamos algunas de las técnicas más habituales:
Eliminación de espacios sobrantes.
A menudo es común que un usuario introduzca espacios sin querer antes o después de un texto en un formulario. Para simplificar los datos recibidos es común usar la función trim().
$nombre = trim($_POST['nombre']??'');
if (empty($nombre))<a id="accesskey_menuitem-1024-itemEl" class="x-menu-item-link" href="http://localhost:51235/DAW_DWES_1_v03_00_00_EDIT#" hidefocus="true" unselectable="on" data-qtip="Ctrl+S"><img id="accesskey_menuitem-1024-iconEl" src="https://educacionadistancia.juntadeandalucia.es/formacionprofesional/pluginfile.php/138705/mod_scorm/content/0/img1.gif" class="x-menu-item-icon undefined" /><span id="accesskey_menuitem-1024-textEl" class="x-menu-item-text">Guardar</span><img id="accesskey_menuitem-1024-arrowEl" src="https://educacionadistancia.juntadeandalucia.es/formacionprofesional/pluginfile.php/138705/mod_scorm/content/0/img1.gif" class="" width="1" height="1" alt="Imagen que muestra dos tiritas sobre un ladrillo." /></a>
{
$errores[]="El nombre está vacío";
}
Conversión de cadena numérica a tipo de dato numérico.
El uso de las funciones intval() y floatval() tiene numerosas ventajas con datos numéricos. Cuando, por ejemplo, recibimos un número con espacios delante o con ceros delante, o con símbolos no numéricos al final, la aplicación de ambas funciones permitirá quedarse con la parte numérica:
Sin embargo, cuando se intenta convertir una cadena que no contiene un número con intval o floatval se generará el valor cero, algo que puede no ser lo esperado. Es por ello que normalmente se acompaña de la validación usando is_numeric():
if (is_numeric($strConNumero))
{
//intval o floatval a conveniencia
$numeroEntero=intval($strConNumero);
$numeroFlotante=floatval($strConNumero);
}
else
{
$errores[]="No es un número";
}
Un inconveniente del método anterior es que los números decimales se esperan siempre que tengan el punto como separador de la parte decimal (por ejemplo, 10.23) y no la coma que es lo estándar en España (por ejemplo, 10,23). Aunque los usuarios ya están acostumbrados a utilizar el punto como separador decimal, a veces es necesario programar nuestra aplicación para que acepten un número en la localización geográfica (también llamado LOCALE) española (es_ES):
<?php
$strConNumero = '1.234,56';
$formatter = new NumberFormatter('es_ES', NumberFormatter::DECIMAL);
$numero = $formatter->parse($numero);
if ($numero === false) {
echo "Error al procesar el número.";
} else {
echo "El recibido es: $numero";
}
El ejemplo anterior requiere el uso de la clase NumberFormatter, la cual, también nos permitirá escribir números usando el formato de cada localización geográfica.
Conversión a mayúsculas o minúsculas.
Cuando registramos datos tales como DNI o NIE en una base de datos, es común que el usuario escriba el dato en minúsculas o minúsculas de forma indiscriminada (12345678A o 12345678a, por ejemplo). Para evitar duplicidades e inconsistencias es necesario normalizarlos, transformándolos siempre a minúsculas o mayúsculas. Esta operación se suele realizar con las funciones strtolower($cadena) (convertir a minúsculas) y strtoupper($cadena) (convertir a mayúsculas), normalmente acompañada del uso de trim() y el empleo de alguna expresión regular:
$dni= strtoupper(trim($_POST['dni']??''));
if (!preg_match('/^([XYZ]?)(\d{1,9})([A-Z])$/',$dni))
{
$errores[]="El DNI o NIE no es correcto";
}
El caso anterior debería ir acompañado de un proceso de verificación de la letra del DNI o NIE, para así completar la validación de datos. También podría ir acompañado de un proceso de regularización de formato, adaptando el dato recibido a un formato diferente. Por ejemplo, podría admitirse un guion opcional para separar la letra del DNI (por ejemplo, 12345678-A), pero al almacenarlo no lo guardamos con dicho guión (12345678A):
$dni= strtoupper(trim($_POST['dni']??''));
$partesDNI=[];
if (!preg_match('/^([XYZ]?)-?(\d{1,9})-?([A-Z])$/',$dni,$partesDNI))
{
$errores[]="El DNI o NIE no es correcto";
}
else
{
$dniNormalizado=$partesDNI[1].$partesDNI[2].$partesDNI[3];
echo $dniNormalizado;
}
Escapado de caracteres y eliminación de etiquetas.
El escape de caracteres y la eliminación de etiquetas son, posiblemente, los procesos de saneado de datos más cruciales e importantes. Cuando los datos se almacenan en una base de datos o en otros medios, o se van a mostrar nuevamente al usuario después de su envío, pueden incluir secuencias de código maliciosamente insertadas que podrían comprometer o revelar el contenido de la base de datos o dañar a otros usuarios del servicio web, frecuentemente con intenciones deshonestas o malintencionadas.
En este contexto se dan dos escenarios posibles:
Evitar que los datos recibidos contengan secuencias que dañen la base de datos a través de ataques de inyección SQL. Para evitar eso se limpian los datos usando funciones como addslashes($dato).
Evitar que se muestren datos previamente recibidos en la web que alteren el contenido mostrado de forma no deseada o que dañe a otros usuarios. Este escenario, común en los ataques XSS, se puede evitar usando las funciones strip_tags, htmlentities y htmlspecialchars.
Un ejemplo de uso de la función addslashes sería el siguiente. Imagina que tienes un código que recibe un usuario y una contraseña, y necesitas componer una sentencia SQL para comprobar si el usuario es o no válido:
$passwordRecibido="...elpassword...";
$emailRecibido="... el usuario ...";
// ... varias líneas de código después, se usa el dato recibido...
$SQL= "SELECT * FROM usuarios WHERE password='$passwordRecibido' and email='$emailRecibido';";
La práctica anterior está completamente desaconsejada (no debería realizarse así como verás en la unidad de base de datos), pero hay muchos programadores y programadoras que lo hacen así. El código generaría una sentencia SQL como: SELECT * FROM usuarios WHERE password='...elpassword...' and email='... el usuario ...';. El problema es que si un usuario malintencionado introduce la cadena adecuada, podría autenticarse como cualquier usuario que deseara:
<?php
$passwordRecibido="...elpassword...";
$emailRecibido="' or email='ejemplo@ejemplo.com";
// ... varias líneas de código después, se usa el dato recibido...
$SQL= "SELECT * FROM usuarios WHERE password='$passwordRecibido' and email='$emailRecibido';";
/*
$SQL contendría:
SELECT * FROM usuarios WHERE password='...elpassword...' and email='' or email='ejemplo@ejemplo.com';
*/
Como puedes ver, la estructura del SQL se ha alterado de forma poco deseable. Para evitar esto es imprescindible usar en estos casos la función addslashes:
<?php
$passwordRecibido="...elpassword...";
$emailRecibido="' or email='ejemplo@ejemplo.com";
// ... saneado de datos con addslashes ...
$emailRecibido = addslashes($emailRecibido);
$SQL= "SELECT * FROM usuarios WHERE password='$passwordRecibido' and email='$emailRecibido';";
/*
$SQL contendría:
SELECT * FROM usuarios WHERE password='...elpassword...' and email='\' or email=\'ejemplo@ejemplo.com';*/
Al usar esta función puedes ver como se escapa el símbolo ' por '\'', de forma que es parte de la cadena con la que se compara el email y no altera la estructura del SQL.
El uso de htmlentities y de htmlspecialchars ya ha sido visto en apartados anteriores, y no vamos a repasarlo otra vez, pero el uso de strip_tags no ha sido revisado y es importante que lo conozcas. Su propósito principal es evitar que información recibida no haga estragos cuando se vuelva a mostrar en la interfaz.
La función strip_tags elimina etiquetas HTML no deseadas. Por ejemplo, si un usuario introduce en un formulario $cadenaRecibida="<B><script>alert('hola');</script>Hola!</B>"; al usar esta función ($cadenaLimpia=strip_tags($cadenaRecibida);) se eliminan las etiquetas HTML, quedando solo "alert('hola');Hola!".
En la función strip_tags podemos indicar aquellas etiquetas que deseamos conservar: por ejemplo $cadenaLimpia=strip_tags($cadenaRecibida,'<B><EM>'); permitiría las etiquetas <B> y <EM>, y aplicado sobre el ejemplo anterior generaría la cadena "<B>alert('hola');Hola!</B>".
Las diferentes medidas que se han explicado en apartados anteriores se pueden combinar entre sí para validar y sanear los datos recibidos de forma adecuada antes de hacer uso de ellos. PHP, por su parte, incorpora también unas varias funciones que permiten realizar validación y saneado. Estas funciones, por supuesto, se pueden combinar con las anteriores y entre sí.
Las primeras funciones que vamos a revisar son filter_has_var y filter_input. La primera de ellas, filter_has_var está pensada para verificar si un dato se ha recibido vía GET o POST (también permite comprobar otros orígenes pero no los vamos a revisar), por ejemplo:
<?php
//true si existe $_POST['nombre']
if (filter_has_var (INPUT_POST, 'nombre'))
{
echo 'Se ha recibido nombre vía POST';
}
//true si existe $_GET['nombre']
if (filter_has_var (INPUT_GET, 'nombre'))
{
echo 'Se ha recibido nombre como parámetro de URL';
}
Como puedes observar para recoger un dato GET o POST se usan respectivamente las constantes INPUT_GET e INPUT_POST. La función filter_input permite, por otro lado, recoger los datos recibidos especificando opcionalmente un filtro o un saneado, por ejemplo:
<?php
$edad=filter_input(INPUT_POST,'edad',FILTER_VALIDATE_INT,
['options'=>['min_range'=>0,'max_range'=>99]]);
if ($edad===null)
{
echo 'No se ha recibido edad vía POST';
}
elseif ($edad===false)
{
echo 'El dato edad recibido no es un entero o no está entre 0 y 99.';
}
else
{
echo "La edad recibida es $edad";
}
Como puedes observar en la función filter_input se indica:
Primer argumento: de donde se debe extraer el dato (normalmente INPUT_POST o INPUT_GET).
Segundo argumento: nombre del parámetro a extraer.
Tercer argumento (opcional): filtrado o saneado a aplicar. En este caso se aplica el filtrado FILTER_VALIDATE_INT que verifica que el parámetro contenga un número entero. Si no se especifica no hará ningún saneado ni validación.
Cuarto argumento (opcional): parámetros para la validación o saneado indicado, en este caso, el filtrado FILTER_VALIDATE_INT admiten las opciones ['min_range'=>0,'max_range'=>99].
Esta función retornará por defecto:
null si no se ha recibido el dato esperado.
false si el dato recibido no encaja con la validación o saneado.
O bien, el dato en sí. Si el filtrado es de validación (contiene _VALIDATE_) se retorna el dato recibido. Si el filtrado es de saneado (contiene _SANITIZE_) retorna el dato saneado según el filtrado.
Aunque ha muchas validaciones y saneados, vamos a revisar los 5 más usados:
Filtrados de validación y saneado de filter_input más usados
Filtro
Ejemplo de uso
FILTER_VALIDATE_INT : Validación de un número entero.
Permite las opciones: min_range (valor mínimo) y max_range (valor máximo).
Valor retornado en caso de superar la validación: int
$cantidad = filter_input(INPUT_GET, 'cantidad', FILTER_VALIDATE_INT);
if (!is_int($cantidad)) {
echo 'La cantidad indicada no es un número entero o no se ha recibido';
} else {
echo "La cantidad indicada es $cantidad";
}
FILTER_VALIDATE_FLOAT : Validación de un número flotante.
Permite las opciones: min_range (valor mínimo) y max_range (valor máximo).
Valor retornado en caso de superar la validación: float
$precio= filter_input(INPUT_GET, 'precio', FILTER_VALIDATE_FLOAT,['options'=>
['min_range'=>1]]);
if (!is_float($precio)) {
echo 'El precio no se ha recibido o no es válido o es menor de 1';
} else {
echo "El precio recibido es $precio";
}
FILTER_VALIDATE_EMAIL : Validación de un email.
Valor retornado en caso de superar la validación: string
$email= filter_input(INPUT_GET, 'email', FILTER_VALIDATE_EMAIL);
if (!is_string($email)) {
echo 'El email no se ha recibido o no es válido';
} else {
echo "El email recibido es $email";
}
FILTER_VALIDATE_REGEXP : Validación de una cadena contra una expresión regular.
Permite la opción: regexp (expresión regular contra la que validar)
Valor retornado en caso de superar la validación: string
$hora = filter_input(INPUT_POST, 'hora', FILTER_VALIDATE_REGEXP,['options'=>
['regexp'=>'/^([01]\d|2[0-3]):[0-5]\d$/']]);
if (!is_string($hora)) {
echo 'La hora indicada no es correcta o no se ha recibido';
} else {
echo "La hora indicada es $hora";
}
FILTER_SANITIZE_SPECIAL_CHARS: Saneado que escapa caracteres que pueden ser potencialmente peligrosos como `'"<>&` entre otros.
Valor retornado en caso de superar la validación: string
$nombre = filter_input(INPUT_POST, 'nombre', FILTER_SANITIZE_SPECIAL_CHARS);
if (!is_string($nombre)) {
echo 'El nombre no se ha recibido.';
} else {
echo "El nombre saneado es $nombre";
}
En este caso, si por ejemplo, $nombre fuera <B>'nombre'</B> se sanearía generando la cadena <B>'nombre'</B>
Por otro lado, existe también la función filter_var se puede aplicarse sobre el contenido de una variable:
$nombreSinSanear= "<B>'nombre'</B>";
$nombre = filter_var($nombreSinSanear, FILTER_SANITIZE_SPECIAL_CHARS);
if (!is_string($nombre)) {
echo 'El nombre no se ha recibido.';
} else {
echo "El nombre saneado es $nombre";
}
Fíjate que aquí no se indica el origen del dato (ni INPUT_GET ni INPUT_POST) sino que se especifica directamente la variable que contiene el dato.
Por último, y no menos importante, podemos aplicar todos los filtrados de golpe usando filter_input_array. Es muy útil cuando, por ejemplo, esperamos recibir vía POST o GET varios datos de un formulario:
$filtros= [
'cantidad' => [
'filter' => FILTER_VALIDATE_INT
],
'precio' => [
'filter' => FILTER_VALIDATE_FLOAT,
'options' => [
'min_range' => 1
]
],
'email' => [
'filter' => FILTER_VALIDATE_EMAIL
],
'hora' => [
'filter' => FILTER_VALIDATE_REGEXP,
'options' => [
'regexp' => '/^([01]\d|2[0-3]):[0-5]\d$/'
]
],
'nombre' => [
'filter' => FILTER_SANITIZE_SPECIAL_CHARS
]
];
// Filtrar todos los datos recibidos vía POST a la vez
$datos= filter_input_array(INPUT_POST, $filtros);
Como resultado del filtrado se generará un array con los datos $datos['cantidad'], $datos['precio'], etc. Cada dato será null, false o contendrá un valor en función de se ha recibido o no, si no ha superado el filtrado o de si ha superado el filtrado.
Materiales desarrollados inicialmente por el Ministerio de Educación, Cultura y Deporte y actualizados por el profesorado de la Junta de Andalucía bajo licencia Creative Commons BY-NC-SA.
Antes de cualquier uso leer detenidamente el siguenteAviso legal
Actualización de materiales y correcciones menores.
Versión: 03.00.00
Fecha de actualización: 02/06/24
Autoría: Salvador Romero Villegas
Ubicación: Muchos apartados Mejora (tipo 3): Se propone modificar los contenidos de esta unidad para tratar aspectos no tratados de forma eficiente. En esta propuesta se sugiere también cambiar el nombre de la unidad a Introducción a la programación de aplicaciones web en entorno servidor en PHP y cambiar las horas asignadas a dicha unidad a 30.
Los cambios a realizar serían:
- Mejorar la explicación del modelo cliente servidor y el protocolo HTTP: métodos, cabeceras, etc.
- Introducir apartado 4.1 aspectos de php7/8
- Modificar apartado 4.2: Sintaxis alternativa de ifs/for/while
- Tratar en el apartado 4.3.1 la función file_get_contents y readfile.
- Tratar en el apartado 4.3.3 los parámetros “tipados” de php 7.
- Tratar en el apartado 4.3 funciones anónimas y funciones como parámetros.
- Mejorar el apartado 4.4.2, dado que no debería usarse la función “each”.
- Tratar en el apartado 4.4.3 funciones como list(…), extract(…), array_walk, array_filter, etc. Mejorar los apartados 4.4.3 para eliminar elementos del array mientras se recorre.
- Mover el apartado 4.5 a un apartado 5. “datos externos” donde se trate: URL encoding / percent encoding, como recibir datos vía GET, vía POST y como generar URL con datos, como introducir campos ocultos en formularios vía POST, como subir archivos vía POST, checkbox.
- Añadir apartado 6. Filtrado y saneamiento de datos: filter_input, addslashes, strip_tags, htmlentities, expresiones regulares, etc.
- Corregir los anexos VI al XII a cada unidad, para que en todos se haga verificación de datos (isset). En cada anexo debería ir una explicación de que se realiza, y no solo el código. Eso o mover el anexo al apartado correspondiente.
- Mover el apartado de depuración con XDEBUG de la antigua unidad 3 a la unidad 1, preferiblemente a la parte de instalación de XAMPP.
La parte de instalar/configurar xdebug debería actualizarse y documentarse también para XAMPP y netbeans/vsc 12. Debería ser lo primero de esta unidad, es decir, debería moverse al apartado 1.
Ubicación: Sin cambios Mejora (Mapa conceptual): Sin cambios con respecto de la versión anterior
Ubicación: Cambio en el índice de contenidos. Mejora (Orientaciones del alumnado): Cambio en el índice de contenidos.
Versión: 02.01.00
Fecha de actualización: 27/11/19
Autoría: Jesús Manuel Marín Navarro
Ubicación: Toda la unidad Mejora (tipo 2): Cambiar el formato de los ejemplos de código usando resaltado de código por colores y quitando la libretilla. De paso tabularlo bien y repasarlo
Versión: 02.00.00
Fecha de actualización: 01/07/16
Autoría: Julio Gómez López
Ubicación: No especificada. Mejora (tipo 1): Cambios realizados por Sonia Amate
Ubicación: Toda la unidad Mejora (tipo 3): Se unifican las unidades 1 y 2.
Ubicación: Añadir contenidos Mejora (tipo 2): Ampliar la unidad y modificar su nombre. La ampliación consistiría en añadir parte de la unidad 2 a modo de introducción a PHP, para que la tarea1 incluya una sencilla aplicación PHP (menús, formularios básicos y sentencias de control simples). Se ha llegado a esta conclusión debido a la dificultad tan grande que encuentran los alumnos en la tarea2, ya que vienen de una tarea1 que sólo les pide instalaciones (muy sencilla) a una tarea2 que les solicita un aplicación completa.
Versión: 01.01.01
Fecha de actualización: 30/09/14
Autoría: Sonia Amate Garrido
Corrección de erratas y enlaces que no funcionan.
Adición de actividades multimedia que se habían perdido.
Actualización de los contenidos a las nuevas versiones de SW: jdk8, Netbeans 8.0.1