(2/5) Generación del Webservice en PHP.
Continuando en el lugar dónde nos quedamos en la primera entrada, vamos a pasar al siguiente punto. La generación del Servidor.
“ROADMAP” DE LAS ENTRADAS
- (1/5) Introducción al problema y solución propuesta.
- (2/5) Generación del Webservice en PHP.
- (3/5) Generación de un cliente de Escritorio en Delphi.
- (4/5) Generación del cliente iOS/Android (código compartido)
- (5/5) Publicación en AppStore (Google Play) paso a paso.
Antes de comenzar a generar código, necesitamos generar la Base de Datos, de esta forma podremos ir realizando pruebas sobre ella.
Para la creación de la tabla de «usuario» podéis utilizar la siguiente sentencia:
CREATE TABLE IF NOT EXISTS `agenda` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `nombre` VARCHAR(30) NOT NULL, `apellidos` VARCHAR(40) NOT NULL, `telefono` VARCHAR(9) NOT NULL, `extension` INT(11) DEFAULT NULL, `departamento` VARCHAR(15) DEFAULT NULL, `interno` INT(11) NOT NULL, `email` VARCHAR(40) DEFAULT NULL, PRIMARY KEY (`id`) |
Os adjunto también el siguiente fichero que incluye 100 registros para realizar pruebas. Está generado desde la web GenerateData que me ha parecido fantástica para crear este tipo de datos. Sin duda debe ir a parar a la lista de favoritos. Podéis configurar las columnas de la tabla, los tipos de datos, el número de registros, incluso las máscaras para aquellos campos “no-estándars” de forma muy sencilla. Una vez completado este paso previo, se genera el fichero con las sentencias SQL para ejecutar en la Base de Datos.
Ahora que ya tenemos la/s tabla/s, vamos a entrar en detalle en el Servicio.
Aunque el código es sencillo, lo dividiré en partes, para ir explicando cada una de ellas por separado, aunque como he dicho son bastante evidentes.
(1) Tratamiento de parámetros de entrada.
Está explicado en los comentarios del código, aun así podemos ver que tenemos dos parámetros que podemos pasar a la llamada; NUM y USER.
Una vez que se han determinado los dos parámetros se «prepara» la sentencia SQL.
- USER: Permite buscar un usuario por el campo ID (Clave primária numérica que lo identifica de forma única).
- NUM: Número de usuarios a recuperar desde el WebService. No se tiene en cuenta si se ha especificado el parámetro USER.
NOTA IMPORTANTE: Por problemas con el pluging del blog que muestra código, en los códigos PHP veréis que aparece =v, en realidad debéis sustituirlo por =>. Ya que el plugin si dejo el original no me lo escribe correctamente.
num => Número de registros a devolver. n Número concreto de registros –1 Todos ? Si no se especifica por defecto se devuelven 10 user => Usuario a buscar (id); si no se introduce son todos |
// parámetros ---------------------------------------------------------------- // num : Número de registros a devolver. // n Valor concreto de registros // -1 Todos // ? Si no se especifica por defcto se devuelven 10 // user : Usuario a buscar (id); si no se introduce son todos // --------------------------------------------------------------------------- // 10 valor por defecto $number_of_users = isset($_GET['num']) ? intval($_GET['num']) : 10; // Se ha introducido el parámetro user y es válido? if(isset($_GET['user']) && intval($_GET['user'])) { $user_id = intval($_GET['user']); $query = "SELECT * FROM `-BASEDATOS-`.`agenda` WHERE id=$user_id"; } else { // Se ha especificado -1? $query = "SELECT * FROM `-BASEDATOS-`.`agenda`"; if ($number_of_users == -1) { } else { $query = "SELECT * FROM `-BASEDATOS-`.`agenda` LIMIT $number_of_users"; } } |
(2) Conexión a la Base de Datos.
El código de conexión es bastante estándar y siempre similar. Basta configurar los valores de acceso (usuarios, password, servidor y nombre de la Base de Datos).
// Conectar a la Base de Datos $link = mysql_connect("localhost", "-USUARIO-", "-PASSWORD-") or die('No se ha podido conectar con la Base de Datos.'); mysql_select_db('-BASEDATOS-',$link) or die('No se ha podido acceder a la Base de Datos.'); |
(3) Ejecución de la consulta.
La ejecución de la consulta (con los parámetros que hayamos configurado) y la recogida del resultado se hace de la siguiente manera.
// Lanzar la Query $result = mysql_query($query,$link) or die('Query errónea: '.$query); |
(4) Recuperar el resultado de la consulta y formatearlo.
Definimos un array para recoger el resultado de la consulta. Posteriormente utilizamos un bucle WHILE que recorre los valores devueltos; Utilizando la función mysql_fetch_assoc (que obtiene un registro y posiciona el cursor en el siguiente) recorremos la respuesta y almacenamos los “registros” devueltos en un array.
Al acabar codificamos el array en formato JSON para devolverlo como resultado.
// Crear un array de registros $arrusers = array(); if(mysql_num_rows($result)) { while($user = mysql_fetch_assoc($result)) { $arrusers[] = array('Usuario =v $user); } } // salida en el formato JSON header('Content-type: application/json'); echo json_encode(array('Usuarios' =v arrusers)); |
(5) Finalmente cerramos la conexión.
// desconectar @mysql_close($link); |
Pues bien, con esto ya tenemos nuestro servidor. En este caso no hemos añadido control de seguridad (dependiendo de cómo sea la aplicación, será indispensable), tal vez más adelante podamos extendernos en ese tema.
Para comprobar que funciona, basta con abrir el navegador y escribir alguna de las direcciones que os adjunto debajo y comprobar que el resultado es el que debería ser.
http://neftali.clubdelphi.com/agenda/listado.php
* Devuelve 10 usuarios (cantidad por defecto)
http://neftali.clubdelphi.com/agenda/listado.php?user=10
* Devuelve 1 usuario con ID=10
http://neftali.clubdelphi.com/agenda/listado.php?num=20
* Devuelve 20 usuarios
http://neftali.clubdelphi.com/agenda/listado.php?num=-1
* Devuelve TODOS los usuarios de la tabla
El fichero PHP lo podéis descargar desde aquí (al final también coloco todos los enlaces).
Ya he comentado que hay muchas librerías en PHP que nos pueden ayudar en la programación del servicio. Podéis buscar en Internet y encontraréis mucha información y ejemplos para la autentificación, acceso a Base de Datos, tratamiento de arrays,… No es mi intención extenderme con este tema, aunque sí voy a tratar una en concreto. Me ha parecido especialmente útil, pues está pensada para facilitar el trabajo con WebServices.
Se trata de la librería nuSOAP, que posee herramientas tanto para facilitar el desarrollo del Servidor, como del cliente (yo lo usaré para el primero). nuSOAP es de código abierto y podéis encontrarla en la página de SourceForge. Para usarla, basta con descargar el zip, colocar las librerías en una carpeta donde tenemos nuestro WebService y hacer referencia a ellas en el código.
Lo que voy a hacer, es generar una variante de nuestro servidor utilizando nuSOAP. Además, para ver otra forma de retornar datos, en este caso voy a trabajar con una estructura «compleja» (lo que PHP llama «ComplexType«), aunque internamene sigue siendo un array; De forma que en lugar de retornarlos, los voy a recibir en mi aplicación cliente (Delphi) como una Clase con una estructura similar a esta:
Estructura = class(TRemotable) private FId: integer; FNombre: String; FApellidos: String; FTelefono: String; FExtension: integer; FDepartamento: String; FInterno: integer; FEMail: String; published property Id: integer read FId write FId; property Nombre: String read FNombre write FNombre; property Apellidos: String read FApellidos write FApellidos; property Telefono: String read FTelefono write FTelefono; property Extension: integer read FExtension write FExtension; property Departamento: String read FDepartamento write FDepartamento; property Interno: integer read FInterno write FInterno; property EMail: String read FEMail write FEMail; end; |
Para esta versión voy a definir la función «ConsultaUsuario» que permite buscar un único usuario por su ID (similar a como hacíamos antes) y ConsultaUsuarios que nos permitirá buscar varios usuarios por el campo nombre, de forma que podamos usar un LIKE en la consulta (búsqueda parcial), añadiendo caracteres comodín.
Además veremos cómo la librería nuSOAP nos genera automáticamente el ficherio WSDL de nuestro WebService de forma automática, facilitándole unos datos básicos para ello.
Este fichero WSDL, nos será muy útil a posteriori para poder importarlo desde el propio Delphi, como veremos en próximas entradas.
Añadiremos a nuestro fichero, la siguiente línea para poder utilizar nuSOAP.
//llamada a librería nusoap require_once('lib/nusoap.php'); |
La definición de los tipos compuestos se hace de la siguiente manera; El tipo para un usuario, y a continuación el array de usuarios (Estructura y ArregloDeEstructuras):
// Definir el tipo para un usuario. $servidor -v wsdl -v addComplexType( 'Estructura', 'complexType', 'struct', 'all', '', array( 'Id' =v array('name' =v 'id', 'type' =v 'xsd:integer'), 'Nombre'=v array('name' =v 'nombre', 'type' =v 'xsd:string'), 'Apellidos'=v array('name' =v 'apellidos', 'type' =v 'xsd:string'), 'Telefono'=v array('name' =v'telefono', 'type' =v 'xsd:string'), 'Extension'=v array('name' =v 'extension', 'type' =v 'xsd:integer'), 'Departamento'=v array('name'=v 'departamento','type'=v 'xsd:string'), 'Interno'=v array('name' =v 'interno', 'type' =v 'xsd:integer'), 'EMail'=v array('name' =v 'email', 'type' =v 'xsd:string') ) ); // Definir el array de la estructura $servidor -v wsdl -v addComplexType( 'ArregloDeEstructuras', 'complexType', 'array', 'sequence', 'http://schemas.xmlsoap.org/soap/encoding/:Array', array(), array( array('ref' =v 'http://schemas.xmlsoap.org/soap/encoding/:arrayType', 'wsdl:arrayType' =v 'tns:Estructura[]' ) ),'tns:Estructura'); |
El registro de los métodos en la librería nuSOAP, se hace de la siguiente manera:
// registrar la función de consulta de usuario (por ID) $servidor -v register('ConsultaUsuario', array('id'=v 'xsd:integer'), //tipo de dato entrada array('return'=v 'tns:ArregloDeEstructuras'), //tipo de dato salida $ns, false, 'rpc', //tipo documento 'literal', //tipo codificacion 'Documentacion de consultaUsuarios') ; //documentacion // registrar la funcion de consulta de usuario (por nombre) $servidor -v register('ConsultaUsuarios', array('nom'=v 'xsd:string'), //tipo de dato entrada array('return'=v 'tns:ArregloDeEstructuras'), //tipo de dato salida $ns, false, 'rpc', //tipo documento 'literal', //tipo codificacion 'Documentacion de consultaUsuarios') ; //documentacion |
El resto del fichero es muy similar al que vimos anteriormente.
Lo podéis descargar desde aquí (al final también coloco todos los enlaces).
Para probar el webService podemos acceder a la siguiente dirección:
http://neftali.clubdelphi.com/agenda/listado2.php
Si todo ha ido bien, veremos una imagen como la que aparece a la derecha. Podemos acceder al WSDL generado y ver los métodos.
___________________________________________________________________
ENLACES:
Fichero PHP con el servidor web (primera versión; listado.php)
Librerías nuSOAP (http://sourceforge.net/projects/nusoap/)
Fichero PHP con el servidor web (segunda versión)
LINKS:
Pruebas para testear el primer servidor:
http://neftali.clubdelphi.com/agenda/listado.php
http://neftali.clubdelphi.com/agenda/listado.php?user=10
http://neftali.clubdelphi.com/agenda/listado.php?num=20
http://neftali.clubdelphi.com/agenda/listado.php?num=-1
Pruebas para testear el segundo servidor:
http://neftali.clubdelphi.com/agenda/listado2.php
http://neftali.clubdelphi.com/agenda/listado2.php?wsdl
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Excelente artículo y muy bien explicado, ya quiero ver los siguientes :)
Saludos
Hola el artículo esta muy bien. Ya habia visto muchos ejemplos de este tipo en Internet pero ninguno explica para mi lo mas importante y es explicar como podemos ponerle seguridad a todo esto ya que claro si en vez un ejemplo fuese un ejemplo real todo el mundo que conozca la url tendrá acceso a estos datos. A ver si te animas a poner un artículo que explique como ponerle seguridad a esto.
Muchas gracias.
@Alberto
Hola Alberto. Te agradezco el comentario.
Fíjate que con lo que hay en la entrada ya tenemos la información suficiente para hacerlo.
En el último ejemplo tal vez sea el más directo, pues basta con añadir al procedimiento 2 parámetros más que incluyan user y password, o uno sólo que incluya la API de usuario.
Con eso ya tienes la información necesaria para saber si el usuario es correcto/válido.
El el primero también podrías usar un parámetro API, junto con lo que ya se envían para identificar el usuario.
Un saludo.
Ok, si pasando usuario y password en la URL y luego verificarlo por cada petición puede ser un nivel muy básico de seguridad. Pero pensaba en algo más seguro como uso de par de claves pública y privada o algo así.
Gracias por la respuesta, un saludo.
Hola Neftalí, excelente artículo como siempre.
Hace rato que quería leer un poco sobre webservice con php, pero no había hecho tiempo.
Pero siendo un artículo tuyo, lo leo con gusto.
Suerte
@Crandel
Gracias Crandel.
Espero que os sea útil. Cualquier comentario o sugerencia será bienvenida.
Un saludo.
Hola excelente articulo, agradezco tu publicación de verdad, estoy por realizar una app movil en Rad Studio que extraiga datos del servidor con php, creo que esto me puede ser de gran ayuda, si conoces información extra te lo agradeceria. Saludos desde México.
Hola, con que motor creaste la base de datos? Podria ser con phpmyadmin, usando xampp en la pc servidor? Muy buenos tus aportes. Y me parece mejor hacerlo con php porque para crear un webservice con windows, es reocmendable usar windows server, y para eso hay que saber algo de redes y configuracion. Entonces teniendo xampp ¿como se accederia al localhost desde otra pc?
Saludos desde Argentina
@giuliano
Hola Giuliano.
Efecívamente la Base de Datos es de MySQL y ha sido creada usando el phpMyAdmin (que no es un motor sino un administrador de Bases de Datos para MySQL).
El servidor, es un servidor en internet (el mismo de este blog) estandard.
Si utilizas un servidor en local, instalando XAMP o cualquier otro paquete similar, la configuración deberás hacerla respecto a ese servidor (localhost), por lo demás no creo que exista ningún cambio, mientras las versiones de MySQL y PHP que instales sean compatibles.
Un saludo.
Hola de vuelta Neftalí, me parece que para que el tutorial me sirva deberia hacer mi propio webservice, de hecho estoy desarrollando una aplicacion en delphi para un negocio con distintas sucursales. Y entonces se me ocurre preguntarte a lista de pasos, deberia repetir los pasos solo que para mi aplicacion.
Primero debo tener una consulta en php para cada dato que necesite obviamente.
Luego todo el codigo desde la clase TRemotable va en delphi?
Me puedes decir como se arma la clase? Es enb private los parametros y en published los read y write. En que unidad del cliente en delphi va esto?
@Giuliano
Resisa los ejemplos que he publicado. Ahí está todo el código necesario.
Basta con que lo replique en las unidades tal y como está ahí.
Un saludo.
Muchas gracias, valoro mucho toda esta información… Espero seguir conectado con tu Blog.
@Alveiro Fernandez Leal
Muchas gracias.