Daniel Rozo

C#, XAML, Windows Phone 7

Modificando entradas en el arranque de #Windows: BCDedit

Hoy, tras tener que reinstalar Windows 8 después de que GParted se cerrara en medio de mover una partición, cuando ya tenía todo arreglado y funcionando, me di cuenta de que había doblado la entrada de Windows 8 en el bootloader, en sí no representa un problema, ya que todo funciona…pero queda feo. ¿Cómo se arregla esto? Eliminando la entrada. ¿Cómo se elimina la entrada? Desde que boot.ini dejó de existir, MS puso a disposición de los administradores una herramienta en línea de comando: BCDEdit. Necesitamos permisos de administrador para ejecutarlo, abrid CMD con dichos permisos ;-) .

Antes de que os pongáis a meter comandos: en el MSConfig (pestaña Arranque) se pueden eliminar y modificar las entradas del bootloader, siempre y cuando, sean de Windows Vista / 7 / 8 las target a modificar. Para versiones anteriores o errores graves o manitas del CMD: BCDEdit.

Eliminando una entrada del bootloader:

Primero, haremos una copia de seguridad, por si las moscas:

  bcdedit /export C:\ruta\hasta\donde\quieras\y_nombre_que_quieras 

(Se puede usar sólo el nombre y lo guarda en la ruta por defecto.

Segundo, vamos a ver qué entradas tenemos inscritas en el bootloader, para saber qué queremos borrar:

 bcdedit /enum 

En mi caso identifiqué la entrada sobrante del bootloader porque en la partición donde debería estar instalada (device) decía “unknown”, bastante explicativo.

Una vez identificada la entrada a borrar, no es más que hacer un:

 bcdedit /delete {<identificador>} 

Sustituyendo, evidentemente, el ID.

Cambiando el orden de la lista de entradas:

Yo, por ejemplo, tengo una pequeña manía con el orden en listas, por eso tuve que cambiar el orden para que saliera Windows 7 antes que Windows 8. Para modificar el orden tenemos tres formas de hacerlo, dos con modificadores y una “a pelo”.

Las formas sencillas:

 bcdedit /displayorder {<identificador>} /addfirst 
 bcdedit /displayorder {<identificador>} /addlast 

Una vez más, sustituyendo <identificador> por el real (obtenido en bcdedit /enum) , sin los signos de menor y mayor que. Creo que no hace falta explicar los modificadores, ¿no? :P

La forma “a pelo”:

 bcdedit /displayorder {<identificador1>} {<identificador2>} {<identificador3>}...{<identificadorN>} 

Con esto lo que haríamos sería poner la entrada con <identificador1> en el 1 lugar y sucesivamente.

Aún no me termina de gustar, cambiando el texto de la entrada:

Este creo que no hace falta ni explicarlo :-)

 bcdedit /set {<identificador>} /description “Mi gato se llama guantes” 

Fácil, sencillo, y para toda la familia.

Besitos.

Cómo extraer información de base de datos desde #JavaScript con #AJAX a #PHP

Muy frecuentemente se plantea el caso en el que necesitamos extraer información de una base de datos MySQL y trabajar con estos datos en JS/JQuery para representarlos en pantalla. Así, pues, es bien sabido que desde JavaScript solo no podemos hacer esto, puesto que se ejecuta del lado del cliente; pero contamos con un sencilla y muy efectiva ayuda: peticiones asíncronas a PHP, que sí puede operar con la BBDD.

Hoy un amigo me ha planteado la duda, y como hace mucho no escribía, he decidido aprovechar la entrada para dedicársela y hacer un minitutorial adaptado a su caso específico; como siempre, si tenéis alguna duda, están los comentarios o en @DanielRozo_ ;-) .

Al lío: tenemos una página simple con un formulario en el que introducimos el DNI y necesitamos conectar a la BBDD para obtener el nombre correspondiente a ese DNI y asignarlo al value de un TextBox.


<!DOCTYPE html>

<html>
<head>

<title>Primer Prototipo</title>

</head>

<body>

<form name="formulario" method="post" onsubmit="leerDNI(document.formulario.dni.value);">

<p>Insertar Datos personales</p>
 <p>Nombre <input type="text" name="nombre" id="dni" placeholder="Nombre"/></p>
 <p>DNI <input type="text" name="dni" required id="name" placeholder="DNI"/></p>
 <p><input type="submit" value="Enviar"/></p>

</form>

</body>
</html>

