Restringir el acceso a phpMyAdmin

Es importante restringir lo máximo posible el acceso al panel de phpMyAdmin, para eso lo mejor es limitar el acceso a una IP concreta, así aunque tengan los datos de acceso no podrán hacer nada. Para ello existen dos formas:

Mediante el fichero .htaccess situado en el directorio /usr/share/phpmyadmin/ , ponemos las siguientes directrices:
deny from all
allow from 127.0.0.1
allow from XXX.XXX.XXX.XXX #la IP desde la que se tendrá acceso

Luego editamos el fichero /etc/phpmyadmin/apache.conf para indicar la ruta del .htaccess que acabamos de editar, añadiendo las líneas:
Directory /usr/share/phpmyadmin
AllowOverride All
/Directory

Y después reiniciar el servicio de apache para que surja efecto la configuración.

La segunda opción me parece más sencilla y es modificando el fichero de configuración del propio phpMyAdmin, situado en /etc/phpmyadmin/config.inc.php, en el encontraremos un if como este:

if (!empty($dbname)) {

al final de dicho if y antes del i++ que lo finaliza, añadimos el siguiente código:

$cfg['Servers'][$i]['AllowDeny']['order'] = 'deny,allow';
$cfg['Servers'][$i]['AllowDeny']['rules'] = array(
    'deny % from all', 
    'allow % from 127.0.0.1', 
    'allow % from ::1',
    'allow root from localhost',
    'allow root from 127.0.0.1',
    'allow root from ::1',
    'allow root from XXX.XXX.XXX.XXX'  // la IP desde la que se tendrá acceso
    );

Y ya está, sin necesidad de reiniciar el servicio.

Calcular número de coincidencias en una cadena de texto

Montando un buscador, me han pedido que ordene los resultados por el número de coincidencias dentro del texto, esto se puede hacer con MATCH AGAINST pero implica que la búsqueda se centraría en un campo de texto que tenga un índice FULLTEXT, el problema es que en mi caso es una vista y tiene que buscar en una concatenación de campos por lo que queda descartada esta opción.

La solución la he hecho con una función para contabilizar el número de ocurrencias dentro de la cadena.

DELIMITER $$
CREATE FUNCTION `num_coincidencias`(
        texto  text ,
        palabra  varchar(100)
    )
    RETURNS int
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN    
	return ROUND ((LENGTH(texto) - LENGTH( REPLACE ( lower(texto), lower(palabra), ""))) / LENGTH(palabra));
END;
$$
DELIMITER ;


-- y asi podríamos usarlo
select num_coincidencias('bla bla bla saf gsdafg sdfg bla', 'bla') as numero_blas

Funciones cortar cadena y formatear url

Hoy ando liado con un buscador que recupera vía Ajax un JSON con los resultados y los muestra en un desplegable. Dos de las necesidades han sido tener una funciona que convierta una cadena de texto en formato url (quitar símbolos raros, espacios, etc) y la otra ha sido recortar cadenas de texto a una longitud determinada pero sin cortar palabras, así que en vez de usar funciones me ha dado por prototipar dos funciones para los strings de JavaScript.

String.prototype.url = String.prototype.url || function() {
  var from = "ÃÀÁÄÂÈÉËÊÌÍÏÎÒÓÖÔÙÚÜÛãàáäâèéëêìíïîòóöôùúüûÑñÇç ",
      to   = "AAAAAEEEEIIIIOOOOUUUUaaaaaeeeeiiiioooouuuunncc-",
      mapping = {};
  for(var i = 0, j = from.length; i < j; i++ ) mapping[ from.charAt( i ) ] = to.charAt( i );
  var result = [];
  for(var i = 0, j = this.length; i < j; i++ ){
    if( mapping.hasOwnProperty(this[i])) result.push(mapping[this[i]]);
    else result.push(this[i]);
  }
  return result.join('').replace(/[^A-Za-z0-9-]/g,'');
}

String.prototype.cut = String.prototype.cut || function(maxlength) {
    var result = [];
    for(var i = 0, j = this.length; i < j; i++ ) result.push(this[i]);
    if(maxlength >= this.length) return result.join('');
    else if(result[maxlength] == ' ') return result.slice(0, maxlength).join('');
    else{
      for(var i = maxlength, j = 0; i > j; i-- ){
          if(result[i] == ' ') return  result.slice(0, i).join('');
      }
    }
}

// y la forma de usarlas serían:
alert('Esta es la cadena a formatear áéíóú%&/()ñÇ'.url());
alert('Esta es la cadena a cortar'.cut(11));