Añadir columna a una tabla en MySQL (y MariaDB)

Una pequeña entrada sobre SQL básico, porque me lo han preguntado hace un rato, así que aprovecho para contestar por aquí.

Muy bien, tienes una tabla y quieres añadir una columna o campo que se te olvidó al crearla, o que por cambios en la aplicación necesitas añadir. Si te vas a la guía de referencia de MySQL puedes leer todas las posibilidades que tienes, pero como se puede hacer largo y pesado mejor unos ejemplillos de código rápidos aquí:

La sintaxis básica es ALTER TABLE nombreDeLaTabla add nombreDeLaColumna tipodedatos(longitud)

ALTER TABLE tabla1 add colNueva varchar(2);

Vamos con más ejemplos. Por ejemplo, queremos que la columna nueva no permita valores nulos (ojo, esto puede dar problemas si la tabla ya tiene valores añadidos):

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL;

O por ejemplo queremos colocarlo específicamente después de una columna que ya existe (si no especificamos nada, añadirá la nueva al final):

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL AFTER col1;

O al revés, queremos insertarla antes de una columna concreta:

ALTER TABLE tabla1 add colNueva varchar(2) NOT NULL BEFORE col2;

También puede venir con un valor por defecto:

ALTER TABLE tabla1 add colNueva varchar(35) DEFAULT 'Ni de ajo';

¿Y si en vez de una quieres insertar varias? Sin problema:

ALTER TABLE tabla1 add (
colNueva varchar(2) NOT NULL,
colMásNueva tinyint(1) default 0
)

Como ves, es sencillo. SQL básico. Como siempre, todo lo aplicable en MySQL lo es también en MariaDB.

Convertir una respuesta xml en un objeto de PHP

Por defecto PHP, desde la versión 5.1.2, incorpora la extensión SimpleXML y la trae habilitada (en versiones anteriores es necesario usar –enable-simplexml para activar esta extensión en el momento de compilar). Dicha extensión incluye una serie de herramientas que nos permiten trabajar fácilmente con XML.

No es extraño que si tenemos que comunicarnos con un api externa esta nos devuelva una respuesta en XML, que es un formato universal que puede ser trabajado con casi cualquier lenguaje (otra posibilidad muy habitual es JSON). SimpleXML nos permite recoger esta respuesta, convertirla en un objeto y trabajar con el mismo sin mucha complicación.

En caso de querer recoger una respuesta de otra página, el método a usar sería simplexml_load_string():

$objetoxml = simplexml_load_string($respuestaApi);

Con esto ya tenemos un objeto fácil de recoger. Vamos a imaginar que el objeto que recibimos es tal que así:

<response>
   <requestid>A16</requestid>
   <requests>3</requests>
   <status>error</status>
   <error>
      <code>106</code>
      <message>Request expired</message>
   </error>
</response>

Una notificación de un error conectando con un servicio externo (de hecho, es una copia de un mensaje de error del api de Calameo). Ahora imaginemos que queremos recoger este mensaje de error y mostrárselo por pantalla al usuario. ¿Qué hacemos? Pues muy facilito:

//primero convertimos el xml a objeto
$objetoxml = simplexml_load_string($respuestaApi);

//luego comprobamos que sea un mensaje de error:
if (isset($objetoxml->error))
{
    //e imprimimos
    echo 'Error:'.$objetoxml->error->code.': '.$objetoxml->error->message;
}

Trabajar con el objeto SimpleXML es cosa fácil: Cuando quieres acceder a un elemento basta ir moviéndose como si accedieras a las propiedades o métodos de un objeto. Es decir abuelo->padre->hijo. ¿Que hay varios elementos con la misma etiqueta? Sin problema, las etiquestas se convierten en objetos iterables y accesibles, por lo que puedes recorrerlos recurriendo a los mecanismos básicos de iteración (bucle foreach, por ejemplo).

¿Y para acceder a los atributos? En el ejemplo del xml no hay, pero imaginemos que en lugar del anterior la cosa fuera así:

<response>
   <requestid>A16</requestid>
   <requests>3</requests>
   <status>error</status>
   <errors>
      <error>      
        <message code="106">Request expired</message>
      </error>
      <error>      
        <message code="401">File not found</message>
      </error>
   </error>
</response>

Ok, ahora tendrías que acceder a los atributos, y de paso podríamos ver un ejemplo de iteración. A los atributos se accede como si fuesen elementos de un array, usando como índice su nombre:


