M101JS – Semana 3

Schema Design

Es muy importante mantener los datos de tal manera que sea favorable para que la aplicación los use.
MongoDB soporta documentos enriquecidos, documentos dentro de documentos, no soporta relaciones (las relaciones han de hacerse en la aplicación), no hay restricciones, operaciones atomicas, no hay esquemas declarados.
Lo mas importante es diseñar una estructura pensando en los patrones de nuestra aplicación.

Las relaciones uno a uno son aquellas en que cada elemento se corresponde exactamente con otro. En MongoDB los anidariamos, a noser que esto haga que el documento pese mas de 16MB o por reducir el trabajo de la aplicación ya que no usariamos todos los datos.

Las relaciones uno a muchos son aquellas en las que un elemento se relaciona con muchos otros. En MongoDB usariamos dos colecciones, en el caso de que sean uno a pocos podemos hacer un anidamiento de documentos.

Las Relaciones muchos a muchos no es consistente anidar documentos.

Multikeys: si tenemos array en los documentos de una coleccion la podemos indexar.

db.students.ensureIndex({teachers:1})

El beneficio de anidar documentos es el rendimiento de lectura

M101JS – Semana 2

CRUD

En mongo es, Insertar(Crear), encontrar(Leer), actualizar(actualizar) y remover(eliminar).

Shell de MongoDB

Con “mongod” arrancamos el servidor y desde otra terminal podemos entrar con mongo, en ella podemos insertar fragmentos de JavaScript y que sean evaluados y ejecutados inmediatamente.

Si escribimos “help” veremos una lista de opciones y ayudas.
Para poder continuar necesitamos entender como funciona en JavaScript el siguiente fragmento, por que un objeto JavaScript puede ser usado en MongoDB como un documento y salvarlo en la base de datos ya que es muy parecida a JSON, MongoDB usa los binarios (bson).

x = { "a" : 1 };
y = "a";
x[y]++;
print(x.a);

Usando los Documentos

La shell tienen la variable “db” que es el identificador de la base de datos. Los documentos en la base de datos estan en las colecciones, por lo que las colecciones son conjuntos de documentos dentro de una base de datos.

Creamos una variable JavaScript

doc = {"nombre" : "Miguel", "twitter" : "@m_minugezz", "conocimientos": ["html5", "CSS3", "JS"]}

Si escibimos “db.persona.insert(doc)” interpreta que “persona” es el nombre de la coleccion de la base de datos actual, “insert” es un metodo que toma como argumento un objeto JavaScript y pone un documento en la base de datos. Con “find” sobre una colección nos retorna todos los documentos.

db.persona.find()

Con “findOne” recupera un documento al azar, es util para examinar el esquema.

db.persona.findOne()

podemos pasarle argumentos

db.persona.findOne({"nombre":"Miguel"})
db.persona.findOne({nombre:"Miguel"}, {"_id":false,"twitter":true})

El metodo “find” se puede usar como “findOne” para recibir todos los datos que coincidan con la consulta.
Si quisieramos buscar todas las personas con “edad” mayor a 25 y menor e igual a 30 usariamos

db.persona.find({edad:{$gt:25, $lte:30}})

Si lo usamos con cadenas de texto, usara la codificacion base para ordenar.

db.persona.find({nombre:{$gt:"M"}})
db.persona.find({nombre:{$lt:"M"}})

En estas busquedas si incluimos otros tipos de datos seran discriminados, por ejemplo que alguna persona tenga como nombre 56.
Podemos buscar los documentos que tengan la edad

db.persona.find({edad:{$exists:true}})

Podemos buscar los documentos que tengan la nombre del tipo “string”

db.persona.find({nombre:{$type:2}})

Podemos buscar usando expresiones regulares, de la libreria “libpcre“, como por ejemplo que acabe en “l” usando “l$” o que empieza con “M” ‘usando $regex:”^M”‘

db.persona.find({nombre:{$regex:"l$"}})

Podemos usar operadores logicos para unir consultas.

db.persona.find({$or : [{nombre : {$regex : "l$"}}, {edad : {$exists : true}}]})
db.persona.find({$and : [{nombre : {$regex : "l$"}}, {edad : {$exists : true}}]})

