Estamos haciendo una consulta a una tabla, y vemos que la tabla tiene un texto. Pero dicho texto contiene etiquetas HTML que nos molestan o no deberían estar ahí (puede que el valor lo hayamos extraído de un campo WYSIWYG) y cuando vamos a extraer la información nos molesta.
Pero tenemos prisa y tendríamos que modificar o crear un programa y no tenemos tiempo. ¿Qué hacemos? Pues nada, implementar strip_tags() dentro de MySQL y luego pegarnos un baile.
Tabla de contenidos
Preparamos nuestra prueba
Primero vamos a preparar un ejemplo. No os puedo mostrar mi caso real porque contiene información confidencial (qué importante suena). Además, contiene muchos campos y nos sobran la mitad de los datos para el ejemplo; por tanto, vamos a crear una tabla y a meter algunos datos:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE SCHEMA POESIA; CREATE TABLE IF NOT EXISTS `POESIA`.`PRUEBAS` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `Key` VARCHAR(150) NOT NULL, `Value` TEXT NULL, PRIMARY KEY(Id) ) ENGINE = InnoDB; INSERT INTO POESIA.PRUEBAS VALUES(NULL, 'Enlace', '<a href="https://poesiabinaria.net/">Poesía Binaria</a>'); INSERT INTO POESIA.PRUEBAS VALUES(NULL, 'LoremIpsum', '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus.</p>'); INSERT INTO POESIA.PRUEBAS VALUES(NULL, 'Test', '<p>This is a <span>test</span>.</p>'); INSERT INTO POESIA.PRUEBAS VALUES(NULL, 'Header', '<h1 class="cabecera">This is a header</h1>'); |
Veamos el problema
El caso es que cuando hacemos un SELECT a la tabla anterior, nos devolvería esto:
Que no sería gran problema si son sólo estos cuatro campos, pero se vuelve un verdadero marrón cuando son varios miles de campos. Tanto si los tiene que procesar una aplicación o vamos a exportarlos como CSV…
Primero, pensemos
Es lo primero que hay que hacer siempre. Y es que si las etiquetas son siempre las mismas, o en definitiva son un número acotable a primera vista, es decir, sólo vemos <p> y <span> podemos utilizar un simple REPLACE y nos quitamos de líos:
Aunque vemos que no vale para todas las etiquetas, y por desgracia en MySQL no tenemos un método fácil para hacer muchos reemplazos juntos. Podríamos crear una tabla temporal y montar un procedimiento almacenado que guardara valores temporales de los replaces (uno por fila), pero sería muy pesado…
MariaDB y expresiones regulares
En MySQL tampoco hay una forma fácil de reemplazar con expresiones regulares. Y digo fácil, porque siempre es posible crear un módulo en C para MySQL (o bajártelo. Podemos utilizar este, aunque tiene algunos años), pero claro, en un servidor de producción no te vas a poner a compilar nada. Es más, si te pilla el sysadmin no sales vivo.
Pero si utilizas MariaDB, desde la versión 10.0.5 tenemos la función REGEXP_REPLACE() que nos ayudará con ésta y muchas otras cosas…
Pero claro, si no vamos a instalar software en el servidor de producción y estamos utilizando MySQL, no vamos a pasarlo todo a MariaDB. Así que al menos, vamos a crear un procedimiento almacenado que nos quite las etiquetas de un campo de la base de datos y lo podamos llamar para devolver todos los campos filtrados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | DROP FUNCTION IF EXISTS fnStripTags; DELIMITER $$ CREATE FUNCTION fnStripTags( Dirty TEXT ) RETURNS TEXT DETERMINISTIC BEGIN DECLARE iStart, iEnd, iLength int; WHILE Locate( '<', Dirty ) > 0 And Locate( '>', Dirty, Locate( '<', Dirty )) > 0 DO BEGIN SET iStart = Locate( '<', Dirty ), iEnd = Locate( '>', Dirty, Locate('<', Dirty )); SET iLength = ( iEnd - iStart) + 1; IF iLength > 0 THEN BEGIN SET Dirty = Insert( Dirty, iStart, iLength, ''); END; END IF; END; END WHILE; RETURN Dirty; END; $$ DELIMITER ; |
La función es de Peter Brawley, que a su vez hizo un port a MySQL de una función de Robert Davis. Ahora cuando hacemos:
Todo funciona bien.
O podríamos utilizar también esta función:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | DROP FUNCTION IF EXISTS `strip_tags`; DELIMITER $$ CREATE FUNCTION `strip_tags`($str text) RETURNS text BEGIN DECLARE $start, $end INT DEFAULT 1; LOOP SET $start = LOCATE("<", $str, $start); IF (!$start) THEN RETURN $str; END IF; SET $end = LOCATE(">", $str, $start); IF (!$end) THEN SET $end = $start; END IF; SET $str = INSERT($str, $start, $end - $start + 1, ""); END LOOP; END; $$ DELIMITER ; |
Mucho más sencilla y también efectiva (Quién mira Stack Overflow?).
Actualización 16/12/2016: Corregidos algunos tags HTML que no se veían bien.
Pingback: Formas de eliminar etiquetas XML/HTML desde MySQL o MariaDb. strip_tags en MySQL | PlanetaLibre /
Hola, hay alguna manera de meter esta función dentro de PHP?
La función puedes crearla en MySQL, desde el cliente de consola, de algún cliente de escritorio o un phpMyAdmin, y luego desde PHP cuando hagas la query puedes hacer la llamada sin problemas:
SELECT id, `Key`, fnStripTags(Value) AS Value FROM POESIA.PRUEBAS;
De todas formas, si estás usando PHP puedes hacer la petición normal, es decir: SELECT id, `Key`, `Value` FROM POESIA_PRUEBAS;
Y cuando hagas el fetch_array utilizar la función strip_tags() de PHP.
I like it and have bookmarked your website to check for new stuff. If you appreciate word games like Quordle and Wordle but fail to complete crossword puzzles, visit wordle answer right away.
This is a great inspiring article. I am pretty much pleased with your good work.You put really very helpful information.
Scarface Jacket
Your post content is being interested by a lot of people, I am very impressed with your post. I hope to receive more good articles.
Blade Runner Coat