//primero convertimos el xml a objeto
$objetoxml = simplexml_load_string($respuestaApi);

//luego comprobamos que sea un mensaje de error:
if (isset($objetoxml->errors))
{
    foreach(objetoxml->errors->error as $error)
    {
        echo 'Error:'.$error['code'].': '.$error->message;
    }
}

Un par de notas más:

  • Para usar el texto de un elemento en una comparación o pasarlo a una función como string hay que forzar la conversión a cadena de texto haciendo un cast con (string)
  • Para acceder a un elemento cuyo nombre viole las convenciones para nombres de objeto de PHP hay que recurrir a encapsular el nombre del elemento dentro de un par de llaves y comillas simples.
  • En este caso hemos hablado de recoger una respuesta de un servicio externo, pero SimpleXML nos permite también recoger un xml desde un archivo con simplexml_load_file().

Y si necesitáis convertir el elemento en un array (en su momento me tocó) ya tratamos ese punto con anterioridad.

Enviar mails con PHPMailer

¿Quieres enviar un mail desde una página de php? Ya sea al usuario, al administrador… la idea es que tu web sea capaz de enviar correos a una dirección de e-mail. Aunque existe la función mail() en php, desde hace tiempo la opción más utilizada es la clase PHPMailer que puedes descargar desde aquí.

Una vez descargado la cuestión es ¿cómo hago para enviar un correo? Bueno, todo es cuestión de configurar un script tal que así:

/*Lo primero es incluir la clase en vuestro php*/
include("metedLaRutaDondePusisteisLaCarpeta/class.phpmailer.php");

/*Obviamente, generáis el mensaje*/
$mensaje="Blablablablabla********"; //puede incluir html, podéis cogerlo de un form...

/*Ahora toca crear una variable de la clase phpmailer*/
$NewMail=new PHPMailer();

/*Y luego añadís todos los parámetros que esta necesita para el envío*/
$NewMail->Host = "localhost"; //El host donde tengáis alojado el correo
$NewMail->From = "correo@del.remitente"; //El correo del remitente
$NewMail->FromName = "Nombre remitente"; //Nombre del remitente
$NewMail->Subject = "asunto"; //El asunto del correo
$NewMail->AddAddress("emailalqueseenvía@asdsd.com","Nombre");//La dirección del receptor del mail
$NewMail->Body = $mensaje; //El mensaje
$NewMail->AltBody = "Relleno Relleno; //relleno

/*Y finalmente llamáis al método de envío*/
$NewMail->Send();

Hay más opciones de configuración, pero esto es lo básico. Entre otras cosas podéis configurar el protocolo de envío (POP, SMTP…), etc… pero con esto pelao debería ir funcionando. Si no, buscáis la documentación y ya profundizáis.

Procesar un formulario con PHPFox (operaciones CRUD)

En los últimos tiempos he estado trabajando con el CMS PHPFox para creación de redes sociales. He de decir que la documentación sobre el mismo es, en el mejor de los casos ambigua y en el peor insuficiente, teniendo que recurrir muchas veces al «voy a ver cómo está hecho aquí, y si se parece lo copio». Por cierto, si no sabes inglés date por jodido que la documentación está toda en la lengua de los inmortales bardos Poe, Shakespeare y Lemmy.

Podría empezar por lo básico, pero está más o menos bien explicado en su documentación (a la que sólo podrás acceder si tienes una cuenta de usuario… de pago, of course), donde te explican más o menos cómo crear tu primer módulo. Por desgracia, tras explicar lo más básico (lo más de lo más, porque esto no está explicado…) se quedan ahí, y no profundizan para acercarse al tema de la persistencia de datos ni a las operaciones CRUD (Create, Read, Update and Delete).

Para el acceso a la base de datos necesitarás al menos tres archivos, ya que PHPFox trabaja sobre la arquitectura MVC: un template (será la vista), un controller (controlador) y un service (el modelo).

Si habéis leído la documentación básica de phpfox ya sabréis en qué carpeta tenéis que meter cada archivo y cómo nombrarlo. Ahora os adjunto un ejemplo de como sería el código del template, seguido de su explicación:

<form method="post" action="{url link='phpfoxexperiment/form'}">
  <input type="number" name="val[orden]" id="orden" placeholder="orden"/>
  <br/>
  <input type="text" name="val[texto]" id="texto" placeholder="texto"/>
  <br/>
  <input type="submit" value="Add" class="button" name="val[add]" /> 