el operador logico “$and” es raro que lo necesitemos usar ya que como decir

db.persona.find({{nombre : {$regex : "l$"}}, {edad : {$exists : true}})

Si queremos buscar coincidencias en un array dentro de los documentos usaremos, tendra que tener los dos:

db.persona.find({conocimientos : {$all :["html5", "css3"]}})

Si queremos buscar coincidencias en un array pero que tenga alguno de los siguientes:

db.persona.find({conocimientos : {$in :["html5", "css3"]}})

Si dentro del documento hay objetos anidados y queremos hacer una busqueda o buscamos una coincidencia exacta o usamos la dotación de punto.

{
   name: "Juan",
   telf : {
      home : "555 66 77"
      work : "555 77 66"
   } 
}
> db.users.find({"telf.work" : "555 77 66"  })

Podemos modificar el cursor con “sort”, “skip” y “limit” en el servidor de MongoDB.

db.scores.find({type:"exam"}).sort({score:-1}).skip(50).limit(20);

Para contar los elementos usamos “count” que puede recibir los mismos parametros de consulta que “find”

db.persona.count({nombre:"Miguel"})

Para actualizar un documento, usamos “update” que recibe dos parametros, el primero es similar a los que hemos visto sobre “find” y sirve para encontrar el elemento a actualizar y el segundo todos los datos que queremos es este elemento, el resto de los datos que tenia desapareceran.

db.persona.update({nombre : "Miguel"}, {nombre : "M. Minguez", edad : 31 });

Si queremos modificar un campo, si el campo no existe lo crea:

db.persona.update({nombre : "Miguel"}, {$set : {telf : "555 667 777 "} });

Para incrementar un campo usaremos

db.persona.update({nombre : "Miguel"}, {$inc : {age : 1} });

Para eliminar un campo

db.persona.update({nombre : "Miguel"}, {$unset : {telf : 1} });

Trabajando con arrays

Cambiar un valor

db.persona.update({nombre : "Miguel"}, {$set : {"a.2": 5} });

Añadir un valor al final

db.persona.update({nombre : "Miguel"}, {$push : {"a": 4} });

Eliminia el ultimo valor

db.persona.update({nombre : "Miguel"}, {$pop : {a : 1} });

Eliminia el primer valor

db.persona.update({nombre : "Miguel"}, {$pop : {a : -1} });

Añade varios valores

db.persona.update({nombre : "Miguel"}, {$pushAll : {a : [7,8,9]} });

Eliminia un valor sin importar su lugar

db.persona.update({nombre : "Miguel"}, {$pull : {a : 7} });

Eliminia varios valores sin importar su lugar

db.persona.update({nombre : "Miguel"}, {$pullAll : {a : [8,9]} });

Si el valor no existe lo añade

db.persona.update({nombre : "Miguel"}, {$addToSet : {a : 8} });

Para actualizar un documento y si no existe lo añadimos

db.persona.update({nombre : "Pedro"}, {$set : {edad : 40} }, {upset:true});

Para actualizar todos los documentos añadiendo un campo

db.persona.update({}, {$set : {titulo: 'Señor'} }, {multi:true});
db.scores.update( { score : { $lt: 70 } } , { $inc : { score : 20 } } , { multi : true } );

Para eliminar documentos (sin argumentos elimina todo):

db.people.remove({nombre: "Juan"})

Usando “drop” eliminias todos los documentos

db.people.drop()

Para ver los errores

db.runCommand({getLastError:1});

si devuelve “null” es que la ultima operación tubo exito por lo que sirve para comprobar.

M101JS – Semana 1

*estos son mis apuntes, no pretende ser una guia. Comentarios a @m_minguezz

¿Que es MongoDB?

es una base de datos no relacional para documentos JSON, en JSON (Javascript Object Notacion) los datos se repesentan por nombre valor
{“a”:4, “b”:7}

MongoDB es “Schemaless”, dos documentos no tienen por que tener la misma estructura.

MongoDB es escalable y funcional, no soporta relaciones y no tiene transacciones

Creamos /data/db/ y le damos permisos 777 e instalamos MongoDB

Para instalar MongoDB podemos ir a la documentación oficial: Instalación de MongoDB en linux.

Iniciamos MongoDB con “mongod” y entramos (desde otra terminal) en la shell com “mongo”

Para probar que funciona podemos probar en la shell con:
db.people.insert({‘name’:’Pepe’})
db.people.find()

ver un poco mas en la consola de mongo con comandos como
show dbs
use prueba
db.cosas.insert({‘a’:1,’b’:2,’c’:3})
db.cosas.find().pretty()
[…]
MongoDB Shell Cheat Sheet

Para saber mas de como son los archivos JSON podemos consultar la documentación en la pagina oficial.

Instalamos Nodejs

Como hacer los ejemplos del curso

Para seguir el curso usamos “npm install package.json” para instalar los modulos de Nodejs que necesitamos para hacer los ejemplos.

Ejemplo de package.json

{
  "name": "hw1-3",
  "version": "0.0.0",
  "description": "Homework 1.3",
  "main": "app.js",
  "dependencies": {
    "consolidate": "~0.9.1",
    "crypto": "~0.0.3",
    "express": "~3.3.4",
    "mongodb": "~1.3.11",
    "swig": "~0.14.0"
  },
  "author": "You",
  "license": "BSD",
  "private": true
}

“Hola mundo” con express

Crea archivo app.js con el siguiente contenido

// expres biblioteca para enrutamiento y otras cosas, basado en Connect.
var express = require('express'), // referencia
// consolidate 
	app = express(); // crear instancia
// end consolidate

//crear controlador de ruta req-> solicitud, res-> respuesta
app.get('/', function (req, res) {
	// render
	res.send("Hola Mundo");
	// end render
});
app.get('*', function (req, res) {
        res.send('La pagina '+req.params+' que buscas no existe', 404);
        console.log(req);
});

//mongoopen

// nuestra app escucha en el puerto 8080
app.listen(8080);
// creamos un mensaje para indicar que se inicio el servidor
console.log("Servidor express iniciado en puerto 8080");
//end mongoopen

Instalamos express “npm install express”, ahora ejecutamos node app.js y podremos ver la salida en “http://localhost:8080”, para cualquier ruta usamos el comodin “*” para que nos devuelva un error 404.

Ahora vamos a ver como podemos enviar plantillas HTML.
Vamos a crear directorio para nuestras vistas y un archivo html, “views/hola.html”, con el siguiente contenido:

<html>
<head>
    <title>Hola</title>
</head>
<body>
    <!-- {{name}} es una sintaxis del motor de plantillas que vamos a usar-->
    <h1>Hola con {{name}}</h1>
</body>
</html>

Vamos a usar “consolidate” que es una libreria que basicamente nos da un conjunto de envolturas y swig es el motor de plantillas.
En “app.js” cambiaremos donde tenemos el comentario “// consolidate” hasta “// end consolidate” por:

	app = express(),
	cons = require('consolidate');
	//mongodb

app.engine('html', cons.swig); // configuramos el modulo 'html' de swig, usando consolidate para poder integrarlo directamente con express
app.set('view engine', 'html'); // registramos el motor de vistas para express
app.set('views', __dirname + "/views"); // Decimos donde debe buscar las plantillas

Ahora le diremos la vista que tiene que renderizar, cambiando en app.js desde // render hasta // end render

	//mongoclient
	res.render('hola', { 'name' : 'Swig'});
	// end mongoclient

Antes de probarlo necesitamos instalar consolidate y swig

	npm install consolidate
	npm install swig

Añadiendo MongoDB

Añadimos el cliente y el servidor de MongoDB donde esta el comentario “//mongodb”

	MongoClient = require('mongodb').MongoClient,
	Server = require('mongodb').Server;

a que nos vamos a conectar //mongoclient hasta // end mongoclient

	var mongoclient = new MongoClient(new Server('localhost', 27017,{'native_parse' : true})); // información de nuestra conexión
	var db = mongoclient.db('course');
	app.get('/', function(req, res){
		db.collection('hola_mongo_express').findOne({}, function(err, doc){
			res.render('hola', doc);
	})
	});

y la conexion en //mongoopen hasta //end mongoopen

	mongoclient.open(function(err, mongoclient){
		app.listen(8080);
		// creamos un mensaje para indicar que se inicio el servidor
		console.log("Servidor express iniciado en puerto 8080");
});

Siempre que tengamos “err” deberiamos tratar el error

if (err) throw err;

Para que funcione tenemos que tener una base de datos ‘course’ con una entrada con el valor ‘nombre’ que es usado en nuestra plantilla.

Mejorando la instalación

Ahora vamos a mejorar nuestra instalación quitando toda la información que no hay que dejar al descubierto y optimizar el rendimiento quitando aquellas cosas que no necesitamos.

Versión de WordPress y links del <head>

Lo primero que vamos a hacer es ocultar la versión de nuestro WordPress, debemos de tener instalada la ultima versión aun así nadie tiene por que saber que versión usamos. Lo primero sera buscar

<?php bloginfo('version'); ?>

en el “header.php” de nuestro tema y la borraremos, además también es recomendable añadir estas líneas en el “functions.php” del tema para cambiar el número de versión por otra cosa:

function inloop_remove_version() {
return 'Game Boy Color 1998';
}
add_filter('the_generator', 'inloop_remove_version');

Donde pone ‘game boy color 1998’ pon lo que quieras o dejarlo vacio

O lo podemos eliminar con:

remove_action( 'wp_head', 'wp_generator' );

Para optimizar un poco mas tambien quitaremos estos enlaces que se incluyen en el <head> añadiendo las siguientes lineas al “functions.php”

remove_action( 'wp_head', 'wlwmanifest_link' ); 
remove_action( 'wp_head', 'rsd_link' );

y los link alternativos al RSS feed

remove_action( 'wp_head', 'feed_links', 2 ); 
remove_action( 'wp_head', 'feed_links_extra', 3 );

Otro sitio donde aparece la versión es en el archivo “readme.html” que esta en la raiz de la instalación, lo borraremos o lo editaremos, este archivo se volvera a crear cuando actualicemos WordPress, no olvideis borrarlo despues de las actualizaciones.

Pagina de Login

En la pagina de “login” de nuestra instalación nos informa si el usuario o la contraseña es incorrecta debemos quitar o cambiar estos textos, para ello usaremos la siguiente función que añadiremos al archivo “function.php” de nuestro tema.

function inloop_login_error_message($error){
    return  "Incorrect username or password"; 
}
add_filter('login_errors','inloop_login_error_message');

Solo lo necesario

Los plugins como los temas tambien presentan vulnerabilidades, al editar nuestro “wp-config.php” hemos cambiado la ruta del directorio de “wp-content” por lo que dificultaremos el listado de los plugins y los temas. Solo deberiamos tener los archivos de los plugins y el tema que usemos, todo lo demas lo borraremos incluido plugin “Hello Dolly”.

Si intentamos visitar, por ejemplo “http://www.misitio.com/wp-settings.php” nos aparecera un error que generan los scripts PHP mostrando la ruta completa de la instalación. Hay muchos mas archivos que muestran el mismo error.
No solo no lo necesitamos sino que no lo queremos mostrar, para evitar esta vulnerabilidad es suficiente con editar el archivo “php.ini” y añadir la línea

display_errors = Off

Cada archivo con sus permisos

Nuestro servidor web posiblemente sea una máquina Linux, y en este sistema es muy importante tener cuidado con los permisos asignados tanto a los directorios como archivos. Para que funcione correctamente WordPress y no haya fallos de seguridad, lo ideal es que todos los directorios tengan el permiso 755 y los archivos el 644.

Apunte para comentarios

Si queremos quitarnos los enlaces de los comentarios podemos usar este filter en nuestro “function.php” que quitara las etiquetas html de los comentarios.

add_filter( 'pre_comment_content', 'wp_specialchars' );

Usa la cabeza:

Nunca uses temas o plugins premium o incluso los gratuitos descargados desde redes P2P o de las paginas no oficiales por ahorrarte unos euros, la inmensa mayoria incluye codigo inyectado que te dara problemas.

¿Donde puedo saber las vulnerabilidades de WordPress?

En WordPress.org, en el enlace “Return to Last Query” podemos ver todas las vulnerabilidades.