Si os dais cuenta, el submit del formulario pasa por la función leerDNI(string) y demás funciones que la ayudan que habrá que construir:


function leerDNI(dni){

var params="dni="+dni;

downloadUrl(params,"genxml.php", function(data) {
var xml = parseXml(data);
var dnis = xml.documentElement.getElementsByTagName("dni"); //por si queremos coger incluso varios, aunque no será este caso.
for (var i = 0; i < dnis.length; i++) {
var name = markers[i].getAttribute("name");
document.getElementById("name").value=name; //asignamos el value al string nombre sacado del XML
 }
 });
 }

function downloadUrl(params,url, callback) {
 var request = window.ActiveXObject ?
 new ActiveXObject('Microsoft.XMLHTTP') :
 new XMLHttpRequest; //en cierto modo es una API, acepta requests HTTP.

request.onreadystatechange = function() {
 if (request.readyState == 4) {
 request.onreadystatechange = doNothing;
 callback(request.responseText, request.status);
 }
 };
 request.open("POST", url, true);
 request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");//creación de headers
 request.setRequestHeader("Content-Length", params.length);
 request.send(params);//enviamos la petición POST
 }

function parseXml(str) {
 if (window.ActiveXObject) {
 var doc = new ActiveXObject('Microsoft.XMLDOM');
 doc.loadXML(str);
 return doc;
 } else if (window.DOMParser) {
 return (new DOMParser).parseFromString(str, 'text/xml');
 }
 }

Con esto hemos creado la función leerDni(string) -que sólo llama a downloadURL(string,url,callback), pero es más cómodo- y la función de parseo a XML y la que envía la petición al servidor. Si somos un poco observadores, nos damos cuenta de que la función downloadURL tiene como parámetro una URL “genxml.php” que no es más que un archivo PHP que debe estar en el mismo directorio que el archivo JS que estamos ejecutando según está estructurado.

Ahora vamos con la parte del servidor, la que ejecuta la conexión a la base de datos y devuelve el XML correspondiente a nuestra petición.


<?php
header("Content-type: text/xml");
$username="MIUSUARIO";
$password="MICONTRASEÑA";
$database="MIBBDD";

function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','&lt;',$htmlStr);
$xmlStr=str_replace('>','&gt;',$xmlStr);
$xmlStr=str_replace('"','&quot;',$xmlStr);
$xmlStr=str_replace("'",'&apos;',$xmlStr);
$xmlStr=str_replace("&",'&amp;',$xmlStr);
return $xmlStr;
}

$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
 die('Not connected : ' . mysql_error());
}

$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
 die ('Can\'t use db : ' . mysql_error());
}

//$dni= filter_input(INPUT_POST, 'dni',FILTER_STRING); evitar inyecciones SQL en producción
$dni= $_POST["dni"];
$query = "SELECT * FROM Personas WHERE DNI= '{$dni}'"; //las llaves son importantes!!!!!!!!!
$result = mysql_query($query);
if (!$result) {
 die('Invalid query: ' . mysql_error());
}

echo '<personas>';

// Iterate through the rows, printing XML nodes for each
while ($row = @mysql_fetch_assoc($result)){ //por si queremos expandirlo a más personas
 // ADD TO XML DOCUMENT NODE
 echo '<persona';
 echo 'name="' . parseToXML($row['Nombre']) . '" ';
 echo 'dni="' . parseToXML($row['DNI']) . '" ';
 echo '/>';
}
echo '</personas>';
?>

Con esto ya tendríamos funcionando todo, espero que os haya servido, un saludo!

 

Mover #WordPress a otra carpeta

Hasta ayer tenía este blog alojado en el subdominio blog.danielrozo.es, que realmente era una redirección a /blog, ya que en el dominio principal tenía alojado otro WordPress con un tema vCard que descubrí que no aportaba ningún valor, por ello me decidí a mover el blog al dominio principal y dejar el vCard para otro subdominio montado un CV en línea, que siempre queda bonito.

La cuestión es que, sin conocer la plataforma me decidí a moverlo, conectándome por FTP al sitio y CTRL-C + CTRL-V con dos pares de narices, el resultado creo que es evidente si estoy escribiendo una entrada de cómo hacerlo es porque algo pasó.

Dejo de contaros mi vida, los pasos son sencillos:

  1. Vamos a Ajustes->Generales
  2. En “Dirección de WordPress” cambiamos la que haya escrita, blog.example.com a example.com o blog2.example.com
  3. Con la casilla de abajo cambiamos la dirección a la misma que hay puesta arriba.
  4. FTP->CTRL-C + CTRL-V
  5. ???????
  6. PROFIT!!!