</form>

Por partes; en el action hemos usado esa variable porque así generará directamente un link a nuestra dirección seguido de ese directorio. En cuanto al nombre de los campos como «val[loquesea]» tiene también una explicación: se considera buena práctica no usar en PHPFox las variables de entorno $_GET y $_POST para recoger los datos de los formularios, en lugar de eso utilizamos el método getArray de la clase request, como verás en el ejemplo e abajo del php.

<?php 

class Phpfoxexperiment_Component_Block_Form extends Phpfox_Component 
{     
    public function process() 
    {         	
	if (($aVal = $this->request()->getArray('val'))) // getArray() nos permite recoger indistintamente valores $_GET y $_POST 
	{  
		  		 
		if(isset($aVal['add']) && !empty($aVal['add'])) // miramos si se ha pulsado el botón enviar 
		{  
		    if(isset($aVal['orden']) && !preg_match("/^[[:digit:]]+$/", $aVal['orden'])) //esto es una validación de los datos por expresión regular
		    {
			$this->url()->send('phpfoxexperiment.basic', null, 'Error'); //en caso de que los datos no sean correctos avisa a una página de error
		    }
		    else{
			if (Phpfox::getService('phpfoxexperiment')->add($aVal)) // llamamos al servicio para guardar los datos
			{ 				 
			    $this->url()->send('phpfoxexperiment.basic', null, 'Added with success');	//en caso de éxito lo comunicamos			 
			}else{
     			     $this->url()->send('phpfoxexperiment.basic', null, 'Error'); //en caso de error también
			}
		    }
		  }
		}         		 
	} 
}
?>

Como ves en el ejemplo se invoca al método add del servicio phpfoxexperiment. Ese método es el que hará la inserción en la base de datos. No se trata de un método del sistema, sino de uno creado por mi dentro del servicio. Aquí el código del mismo

<?php 
  
class Phpfoxexperiment_Service_Phpfoxexperiment extends Phpfox_Service  
{ 
    public function getData($iUser)
	
    { 
        return $this->database()->select('e.aescrypt') 
            ->from(Phpfox::getT('experiment'), 'e')
	    ->where('e.orden < 60 and user = '.$iUser)             
            ->execute('getRows'); 
    }
	public function add($aVal){ 
     
        $this->database()->insert( 
          Phpfox::getT('experiment'), 
          array(
            'user'=>Phpfox::getUserId(),
            'orden'=>$aVal['orden'], 
            'aescrypt'=>$aVal['texto'] 			
          ) 
        ); 
	return true;

    } 
} 
  
?>

En cambos casos accedo a la base de datos (MySQL) a través de los métodos de la clase database() de phpfox, que teóricamente ya implementa seguridad contra inyección sql y otros posbiles ataques. El return del final servirá para confirmar que la transacción se ha realizado. En el primer ejemplo se recuperar unos datos (teniendo en cuenta el id del usuario) y en el siguiente se insertan.

En fin, una explicación muy básica, pero que os ayudará a ir empezando a desarrollar módulos para este CMS.

Enviar datos por POST desde php mediante cURL

Habitualmente para mandar una petición HTTP con datos POST solemos utilizar un formulario desde HTML, y enviarlo ya sea de forma nativa o mediante AJAX/Javascript.

Pero la semana pasada me vi con una cuestión delicada en el curro. Tenía que enviar un archivo utilizando un API externa y, como medida de autenticación, tenía que generar una firma que consistía en un hash de los parámetros más una clave secreta. El «secretismo» de la clave me impedía generar dicha firma en el cliente. Aunque la metiera en un campo oculto o la encapsulara dentro del javascript siempre existe un riesgo porque tiene que llegar al equipo del cliente. Por lo que pensé «bueno, alguna forma habrá de hacer esto en el servidor». Y descubrí cURL, una herramienta libre que me solucionaría la papeleta.

El razonamiento para solucionar el problema fue el siguiente: envío los datos por POST de la forma habitual al servidor, a una clase PHP que los maneje. Desde ahí genero la firma con los datos del formulario más la clave secreta (que de esta forma nunca viaja hasta el cliente), los envío al API, recojo la respuesta y la manipulo. Todo fetén.

¿Y como lanzo la petición desde cURL? Aquí te rulo un ejemplo del código:

<?php
//Lo primerito, creamos una variable iniciando curl, pasándole la url
$ch = curl_init('http://loquesea.com/quepachacolega.php');

//especificamos el POST (tambien podemos hacer peticiones enviando datos por GET
curl_setopt ($ch, CURLOPT_POST, 1);

//le decimos qué paramáetros enviamos (pares nombre/valor, también acepta un array)
curl_setopt ($ch, CURLOPT_POSTFIELDS, "parametro1=valor1&parametro2=valor2");

//le decimos que queremos recoger una respuesta (si no esperas respuesta, ponlo a false)
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true)

//recogemos la respuesta
$respuesta = curl_exec ($ch);

//o el error, por si falla
$error = curl_error($ch);

//y finalmente cerramos curl
curl_close ($ch);
?>

Et voilà, petición enviada con datos por POST. Un truquito fácil que te puede ayudar a automatizar tareas o a añadir seguridad a tu página.

FancyBox: Una alternativa a lightbox y otra opción para ventanas modales.

Seguimos con el mundo de los plugins de jQuery, el productivo framework libre de javascript que, con pocas líneas, te permite mejorar la experiencia del usuario, poner la página bonita y quedar como un Master del Universo delante de tu jefe.

Previamente en este blog hablamos de cómo hacer ventanas modales de forma sencilla con jQueryUI y de cómo trabajar con el plugin Lightbox. ¿Y si te dijera que hay un plugin que incorpora ambas funcionalidades? Sí, un plugin que te permite crear ventanas modales, mostrar galerías de fotos flotando sobre la web original, cargar iFrames (con todo lo que ello te puede proporcionar: vídeos de youtube, metacafe, vimeo, juegos o funcionalidades en flash…). Yo lo he utilizado para una ventana modal y para un flash. Podéis ver varias demos en esta página y descargarlo desde esta.

Como supongo que estáis deseando una explicación, allá voy: Lo primero, tras descargar es copiar en vuestro servidor el archivo .js (para entornos de producción mejor la versión «pack», que está comprimida, para experimentar usad la versión normal con el código legible), las imágenes, el .css (ojo, importante, si las imágenes y el .css no van a estar guardadas en la misma carpeta revisad las url de las mismas en el css, porque este viene pensado para que estén así) e incluirlos en la cabecera de la página donde queréis cargarlas. Para su correcto funcionamiento requiere que incluyáis una versión de jQuery superior a la 1.6, así que echad un ojo que todavía hay mucha gente funcionando por ahí con versiones viejas.

Una vez incluída la librería veamos dos ejemplos. Si quisiéramos usarlo para ampliar una imágen tipo facebook (como haría el lightbox) el código sería tal que así:
HTML:

<a class="ejemplo" href="../image/foto1.jpg" title="EjemploImagen"><img src="../image/foto1thumb.jpg"  /></a>

Explicación rápida: creamos un link, le damos una clase (que en el javascript utilizaremos para acceder al mismo, también podría usarse un id, pero suponiendo un caso real lo habitual son clases porque suele trabajarse con varias imágenes) y hacemos que la referencia apunte a la imagen que queremos cargar. Luego, para mostrar en el menú de la página, cargamos una versión minimizada de la imagen.

<script type="text/javascript">  
  $(document).ready(function(){  
      $(".ejemplo").fancybox({ });  
  });  
</script>  

Y sólo con esa línea de javascript ya tienes el efecto logrado.

Ahora imaginemos que queremos abrir una ventana modal con un aviso (por ejemplo, unas condiciones de uso, que es lo que tuve que hacer yo). La cosa empezaría con un HTML tal que así:

<!-- Aquí el link a la ventana modal -->
<a class="ejemplo" href="#inline1" title="Lorem ipsum dolor sit amet">Inline</a>
<!-- Aquí lo que queremos que se muestre en la ventana modal -->
<div id="inline1" style="display: none;">
   <h3>Etiam quis mi eu elit</h3>
   <p>
   Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam quis mi eu elit tempor facilisis id et neque. Nulla sit amet sem sapien. Vestibulum imperdiet porta ante ac ornare. Nulla et lorem eu nibh adipiscing ultricies nec at lacus. Cras laoreet ultricies sem, at blandit mi eleifend aliquam. Nunc enim ipsum, vehicula non pretium varius, cursus ac tortor. Vivamus fringilla congue laoreet. Quisque ultrices sodales orci, quis rhoncus justo auctor in. Phasellus dui eros, bibendum eu feugiat ornare, faucibus eu mi. Nunc aliquet tempus sem, id aliquam diam varius ac. Maecenas nisl nunc, molestie vitae eleifend vel, iaculis sed magna. Aenean tempus lacus vitae orci posuere porttitor eget non felis. Donec lectus elit, aliquam nec eleifend sit amet, vestibulum sed nunc.
   </p>
