![]() |
|
Tasker Para hablar de todo lo relacionado con la aplicación tasker |
«
Tema Anterior
|
Siguiente tema
»
|
Herramientas |
#1
|
||||
|
||||
Crear un WebService con PHP - Iteractuar con una DB SQL en la Web
A raíz de una consulta que hice en este foro http://www.htcmania.com/showthread.php?t=1349091 para mejorar la comunicación con una Base de datos (DB de ahora en adelante) ubicada en Dropbox, usando la app Dropsync, al compañero @WillyWeb se lo ocurrió la ingeniosa idea de montar la DB en un alojamiento web gratuito para acceder a ella desde Tasker.
Como ha sido un hilo en el que se ha trabajado a base de ensayo y error, puede ser un poco engorroso de entender, y dado que el que cometía los errores solía ser yo, me veo obligado moralmente a intentar recoger toda la información para que se pueda entender de forma más sencilla. Antes de continuar, quiero dejar claro que TODO lo que voy a explicar en este tutorial, me lo ha facilitado @WillyWeb, incluso mucho contenido del texto, lo he copiado y pegado literalmente de sus comentarios. 1. PREPARACIÓN DB y SUBDOMINIO Registrarse en una página que ofrezca alojamiento web. Yo particularmente lo he hecho en la página http://www.atspace.com. Crear una DB MySQL. Una vez creada se puede administrar desde phpMyAdmin. En mi caso he creado una DB con una tabla denominada goleadores, con la siguiente estructura: goles (INTYINT) jugador (VARCHAR) usuario (VARCHAR) Crear un subdominio. Panel de control > Herramientas de alojamiento > Gestor de dominios > Crear un Subdominio Gratuito. Selecciona uno de los dominios base que te ofrecen y escribe en la casilla una palabra que te guste. La idea es componer una dirección web de esta forma... http://miweb.atspace.cc Esa será la dirección base (el servidor) de la URL del WebService. 2. CREAR UN WEBSERVICE CON PHP La información se ha obtenido en esta página: http://tosblama.blogspot.com.es/2015...e-con-php.html y las modificaciones necesarias para conseguir hacerlo funcionar, las ha aportado @WillyWeb. Para entender como funciona, recomiendo entrar en la página, ya que está mucho mejor explicado de lo que lo pueda hacer yo. Básicamente el sistema se basa en dos archivos. Un PHP (webservice.php) con el código del WebService y un XML (opciones.xml) con las consultas SQL que usa el proyecto. A continuación copio el código PHP que yo he utilizado, pero antes, es importante recalcar que en necesario cambiar la línea 56 e indicar los datos correspondientes a vuestra DB. Como al copiar el código no se han mantenido los números de las líneas, puede resultar más complicado localizarla, así que busca la palabra "CONTRASEÑA" en el código y tómalo como referencia. [PHP]<?php // Recoger parámetros de entrada. Se permite GET y POST $paramOpcion = $_REQUEST['opcion']; $paramLista = $_REQUEST['listaParametros']; $formato = strtolower($_REQUEST['format']) == 'xml' ? 'xml' : 'json'; // Obtener consulta SQL a ejecutar $sql = getSQL($paramOpcion); $sql = aplicarParametrosSQL($sql,$paramLista); // Lanzar consulta a la base de datos if ($sql == '') die ('Opcion incorrecta'); else { $datos = getArrayDatos($sql); echo formatData($datos,$formato); } // Dado un nombre de opción, buscar en el xml su SQL correspondiente function getSQL($nombreOpcion) { $xmlOpciones = simplexml_load_file('opciones.xml'); $sql = ""; foreach ($xmlOpciones->opcion as $opcion) { $nombre = $opcion->nombre; if ($nombre == $nombreOpcion) { $sql = $opcion->SQL; break; } } return $sql; } // Aplicar parámetros de la sentencia SQL function aplicarParametrosSQL($sql, $listaPametros) { if ($listaPametros != '') { $arrParam = explode(':',$listaPametros); for ($i=0; $i<count($arrParam); $i++) { $nomParam = '#PARAMETRO_'.($i+1).'#'; $valor = $arrParam[$i]; $sql = str_replace($nomParam, $valor, $sql); } } return $sql; } function getArrayDatos($sql) { $db = mysqli_connect('fdb17.atspace.me','codigo_promunio ','CONTRASEÑA','codigo_promunio') or die('No se pudo conectar con la base de datos'); //mysql_select_db('2454802_promunio',$db) or die('No se pudo seleccionar la base de datos.'); $resul = mysqli_query($db,$sql) or die('Consulta incorrecta: '.$sql); /* create one master array of the records * $datos = array(); if(mysqli_num_rows($resul)) { while($row = mysqli_fetch_assoc($resul)) { $datos[] = $row; } } /* disconnect from the db * mysqli_close($db); /* Return data array * return $datos; } function formatData($data,$format='json') { if($format == 'json' || $format == 'jsonp') { header('Content-type: application/json'); if (isset($_REQUEST['callback'])) // Peticiones ajax return $_REQUEST['callback'].'('.json_encode($data).')'; else return json_encode($data); } else { header('Content-type: text/xml'); $xml = new SimpleXMLElement('<response/>'); return array2xml($data, $xml); } } function array2xml($array, $xml = false) { if($xml === false) { $xml = new SimpleXMLElement('<root/>'); } foreach($array as $key => $value) { if(is_array($value)) { //array2xml($value, $xml->addChild($key)); array2xml($value, $xml->addChild('item')); } else { $xml->addChild($key, htmlspecialchars($value)); } } return $xml->asXML(); } ?>[/PHP] Y a continuación pongo el código XML. Código:
<?xml version="1.0" encoding="utf-8" ?> <OpcionesDisponibles> <opcion> <nombre>listajugadores</nombre> <SQL>SELECT goles,jugador,usuario FROM goleadores</SQL> </opcion> <opcion> <nombre>insertar</nombre> <SQL>UPDATE goleadores SET goles = (goles+1) WHERE jugador LIKE "MESSI"</SQL> </opcion> </OpcionesDisponibles> En <nombre> se puede poner lo que queráis pero recomiendo usar términos descriptivos del propósito de la sentencia SQL. Si has creado una sentencia para listar los goles de un jugador yo usaría 'golesjugador'. Si tienes otra para obtener el listado de todos los jugadores podrías usar 'listajugadores'. Y así con todas las demás sentencias necesarias. La palabra que pongamos entre las etiquetas <nombre>, será la que debamos usar en la acción HTTP Get, para ejecutar la sentencia SQL deseada. Eso se detallará más adelante. Evidentemente en el campo <SQL> hay que poner la sentencia SQL, pero con un pequeño matiz. Si esa sentencia tiene un parámetro que pueda ser variable (como el nombre del jugador) debes poner '#PARAMETRO_1#' en su lugar (mira la línea 9 del XML del siguiente enlace (https://pastebin.com/jbWf708h). Si la sentencia tiene más de un parámetro de ese tipo pones '#PARAMETRO_1#' y '#PARAMETRO_2#'. Y así con todos los parámetros que necesite la sentencia. 3. DE VUELTA AL PANEL DE CONTROL DEL ALOJAMIENTO (HOSTING) Una vez creados los archivos webservice.php y opciones.xml como se ha explicado en el punto anterior, hay que copiarlos a la raíz de la DB, utilizando un gestor de archivos que se muestra al hacer click sobre la etiqueta "Administrar archivos". 4. TASKER Ejecutamos una acción HTTP Get, e indicamos en la pestaña Servidor:Puerto lo siguiente: Código:
http:/Nombre del subdominio/webservice.php?opcion=nombreopción&format=json. Código:
http:/pruminio.atspace.eu/webservice.php?opcion=listajugadores&format=json Seguramente os hayáis dado cuenta que el nombre de opción listajugadores es el que usado en el código xml. <nombre>listajugadores</nombre> Como ya he comentado, se usa para determinar que sentencia SQL vamos a ejecutar. Lo que devuelve el WebService es un objeto JSON y en mi caso queda así, y queda alojado en la variable incorporada %HTTPD [{"goles":"7","jugador":"RONALDO","usuario":"SANDRO "},{"goles":"8","jugador":"MORATA","usuario":"BIFU "}, {"goles":"9","jugador":"LUIS SUAREZ","usuario":"RICHY"},{"goles":"15","jugador" :"MESSI","usuario":"RAUL"}] También podemos abrir el enlace desde el navegador, y deberemos de obtener el mismo resultado. A día de hoy, todavía no he logrado obtener únicamente el contenido de los campos de la tabla, pero según indica WillyWeb, es facil de procesar con Javascript. En cuanto tenga más información la añadiré. SOLUCIÓN: http://www.htcmania.com/showthread.php?t=1349091&page=4 La acción "Consulta SQL" devuelve el resultado en un array. Cada elemento del array es una fila del resultado. Cada elemento/fila contiene los valores de las columnas separados por el símbolo que pongamos en el campo correspondiente de la acción. Lo que el WebService devuelve es un JSON compuesto por un array de objetos. Cada elemento del array es una fila del resultado. Cada elemento/fila contiene los valores de las columnas en un objeto con parejas "nombre_columna : valor" separadas por comas. En un vistazo rápido vemos que "casi" es lo mismo, pero sobra lo de los objetos y los nombres de las columnas. Pues quitamos lo que sobra y listo... Código:
ConvierteJSONenArrayLocal (999) A1: HTTP Get [ Servidor:pruminio.atspace.eu Ruta:webservice.php Atributos:opcion=listajugadores ] A2: JavaScriptlet [ Código://Convierte JSON a un array local json=global('HTTPD'); json=json.replace(/"goles":/g,"") json=json.replace(/"jugador":/g,"") json=json.replace(/"usuario":/g,"") json=json.replace(/"listado":/g,"") json=json.replace(/"/g,"") //dos comillas dobles json=json.replace(/{|}/g,'"') //comilla simple + doble + simple var array=[] array=JSON.parse(json) A3: Flash [ Texto:%array(#) registros ] Para guardar el resultado en un array global en vez de en un array Global, hay que utilizar este otro código, que funciona perfectamente a pesar de que la documentación de Tasker indica que no se pueden crear arrays globales desde JS Código:
ConvierteJSONenArrayGlobal (666) A1: HTTP Get [ Servidor:pruminio.atspace.eu Ruta:webservice.php Atributos:opcion=listajugadores ] A2: Array Clear [ Matriz de Variables (array):%MiArray ] A3: JavaScriptlet [ Código://Convierte JSON a un array global json=global('HTTPD'); json=json.replace(/"goles":/g,"") json=json.replace(/"jugador":/g,"") json=json.replace(/"usuario":/g,"") json=json.replace(/"listado":/g,"") json=json.replace(/"/g,"") //dos comillas dobles json=json.replace(/{|}/g,'"') //comilla simple + doble + simple json=JSON.parse(json) for(ind=0;ind<json.length;ind++) { nom="MiArray"+(ind+1) setGlobal(nom,json[ind]) } A4: Flash [ Texto:%MiArray(#) registros ] var array=[] array=JSON.parse(json) En la versión para array global el nombre se define en esta otra línea... nom="MiArray"+(ind+1) *Hay que tener en cuenta que ese nombre es el mismo que hay que poner en la acción "Array Clear" que va justo antes de la acción JavaScriptlet. Funcionamiento de este JavaScriptlet paso a paso... Código:
//Convierte JSON a un array global json=global('HTTPD') json=json.replace(/"goles":/g,"") json=json.replace(/"jugador":/g,"") json=json.replace(/"usuario":/g,"") json=json.replace(/"listado":/g,"") json=json.replace(/"/g,"") //dos comillas dobles json=json.replace(/{|}/g,'"') //comilla simple + doble + simple json=JSON.parse(json) for(ind=0;ind<json.length;ind++) { nom="MiArray"+(ind+1) setGlobal(nom,json[ind]) } Código:
[{"goles":"7","jugador":"RONALDO","usuario":"SANDRO "},{"goles":"8","jugador":"MORATA","usuario":"BIFU "}, {"goles":"9","jugador":"LUIS SUAREZ","usuario":"RICHY"},{"goles":"15","jugador" :"MESSI","usuario":"RAUL"}] Esta línea... json=global('HTTPD') ...pasa la variable global %HTTPD a JS usando la función global(), que es un añadido de Tasker. El valor queda almacenado en la variable "json". Este bloque... json=json.replace(/"goles":/g,"") json=json.replace(/"jugador":/g,"") json=json.replace(/"usuario":/g,"") json=json.replace(/"listado":/g,"") ...quita los nombres de los campos. Puedes añadir tantas líneas como necesites. Esta línea... json=json.replace(/"/g,"") //dos comillas dobles ...quita todas las comillas dobles. Esta línea... json=json.replace(/{|}/g,'"') //comilla simple + doble + simple ...cambia las llaves (abrir y cerrar) por una comilla doble. Después de pasar por esas líneas el JSON inicial debería tener esta pinta... Código:
["7,RONALDO,SANDRO","8,MORATA,BIFU","9,LUIS SUAREZ,RICHY","15,MESSI,RAUL"] Si queremos el resultado en un array global pondremos esta línea... json=JSON.parse(json) ...con la que convertimos ese JSON "modificado" en un array haciendo uso del "parser" JSON de JavaScript. Y luego pondremos este bucle... for(ind=0;ind<json.length;ind++) { nom="MiArray"+(ind+1) setGlobal(nom,json[ind]) } ...que hace lo que se supone que no se puede hacer, pasar un array global de JS a Tasker. El bucle recorre cada elemento del array "json", crea un nombre para cada elemento del array global de Tasker con su número de índice corregido (uno más que en JS) y pasa el valor del array a esa variable de Tasker usando su función añadida setGlobal(). Si quisieramos el resultado en un array local deberíamos poner esto otro... var array=[] array=JSON.parse(json) El matíz está en esa línea "var array=[]" que define la variable "array" como un array local para la tarea Tasker que contiene el JavaScriptlet. Última edición por Rsc Día 29/10/17 a las 13:21:19 |
Los siguientes 4 usuarios han agradecido a Rsc su comentario: | ||
|
#2
|
Hola, he leido tu trabajo y me parece aparte de interesante muy ingenioso he tenido la oprtunidad de que has compartido un video con lo que hace tu tabla de goleadores y me parece asombroso.
quiero iniciar una idea, donde llevar en una tabla similar a la tuya pero donde se lleve un control de personas que te deban y cuanto te han abonado pero no se donde empezar. tengo la idea en la cabeza la cual describo: terminar el proyecto exportando a APK donde cada usuario (cliente y admon) tenga la app por ejemplo WillyWeb ![]() cambe mencionar que cada vez que el me de $$$ me gustaria ver que posibilidad hay de agregar una firma digital con esta idea: así cada vez que me pague puede haber un respaldo de que recibí dinero. ¿crees poder orientarme? ![]() |
#3
|
|
Cita:
Saludos! y gracias por tomarse el tiempo de leerme. |
#4
|
||||
|
||||
Cita:
Cita:
Cita:
Además de ese dato, también esta bien que tengas en cuenta, cuanto almacenamiento requiere cada uno de los datos. Por ejemplo, antes has usado INT... desconozco lo que te tienen que pagar, pero si supera los 10 dígitos, quizás es mejor que en vez de hacer una aplicación para controlarlo, te vayas a sus casas a buscarlos. Lo que te quiero decir es que INT permite números enteros de hasta 10 dígitos y ocupa 8 bytes, y por ejemplo SMALLINT, permite números enteros de hasta 5 dígitos, y ocupa 2 bytes. Con float y double pasa algo parecido, así que mira cual te conviene más. Realmente no se si esto se nota a la hora de interactuar con la DB para que vaya más fluida o no... pero supongo que algo si que afectará, y luego se agradece que los cambios en la app se realicen lo más rápido posible. |
#5
|
|
Cita:
en cuanto al proyecto ¿crees poder apoyarme en validar que hacer para iniciar un nuevo tema? de antemano gracias por tu respuesta! |
#6
|
||||
|
||||
Cita:
Empieza por seguir paso a paso, todo el resumen que dejé, e intenta apoyarte también en el hilo donde surgió todo https://www.htcmania.com/showthread.php?t=1349091 Por cierto, cuando finalices el proyecto, acuérdate de poner alguna condición, para que los que te deben pasta no puedan hacer modificaciones en la base de datos. |
Gracias de parte de: | ||
#8
|
|
Cita:
por lo que puedo apreciar no es por motivo de contraseña que no este conectando podrias orientarme que esta mal? ![]() de hecho en la sentencia del webservice.php la linea 56 la modifique como mencionan: ('servidor','usuario','password','ba se_datos') de antemano gracias por tomarte el tiempo de leer esto. ![]() |
#9
|
||||
|
||||
No sé ve lo que te devuelve el servidor
|
#10
|
precisamente es lo que me devuelve el servidor... entiendo que si no conectara por la contraseña o usuario el error seria diferente:
![]() |
#11
|
||||
|
||||
Creo que vas a tener que copiar el php y el XML para que podamos ayudarte a localizar el error
|
#12
|
|
Cita:
¿De verdad necesitas un WebService para esto? ![]() El WebService que hicimos en su momento era para compartir una base de datos entre varios usuarios (ese es el principal propósito de un WebService) pero en tu caso no parece imprescindible. Las anotaciones de lo que te han pagado las haces tú y sólo tú. Si quieres que el "deudor" tenga constancia de lo que todavía te debe le haces un justificante cada vez que te pague y tema resuelto. Otra cosa es que quieras que el deudor pueda "ver" en cualquier momento lo que te debe. Y hasta en ese caso tampoco necesitas montar una aplicación online. Una simple hoja de cálculo compartida te puede solucionar la papeleta. Tú eres el propietario del archivo y haces anotaciones y al "cliente" le das acceso de consulta para que vea tus anotaciones. Ese sistema que propones no parece que sea para lo que pretendes hacer. |
Gracias de parte de: | ||
#13
|
|
Cita:
Mi intención es prepararle una aplicación (creada con Tasker) donde pueda entrar con usuario y contraseña ya que no solo es un deudor son varios entonces el control seria unitario... ya que con hoja de excel compartida tendría que hacer una por usuario... ![]() en cuanto a lo de la firma digital que etiquetaste abajo... era una idea para que tenga una constancia de la parte del deudor que en tal fecha me pago y quede evidencia (esto creo que es muy avanzado por lo que menciona @Rsc entonces me quedaría con la primer idea... Aunado que lo quiero tomar como practica para aprender lo que bien enseñan por aquí... se me hace interesante la interacción online. gracias por tu tiempo y tu opinión es bienvenida, si bien mencionas que definitivamente no es necesario. también lo tomo en cuenta. ![]() |
Gracias de parte de: | ||
#14
|
|
Cita:
[PHP]<?php // Recoger parametros de entrada. Se permite GET y POST $paramOpcion = $_REQUEST['opcion']; $paramLista = $_REQUEST['listaParametros']; $formato = strtolower($_REQUEST['format']) == 'xml' ? 'xml' : 'json'; // Obtener consulta SQL a ejecutar $sql = getSQL($paramOpcion); $sql = aplicarParametrosSQL($sql,$paramLista); // Lanzar consulta a la base de datos if ($sql == '') die ('Opcion incorrecta'); else { $datos = getArrayDatos($sql); echo formatData($datos,$formato); } // Dado un nombre de opcion, buscar en el xml su SQL correspondiente function getSQL($nombreOpcion) { $xmlOpciones = simplexml_load_file('opciones.xml'); $sql = ""; foreach ($xmlOpciones->opcion as $opcion) { $nombre = $opcion->nombre; if ($nombre == $nombreOpcion) { $sql = $opcion->SQL; break; } } return $sql; } // Aplicar parametros de la sentencia SQL function aplicarParametrosSQL($sql, $listaPametros) { if ($listaPametros != '') { $arrParam = explode(':',$listaPametros); for ($i=0; $i<count($arrParam); $i++) { $nomParam = '#PARAMETRO_'.($i+1).'#'; $valor = $arrParam[$i]; $sql = str_replace($nomParam, $valor, $sql); } } return $sql; } function getArrayDatos($sql) { $db = mysqli_connect('fdb19.atspace.me','2657215_contado r','a123456789','contadormx') or die('No se pudo conectar con la base de datos'); //mysql_select_db('2657215_contador',$db) or die('No se pudo seleccionar la base de datos.'); $resul = mysqli_query($db,$sql) or die('Consulta incorrecta: '.$sql); /* create one master array of the records * $datos = array(); if(mysqli_num_rows($resul)) { while($row = mysqli_fetch_assoc($resul)) { $datos[] = $row; } } /* disconnect from the db * mysqli_close($db); /* Return data array * return $datos; } function formatData($data,$format='json') { if($format == 'json' || $format == 'jsonp') { header('Content-type: application/json'); if (isset($_REQUEST['callback'])) // Peticiones ajax return $_REQUEST['callback'].'('.json_encode($data).')'; else return json_encode($data); } else { header('Content-type: text/xml'); $xml = new SimpleXMLElement('<response/>'); return array2xml($data, $xml); } } function array2xml($array, $xml = false) { if($xml === false) { $xml = new SimpleXMLElement('<root/>'); } foreach($array as $key => $value) { if(is_array($value)) { //array2xml($value, $xml->addChild($key)); array2xml($value, $xml->addChild('item')); } else { $xml->addChild($key, htmlspecialchars($value)); } } return $xml->asXML(); } ?>[/PHP] y el xml aun lo estoy modificando pero solo ocupo consultar: Código:
<?xml version="1.0" encoding="utf-8" ?> <OpcionesDisponibles> <opcion> <nombre>listac</nombre> <SQL>SELECT Fecha,Compra,Total,Abono,Debe FROM contadormx</SQL> </opcion> </OpcionesDisponibles> ![]() |
#15
|
||||
|
||||
Parece que el error está en la línea en la cual indicas los parámetros relativos a tu base de datos.
Tendría que quedar así; ('servidor','usuario','password','ba se_datos') Comprueba que los datos de tu código, coinciden con con los parámetros que hay que pasarle. En mi caso usuario, coincide con base_datos, no recuerdo si coincidió por defecto, o porque yo personalmente le puse el mismo nombre. Suponiendo que ese fuese el error, la línea referida del código php, tendría que quedar así; Cita:
|
Los siguientes 2 usuarios han agradecido a Rsc su comentario: | ||
#16
|
|
Cita:
![]() |
#17
|
||||
|
||||
Copia la URL, el código XML con la opción (Consulta SQL) que estés utilizando, y lo que te devuelve con el error incluido.
|
Gracias de parte de: | ||
#18
|
|
Cita:
url: http://contadormx.atspace.cc/webserv...ac&format=json Código XML: Código:
<?xml version="1.0" encoding="utf-8" ?> <OpcionesDisponibles> <opcion> <nombre>listac</nombre> <SQL>SELECT Fecha,Compra,Total,Abono,Debe FROM contadormx</SQL> </opcion> </OpcionesDisponibles> gracias ![]() |
#19
|
||||
|
||||
Parece que el error está en la consulta SQL
Cita:
Prueba a corregirlo y nos cuentas. |
Los siguientes 2 usuarios han agradecido a Rsc su comentario: | ||
|
#20
|
|
Cita:
La tabla creada la realice así: ContadorMx y la escribi: contadormx el uso de la MAYUCULAS que use tiene que ser tal cual el del nombre de la Tabla. Seguiré avanzando, cualquier cosa mantendré informados. Saludos y gracias por el apoyo a todos! ![]() |
Los siguientes 2 usuarios han agradecido a Mx WaR HaBiB su comentario: | ||
Respuesta |
![]() |
||||||
|
«
Tema Anterior
|
Siguiente tema
»
|
|
Hora actual: 20:56:29 (GMT +2)
HTCMania: líderes desde el 2007