¿Sencillo, no?

Añadir enlaces #BitLy al botón compartir en #Twitter

Resulta que soy un aficionado a las estadísticas. Si son graciosas, mejor, pero este no es el caso, aunque sean de risa. Por todo ello he montado algo simple para ayudar a mantener un mejor control sobre las visitas, si algún día se descontrolan: en lugar de usar el link de la entrada en el botón de compartir en Twitter, usar el link de BitLy, que aporta estadísticas más detalladas e individualizadas.

Es una resolución sencilla usando PHP y JS con un AJAX XMLHTTPRequst Object como interfaz de comunicación entre ellos y la API de BitLy. Partiendo del boton que ya hemos creado solo tenemos que hacer unas pequeñas modificaciones al JS que lo controla y añadir un archivo PHP. En realidad el problema se podría solventar con tres líneas de JQuery o JS en el mismo archivo que ya teníamos, pero por seguridad de la API Key prefiero usar las peticiones desde el servidor.

Al lío, en el archivo JS que controlaba el intent sólo debemos añadir unas cuantas líneas de código que explicaré a continuación de él:

function (element) {
 var loc = element.attr("data-url");
 var text = element.attr("data-text");
 var params="url="+loc;
 var urlcorta;

function downloadUrl(params,url, callback) {
 var request = window.ActiveXObject ?
 new ActiveXObject('Microsoft.XMLHTTP') :
 new XMLHttpRequest; //en cierto modo es una API, acepta requests HTTP.

request.onreadystatechange = function() {
 if (request.readyState == 4) {
 request.onreadystatechange = doNothing;
 callback(request.responseText, request.status);
 }
 };
 request.open("POST", url, true);
 request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 request.setRequestHeader("Content-Length", params.length);
 request.send(params);
 }

downloadUrl(params,"getShortURL.php", function(data) {
 var xml = parseXml(data);
 var contenedor = xml.documentElement.getElementsByTagName("link"); //coge todos los markers
 for (var i = 0; i < contenedor.length; i++) { //coge los atributos de los markers
 urlcorta=contenedor[i].getAttribute("value");

 });

while(text.indexOf("#")!=-1){
 text=text.replace("#","%23");
 }
 var url = "http://urls.api.twitter.com/1/urls/count.json?url=" + loc + "&callback=?";
 var metro = this;
 $.getJSON(url, function (data) {
 var qualifier = "Twittea!";
 element.attr("href", "http://twitter.com/share?url=" + urlcorta + "&text=" + text + "&via=" + metro._accountName);
 element.attr("target", "_blank");
 element.html("<span>"+ " " + qualifier + "</span>");

});

}

Las nuevas líneas son de la 7 a la 30, lo que hacen es definir una función que llama al archivo PHP con un POST y espera su respuesta; cuando la obtiene asigna el valor de la dirección corta a “urlcorta” que luego le pasaremos al intent de Twitter como URL normal.

Como ya hemos dicho, la request a la API en sí la hace el servidor, no el cliente, por ello, debemos implementar el archivo PHP que lo haga, que quedaría algo parecido a esto:

<?php
header("Content-type: text/xml");

function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','&lt;',$htmlStr);
$xmlStr=str_replace('>','&gt;',$xmlStr);
$xmlStr=str_replace('"','&quot;',$xmlStr);
$xmlStr=str_replace("'",'&apos;',$xmlStr);
$xmlStr=str_replace("&",'&amp;',$xmlStr);
return $xmlStr;
}

$url = $_POST["url"];
$usuario="danirXXXX";
$clave_api="R_378XXXXXXXXXXX"; //no válida

$shortURL=function acortar_url_bitly($url,$usuario,$clave_api,$formato = 'xml',$version = '2.0.1')
{
 $bitly = 'http://api.bit.ly/shorten?version='.$version.'&longUrl='.urlencode($url).'&login='.$usuario.'&apiKey='.$clave_api.'&format='.$formato;
 $respuesta = file_get_contents($bitly)
 if(strtolower($formato) == 'json')
 {
 $json = @json_decode($respuesta,true);
 return $json['results'][$url]['shortUrl'];
 }
 else //xml
 {
 $xml = simplexml_load_string($respuesta);
 return 'http://bit.ly/'.$xml->results->nodeKeyVal->hash;
 }
}