</div>

Y con un javascript tal que

$(document).ready(function(){			
	$(".ejemplo").fancybox({
		maxWidth	: 400,
		maxHeight	: 300,
		fitToView	: false,
		width		: '70%',
		height		: '70%',
		autoSize	: false,
		closeClick	: true,
		openEffect	: 'none',
		closeEffect	: 'none'
	});		
})

En este caso definimos varios efectos. Las opciones son múltiples y variadas, por lo que si quieres sacar el 100% del jugo de este plugin lo que te recomiendo es que le pegues un ojo a la documentación del proyecto en su página oficinal.

Diferencia entre display:none y visibility:hidden en CSS

A la hora de ocultar elementos html desde el css tenemos dos posibilidades: las propiedades display  y visibility. Ambas nos permiten definirlas para que un elemento no se muestre en nuestra página. En caso de display definiéndola como display:none y en caso de visibility como visibility:hidden. Muchos son los inconscientes que los usan de manera indistinta, con fatídicas consecuencias para sus maquetaciones porque ambas propiedades tienen diferencias. Veamos cuales:

  • La propiedad visibility:hidden oculta un elemento de la vista del usuario, pero respetando el espacio que ocupaba. Imagina que tienes tres cuadrados y ocultas el del medio con esta propiedad, ¿ok? Lo que ocurriría es que el cuadrado desaparecería, dejando ver lo que haya de fondo, y los cuadrados 1 y 3 seguirían en la misma posición. Con visibility:hidden todas las cajas css siguen en su sitio.
  • La propiedad display:none no sólo oculta, sino que quita el elemento del flujo lógico de la maquetación. Imagina el mismo caso de los cuadrados, en este supuesto en cambio el tercer cuadrado se desplazaría hacia la izquieda, ocupando el espacio que antes ocupaba el 2. Es decir, cuando usas display:none todas las cajas se recolocan como si la caja oculta no existiera.

Por tanto, a la hora de usar una propiedad u otra ten en cuenta estos comportamientos por el bien de tu maquetación.

Convertir un objeto SimpleXMLElement en un array

Toda la mañana peleando con un API que debería devolverme un array de PHP pero que, cosas de la vida, me devuelve un SimpleXMLElement. Cosillas del PHP y de tener que integrar aplicaciones externas a un proyecto usando sus APIs propias (y, en muchos casos, chapuceras). Tras mucho romperme la cabeza (cosa mala) llegué a la conclusión de que con aquello no había dios que trabajara (o sí, pero necesitaría unos días para aprender a manejarlo) y que mejor me sería pasarlo todo a un array y manipularlo a gusto. Tocó búsqueda por stack overflow y google y aparecieron muchas soluciones.

La mayoría son un truquito tal que así, recorriendo el XML y almacenando sus elementos en un array:

/*Siendo $xml el objeto SimpleXML*/
function xml2array($xml) {
  $arr = array();
  foreach ($xml as $element) {
    $tag = $element->getName();
    $e = get_object_vars($element);
    if (!empty($e)) {
      $arr[$tag] = $element instanceof SimpleXMLElement ? xml2array($element) : $e;
    }
    else {
      $arr[$tag] = trim($element);
    }
  }
  return $arr;
}

Esa es la solución propuesta por php.net, que funciona, sin duda. Pero he visto otra más simple y cortita en Book of Zeus donde lo solucionan con una sola línea:

$xml = json_decode(json_encode((array) simplexml_load_string($string)), 1);

Funciona, lo que no tengo claro es cual cargará menos tu servidor a nivel de rendimiento (eso de codificar como JSON y luego descodificar… mmmmmm, pero a saber). Yo me he decantado por la segunda, que hace el código más legible.

Cinco webs sobre seguridad que no debes dejar de mirar

Hoy toca lista, en este caso de páginas web sobre seguridad y asistencia técnica informática en castellano. Por no perder la costumbre de este sitio, la lista será de cinco sitios web.