// Start XML file, echo parent node
echo '<contenedor>';
 echo '<link ';
 echo 'value="' . parseToXML($shortURL) . '" ';
 echo '/>';

echo '</contenedor>';

?>

En este script lo que hacemos es coger la URL desde la variable POST que le hemos pasado por el XMLHTTRequest, formamos la URL de petición de BitLy y cogemos el XML o JSON que recibimos y se devuelve bitly.com/hash, siendo el hash el identificador de nuestro enlace.

Cabe anotar que tal y como está montado el asunto, el archivo JS y PHP deben estar en la misma carpeta y el PHP llamarse getShortURL.php (esto se puede cambiar modificado el string que se le pasa como URL a downloadURL(params,url,callback).

Si bien esto añade un poco de retraso a la hora de carga de la ventana compartir, no será muy notable para el usuario y en cambio puede ayudar a mantener las estadísticas bastante controladas para los freaks de ellas :-) .

La función para la petición a BitLy la encontré en el blog de @tonijota ;-)

Crear botón compartir en #Twitter con estilo #Metro en #WordPress

Partiendo de la base de que tenemos un tema ya instalado, vamos al Editor del tema, concretamente a la sección de la Plantilla de la página principal (index.php), si queremos que el botón salga debajo de las entradas en el índice y en las entradas individuales. Una vez allí agregamos el siguiente código:


<div class="mentions">
 <div><span class="twitter-small left"></span><a href="" class="twitter-share-button-2 left" data-text="<?php the_title();?>" data-url="<?php the_permalink();?>" data-via="DanielRozo_"></a></div>
 </div>

Como probablemente os habréis dado cuenta, creamos unas clases CSS para controlar el estilo del botón. La “implementación” de dichas clases son las siguientes:


.mentions
{
display: block;
margin: 15px 0 75px 0;
}

.twitter-small
{
display: block;
background-image: url(content/twitter-small.png);
height: 28px;
width: 28px;
}

.twitter-share-button-2
{
display: block;
background-image: url(content/twitter-mentions.png);
height: 21px;
width: 100px;
color: #ffffff;
margin: 2px 12px 0 5px;
}

.twitter-share-button-2 span
{
margin: 0 0 0 15px;
}

.left {float:left;}

Ahora sólo necesitamos controlar la acción click del botón, para que redirija al intent de share en Twitter – esto se hace con JavaScript – hay dos métodos que podemos usar, implementar la función dentro del fichero JS que tenga nuestro tema o agregar un onclick=funcion en el elemento <a> de nuestro botón. Yo opté por la primera opción, para tener todo el JS en un único lugar. La implementación es como sigue:


_loadTweetCount: function (element) {
var loc = element.attr("data-url");
var text = element.attr("data-text");

while(text.indexOf("#")!=-1){
text=text.replace("#","%23");
}

var url = "http://urls.api.twitter.com/1/urls/count.json?url=" + loc + "&callback=?";
var accountName= DanielRozo_
$.getJSON(url, function (data) {
var qualifier = "Twittea!";
element.attr("href", "http://twitter.com/share?url=" + loc + "&text=" + text + "&via=" + accountName);
element.attr("target", "_blank");
element.html("<span>"+ " " + qualifier + "</span>"); //aquí puedes implementar una cuenta

});

}

El código, rápidamente explicado, es sencillo: es una función encapsulada dentro de un initialize de un elemento Metro -el tema que uso- que obtiene los atributos del <a> de nuestro botón (es el “element” que le pasamos como argumento), reemplaza todos los posibles “#” que encuentre en el título -útil si lo que vamos es a tuitear- y arma un intent de Twitter a partir del título (text), la URL (loc) y un via (accountName).

Con esto ya podréis tener un botón igual de bonito que el mío :P .

#Metro Studio, 600 iconos metro gratuitos para devs

 

Para los más avezados, esto es algo ya conocido, pero para los que empezamos resulta ser un recurso realmente útil, sobretodo para aquellos que desarrollamos aplicaciones casi siempre en solitario y no contamos con grandes habilidades artísticas -aquí la prueba-; se trata de una utilidad creada por Syncfusion, empresa dedicada a elaborar recursos para desarrolladores del .NET framework.

Nada menos que 600 iconos personalizables desde la interfaz de la herramienta, vectorizadas y con código XAML exportable. Sin duda lo mejor de todo es que son iconos libres y sin DRM, perfectamente aptos para su uso comercial :-) .

Se descarga aquí.