seguridad informática

Dicho listado está formado por las cinco que más suelo seguir para mantenerme informado del tema, ya sea a través de RSS o de Twitter. Últimamente no tengo tanto tiempo para leer como cuando estaba desempleado, pero sigo siguiendo los artículos que más me interesan en la medida de lo posible.

  • El lado del Mal: El blog de Chema Alonso es sin duda mi favorito en este tema. Mayormente por el humor con el que suele tocar los temas, haciendo así más amena la experiencia de lectura. Pero que no te engañe, el que sea más fácil de leer que otros blogs técnicos no hace que su contenido sea menos útil. Tendrás desde artículos sobre auditoria de redes a otros sobre seguridad en Windows o Apple, en una amplia gama de temas.
  • Daboweb: Veterano site con múltiples actualizaciones mensuales recopilando noticias sobre seguridad y redes. Sobre todo es muy interesante su sección de manuales y tutoriales y sus recomendaciones de software para mantenimiento.
  • INTECO: El Instituto Nacional de Tecnologías de Comunicaciones pone a tu disposición en su web múltiple información sobre seguridad, control de calidad… Además de un área de formación donde podrás realizar diversos cursos de manera gratuita encontrarás información actualizada sobre malware y vulnerabilidades.
  • Sophos Iberia: Hace poco que les he descubierto a través de Twitter, pero ya he ojeado algún artículo interesante en esta web. Merece al menos una ojeada a sus artículos, sobre todo porque ofrecen entradas para todo tipo de usuarios, desde profesionales hasta usuarios medios.
  • Segu-Info: Interesante página web argentina sobre seguridad. Incluye listas de enlaces, blog, foro, formación… todo tipo de cuestiones que se te puedan ocurrir sobre seguridad informática (y en caso de duda siempre puedes recurrir al foro).

En algunos casos ciertos artículos pueden resultar excesivamente técnicos para el usuario medio, pero en todas ellas encontraréis múltiple información muy útil para mantener vuestro equipo y vuestra red protegidos.

jPage: Plugin de jQuery para paginación

Tras las comida con el $Hyperboss me ha comentado que reunión a las 7… así que forzado a salir más tarde hoy voy a alargar la pausa de la comida para dedicaros una entradilla corta, hablando de un interesante plugin de jQuery llamado jPage, que permitirá paginar listas desdde el lado del cliente. Creado por Luís Almeida os lo podéis descargar desde su página en gitHub donde encontraréis también referencias a los útiles (y perfectamente complementarios) plugins Lazy Load, para aligerar la carga de imágenes, y animate.css con varias vistosas animaciones.

Os copio el código de ejemplo de como iría la cosa con la versión «default» del plugin:

El html sería:

<!-- navigation holder -->
<div class="holder">
</div>

<!-- item container -->
<ul id="itemContainer">
    <li><img src="img/img (1).jpg" alt="image"></li>
    <li><img src="img/img (2).jpg" alt="image"></li>
    <li><img src="img/img (3).jpg" alt="image"></li>
     ...<!--aquí metéis las imágenes que hagan falta-->
</ul>

<!-- navigation holder -->
<div class="holder">
</div>

El javascript es apena intrusivo y muy cortito:

/* when document is ready */
  $(function() {
    /* initiate plugin */
    $("div.holder").jPages({
        containerID: "itemContainer"
    });
});

Y para finalizas el CSS sería este:

 .holder {
    margin:15px 0;
}
.holder a {
    font-size:12px;
    cursor:pointer;
    margin:0 5px;
    color:#333;
}
.holder a:hover {
    background-color:#222;
    color:#fff;
}
.holder a.jp-previous {
    margin-right:15px;
}
.holder a.jp-next {
    margin-left:15px;
}
.holder a.jp-current,a.jp-current:hover {
    color:#FF4242;
    font-weight:bold;
}
.holder a.jp-disabled,a.jp-disabled:hover {
    color:#bbb;
}
.holder a.jp-current,a.jp-current:hover,.holder a.jp-disabled,a.jp-disabled:hover {
    cursor:default;
    background:none;
}
.holder span {
    margin: 0 5px;
}

Podéis ver el resultado, junto al código original en este enlace. Además, podréis ver muchas más interesantes opciones para personalizarlo e implementarlo en vuestra página.

A mi me ha ahorrado un rato largo de trabajo esta mañana. Disfrutadlo.